setns-dcache.c (2612B)
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_NEWNET) points to new /proc/net content even 18 * if old one is in dcache. 19 * 20 * FIXME /proc/net/unix is under CONFIG_UNIX which can be disabled. 21 */ 22#undef NDEBUG 23#include <assert.h> 24#include <errno.h> 25#include <sched.h> 26#include <signal.h> 27#include <stdio.h> 28#include <stdlib.h> 29#include <string.h> 30#include <unistd.h> 31#include <sys/types.h> 32#include <sys/stat.h> 33#include <fcntl.h> 34#include <sys/socket.h> 35 36static pid_t pid = -1; 37 38static void f(void) 39{ 40 if (pid > 0) { 41 kill(pid, SIGTERM); 42 } 43} 44 45int main(void) 46{ 47 int fd[2]; 48 char _ = 0; 49 int nsfd; 50 51 atexit(f); 52 53 /* Check for priviledges and syscall availability straight away. */ 54 if (unshare(CLONE_NEWNET) == -1) { 55 if (errno == ENOSYS || errno == EPERM) { 56 return 4; 57 } 58 return 1; 59 } 60 /* Distinguisher between two otherwise empty net namespaces. */ 61 if (socket(AF_UNIX, SOCK_STREAM, 0) == -1) { 62 return 1; 63 } 64 65 if (pipe(fd) == -1) { 66 return 1; 67 } 68 69 pid = fork(); 70 if (pid == -1) { 71 return 1; 72 } 73 74 if (pid == 0) { 75 if (unshare(CLONE_NEWNET) == -1) { 76 return 1; 77 } 78 79 if (write(fd[1], &_, 1) != 1) { 80 return 1; 81 } 82 83 pause(); 84 85 return 0; 86 } 87 88 if (read(fd[0], &_, 1) != 1) { 89 return 1; 90 } 91 92 { 93 char buf[64]; 94 snprintf(buf, sizeof(buf), "/proc/%u/ns/net", pid); 95 nsfd = open(buf, O_RDONLY); 96 if (nsfd == -1) { 97 return 1; 98 } 99 } 100 101 /* Reliably pin dentry into dcache. */ 102 (void)open("/proc/net/unix", O_RDONLY); 103 104 if (setns(nsfd, CLONE_NEWNET) == -1) { 105 return 1; 106 } 107 108 kill(pid, SIGTERM); 109 pid = 0; 110 111 { 112 char buf[4096]; 113 ssize_t rv; 114 int fd; 115 116 fd = open("/proc/net/unix", O_RDONLY); 117 if (fd == -1) { 118 return 1; 119 } 120 121#define S "Num RefCount Protocol Flags Type St Inode Path\n" 122 rv = read(fd, buf, sizeof(buf)); 123 124 assert(rv == strlen(S)); 125 assert(memcmp(buf, S, strlen(S)) == 0); 126 } 127 128 return 0; 129}