Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Alexey Dobriyan and committed by
Linus Torvalds
7dbbade1 9af27b28

+135
+1
tools/testing/selftests/proc/.gitignore
··· 12 12 /read 13 13 /self 14 14 /setns-dcache 15 + /setns-sysvipc 15 16 /thread-self
+1
tools/testing/selftests/proc/Makefile
··· 17 17 TEST_GEN_PROGS += read 18 18 TEST_GEN_PROGS += self 19 19 TEST_GEN_PROGS += setns-dcache 20 + TEST_GEN_PROGS += setns-sysvipc 20 21 TEST_GEN_PROGS += thread-self 21 22 22 23 include ../lib.mk
+133
tools/testing/selftests/proc/setns-sysvipc.c
··· 1 + /* 2 + * Copyright © 2019 Alexey Dobriyan <adobriyan@gmail.com> 3 + * 4 + * Permission to use, copy, modify, and distribute this software for any 5 + * purpose with or without fee is hereby granted, provided that the above 6 + * copyright notice and this permission notice appear in all copies. 7 + * 8 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 + */ 16 + /* 17 + * Test that setns(CLONE_NEWIPC) points to new /proc/sysvipc content even 18 + * if old one is in dcache. 19 + */ 20 + #undef NDEBUG 21 + #include <assert.h> 22 + #include <errno.h> 23 + #include <stdio.h> 24 + #include <sched.h> 25 + #include <signal.h> 26 + #include <stdlib.h> 27 + #include <string.h> 28 + #include <unistd.h> 29 + #include <sys/types.h> 30 + #include <sys/stat.h> 31 + #include <fcntl.h> 32 + #include <sys/ipc.h> 33 + #include <sys/shm.h> 34 + 35 + static pid_t pid = -1; 36 + 37 + static void f(void) 38 + { 39 + if (pid > 0) { 40 + kill(pid, SIGTERM); 41 + } 42 + } 43 + 44 + int main(void) 45 + { 46 + int fd[2]; 47 + char _ = 0; 48 + int nsfd; 49 + 50 + atexit(f); 51 + 52 + /* Check for priviledges and syscall availability straight away. */ 53 + if (unshare(CLONE_NEWIPC) == -1) { 54 + if (errno == ENOSYS || errno == EPERM) { 55 + return 4; 56 + } 57 + return 1; 58 + } 59 + /* Distinguisher between two otherwise empty IPC namespaces. */ 60 + if (shmget(IPC_PRIVATE, 1, IPC_CREAT) == -1) { 61 + return 1; 62 + } 63 + 64 + if (pipe(fd) == -1) { 65 + return 1; 66 + } 67 + 68 + pid = fork(); 69 + if (pid == -1) { 70 + return 1; 71 + } 72 + 73 + if (pid == 0) { 74 + if (unshare(CLONE_NEWIPC) == -1) { 75 + return 1; 76 + } 77 + 78 + if (write(fd[1], &_, 1) != 1) { 79 + return 1; 80 + } 81 + 82 + pause(); 83 + 84 + return 0; 85 + } 86 + 87 + if (read(fd[0], &_, 1) != 1) { 88 + return 1; 89 + } 90 + 91 + { 92 + char buf[64]; 93 + snprintf(buf, sizeof(buf), "/proc/%u/ns/ipc", pid); 94 + nsfd = open(buf, O_RDONLY); 95 + if (nsfd == -1) { 96 + return 1; 97 + } 98 + } 99 + 100 + /* Reliably pin dentry into dcache. */ 101 + (void)open("/proc/sysvipc/shm", O_RDONLY); 102 + 103 + if (setns(nsfd, CLONE_NEWIPC) == -1) { 104 + return 1; 105 + } 106 + 107 + kill(pid, SIGTERM); 108 + pid = 0; 109 + 110 + { 111 + char buf[4096]; 112 + ssize_t rv; 113 + int fd; 114 + 115 + fd = open("/proc/sysvipc/shm", O_RDONLY); 116 + if (fd == -1) { 117 + return 1; 118 + } 119 + 120 + #define S32 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n" 121 + #define S64 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n" 122 + rv = read(fd, buf, sizeof(buf)); 123 + if (rv == strlen(S32)) { 124 + assert(memcmp(buf, S32, strlen(S32)) == 0); 125 + } else if (rv == strlen(S64)) { 126 + assert(memcmp(buf, S64, strlen(S64)) == 0); 127 + } else { 128 + assert(0); 129 + } 130 + } 131 + 132 + return 0; 133 + }