diff options
author | Alexey Dobriyan <adobriyan@gmail.com> | 2019-07-16 16:26:48 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-16 19:23:21 -0700 |
commit | 7dbbade1f285e881119049563ab2a036c96dd9f3 (patch) | |
tree | 9c45ceb42846a92a8d9d3bbbcdbb26ff21dd1127 /tools/testing/selftests/proc | |
parent | 9af27b28b1da1020e427b626c4967d0206b55100 (diff) | |
download | lwn-7dbbade1f285e881119049563ab2a036c96dd9f3.tar.gz lwn-7dbbade1f285e881119049563ab2a036c96dd9f3.zip |
proc: test /proc/sysvipc vs setns(CLONE_NEWIPC)
I thought that /proc/sysvipc has the same bug as /proc/net
commit 1fde6f21d90f8ba5da3cb9c54ca991ed72696c43
proc: fix /proc/net/* after setns(2)
However, it doesn't! /proc/sysvipc files do
get_ipc_ns(current->nsproxy->ipc_ns);
in their open() hook and avoid the problem.
Keep the test, maybe /proc/sysvipc will become broken someday :-\
Link: http://lkml.kernel.org/r/20190706180146.GA21015@avx2
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'tools/testing/selftests/proc')
-rw-r--r-- | tools/testing/selftests/proc/.gitignore | 1 | ||||
-rw-r--r-- | tools/testing/selftests/proc/Makefile | 1 | ||||
-rw-r--r-- | tools/testing/selftests/proc/setns-sysvipc.c | 133 |
3 files changed, 135 insertions, 0 deletions
diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore index 444ad39d3700..66fab4c58ed4 100644 --- a/tools/testing/selftests/proc/.gitignore +++ b/tools/testing/selftests/proc/.gitignore @@ -12,4 +12,5 @@ /read /self /setns-dcache +/setns-sysvipc /thread-self diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile index 9f09fcd09ea3..a8ed0f684829 100644 --- a/tools/testing/selftests/proc/Makefile +++ b/tools/testing/selftests/proc/Makefile @@ -17,6 +17,7 @@ TEST_GEN_PROGS += proc-uptime-002 TEST_GEN_PROGS += read TEST_GEN_PROGS += self TEST_GEN_PROGS += setns-dcache +TEST_GEN_PROGS += setns-sysvipc TEST_GEN_PROGS += thread-self include ../lib.mk diff --git a/tools/testing/selftests/proc/setns-sysvipc.c b/tools/testing/selftests/proc/setns-sysvipc.c new file mode 100644 index 000000000000..903890c5e587 --- /dev/null +++ b/tools/testing/selftests/proc/setns-sysvipc.c @@ -0,0 +1,133 @@ +/* + * Copyright © 2019 Alexey Dobriyan <adobriyan@gmail.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Test that setns(CLONE_NEWIPC) points to new /proc/sysvipc content even + * if old one is in dcache. + */ +#undef NDEBUG +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <sched.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ipc.h> +#include <sys/shm.h> + +static pid_t pid = -1; + +static void f(void) +{ + if (pid > 0) { + kill(pid, SIGTERM); + } +} + +int main(void) +{ + int fd[2]; + char _ = 0; + int nsfd; + + atexit(f); + + /* Check for priviledges and syscall availability straight away. */ + if (unshare(CLONE_NEWIPC) == -1) { + if (errno == ENOSYS || errno == EPERM) { + return 4; + } + return 1; + } + /* Distinguisher between two otherwise empty IPC namespaces. */ + if (shmget(IPC_PRIVATE, 1, IPC_CREAT) == -1) { + return 1; + } + + if (pipe(fd) == -1) { + return 1; + } + + pid = fork(); + if (pid == -1) { + return 1; + } + + if (pid == 0) { + if (unshare(CLONE_NEWIPC) == -1) { + return 1; + } + + if (write(fd[1], &_, 1) != 1) { + return 1; + } + + pause(); + + return 0; + } + + if (read(fd[0], &_, 1) != 1) { + return 1; + } + + { + char buf[64]; + snprintf(buf, sizeof(buf), "/proc/%u/ns/ipc", pid); + nsfd = open(buf, O_RDONLY); + if (nsfd == -1) { + return 1; + } + } + + /* Reliably pin dentry into dcache. */ + (void)open("/proc/sysvipc/shm", O_RDONLY); + + if (setns(nsfd, CLONE_NEWIPC) == -1) { + return 1; + } + + kill(pid, SIGTERM); + pid = 0; + + { + char buf[4096]; + ssize_t rv; + int fd; + + fd = open("/proc/sysvipc/shm", O_RDONLY); + if (fd == -1) { + return 1; + } + +#define S32 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n" +#define S64 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n" + rv = read(fd, buf, sizeof(buf)); + if (rv == strlen(S32)) { + assert(memcmp(buf, S32, strlen(S32)) == 0); + } else if (rv == strlen(S64)) { + assert(memcmp(buf, S64, strlen(S64)) == 0); + } else { + assert(0); + } + } + + return 0; +} |