1*28ef38a9SChristian Brauner // SPDX-License-Identifier: GPL-2.0 2*28ef38a9SChristian Brauner #define _GNU_SOURCE 3*28ef38a9SChristian Brauner #include <errno.h> 4*28ef38a9SChristian Brauner #include <fcntl.h> 5*28ef38a9SChristian Brauner #include <grp.h> 6*28ef38a9SChristian Brauner #include <limits.h> 7*28ef38a9SChristian Brauner #include <sched.h> 8*28ef38a9SChristian Brauner #include <stdio.h> 9*28ef38a9SChristian Brauner #include <stdlib.h> 10*28ef38a9SChristian Brauner #include <string.h> 11*28ef38a9SChristian Brauner #include <sys/mount.h> 12*28ef38a9SChristian Brauner #include <sys/stat.h> 13*28ef38a9SChristian Brauner #include <sys/types.h> 14*28ef38a9SChristian Brauner #include <sys/wait.h> 15*28ef38a9SChristian Brauner #include <unistd.h> 16*28ef38a9SChristian Brauner #include <linux/unistd.h> 17*28ef38a9SChristian Brauner #include "../kselftest_harness.h" 18*28ef38a9SChristian Brauner 19*28ef38a9SChristian Brauner #ifndef FD_NSFS_ROOT 20*28ef38a9SChristian Brauner #define FD_NSFS_ROOT -10003 /* Root of the nsfs filesystem */ 21*28ef38a9SChristian Brauner #endif 22*28ef38a9SChristian Brauner 23*28ef38a9SChristian Brauner TEST(nsfs_net_handle) 24*28ef38a9SChristian Brauner { 25*28ef38a9SChristian Brauner struct file_handle *handle; 26*28ef38a9SChristian Brauner int mount_id; 27*28ef38a9SChristian Brauner int ret; 28*28ef38a9SChristian Brauner int fd; 29*28ef38a9SChristian Brauner int ns_fd; 30*28ef38a9SChristian Brauner struct stat st1, st2; 31*28ef38a9SChristian Brauner 32*28ef38a9SChristian Brauner /* Drop to unprivileged uid/gid */ 33*28ef38a9SChristian Brauner ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 34*28ef38a9SChristian Brauner ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 35*28ef38a9SChristian Brauner 36*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 37*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 38*28ef38a9SChristian Brauner 39*28ef38a9SChristian Brauner /* Open a namespace file descriptor */ 40*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/net", O_RDONLY); 41*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 42*28ef38a9SChristian Brauner 43*28ef38a9SChristian Brauner /* Get handle for the namespace */ 44*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 45*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 46*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 47*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 48*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 49*28ef38a9SChristian Brauner } 50*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 51*28ef38a9SChristian Brauner ASSERT_GT(handle->handle_bytes, 0); 52*28ef38a9SChristian Brauner 53*28ef38a9SChristian Brauner /* Try to open using FD_NSFS_ROOT as unprivileged user */ 54*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 55*28ef38a9SChristian Brauner if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 56*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 57*28ef38a9SChristian Brauner return, 58*28ef38a9SChristian Brauner "open_by_handle_at with FD_NSFS_ROOT not supported"); 59*28ef38a9SChristian Brauner } 60*28ef38a9SChristian Brauner if (fd < 0 && errno == EPERM) { 61*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 62*28ef38a9SChristian Brauner return, 63*28ef38a9SChristian Brauner "Permission denied for unprivileged user (expected)"); 64*28ef38a9SChristian Brauner } 65*28ef38a9SChristian Brauner ASSERT_GE(fd, 0); 66*28ef38a9SChristian Brauner 67*28ef38a9SChristian Brauner /* Verify we opened the correct namespace */ 68*28ef38a9SChristian Brauner ASSERT_EQ(fstat(ns_fd, &st1), 0); 69*28ef38a9SChristian Brauner ASSERT_EQ(fstat(fd, &st2), 0); 70*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_ino, st2.st_ino); 71*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_dev, st2.st_dev); 72*28ef38a9SChristian Brauner 73*28ef38a9SChristian Brauner close(fd); 74*28ef38a9SChristian Brauner close(ns_fd); 75*28ef38a9SChristian Brauner free(handle); 76*28ef38a9SChristian Brauner } 77*28ef38a9SChristian Brauner 78*28ef38a9SChristian Brauner TEST(nsfs_uts_handle) 79*28ef38a9SChristian Brauner { 80*28ef38a9SChristian Brauner struct file_handle *handle; 81*28ef38a9SChristian Brauner int mount_id; 82*28ef38a9SChristian Brauner int ret; 83*28ef38a9SChristian Brauner int fd; 84*28ef38a9SChristian Brauner int ns_fd; 85*28ef38a9SChristian Brauner struct stat st1, st2; 86*28ef38a9SChristian Brauner 87*28ef38a9SChristian Brauner /* Drop to unprivileged uid/gid */ 88*28ef38a9SChristian Brauner ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 89*28ef38a9SChristian Brauner ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 90*28ef38a9SChristian Brauner 91*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 92*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 93*28ef38a9SChristian Brauner 94*28ef38a9SChristian Brauner /* Open UTS namespace file descriptor */ 95*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/uts", O_RDONLY); 96*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 97*28ef38a9SChristian Brauner 98*28ef38a9SChristian Brauner /* Get handle for the namespace */ 99*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 100*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 101*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 102*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 103*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 104*28ef38a9SChristian Brauner } 105*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 106*28ef38a9SChristian Brauner ASSERT_GT(handle->handle_bytes, 0); 107*28ef38a9SChristian Brauner 108*28ef38a9SChristian Brauner /* Try to open using FD_NSFS_ROOT */ 109*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 110*28ef38a9SChristian Brauner if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 111*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 112*28ef38a9SChristian Brauner return, 113*28ef38a9SChristian Brauner "open_by_handle_at with FD_NSFS_ROOT not supported"); 114*28ef38a9SChristian Brauner } 115*28ef38a9SChristian Brauner ASSERT_GE(fd, 0); 116*28ef38a9SChristian Brauner 117*28ef38a9SChristian Brauner /* Verify we opened the correct namespace */ 118*28ef38a9SChristian Brauner ASSERT_EQ(fstat(ns_fd, &st1), 0); 119*28ef38a9SChristian Brauner ASSERT_EQ(fstat(fd, &st2), 0); 120*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_ino, st2.st_ino); 121*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_dev, st2.st_dev); 122*28ef38a9SChristian Brauner 123*28ef38a9SChristian Brauner close(fd); 124*28ef38a9SChristian Brauner close(ns_fd); 125*28ef38a9SChristian Brauner free(handle); 126*28ef38a9SChristian Brauner } 127*28ef38a9SChristian Brauner 128*28ef38a9SChristian Brauner TEST(nsfs_ipc_handle) 129*28ef38a9SChristian Brauner { 130*28ef38a9SChristian Brauner struct file_handle *handle; 131*28ef38a9SChristian Brauner int mount_id; 132*28ef38a9SChristian Brauner int ret; 133*28ef38a9SChristian Brauner int fd; 134*28ef38a9SChristian Brauner int ns_fd; 135*28ef38a9SChristian Brauner struct stat st1, st2; 136*28ef38a9SChristian Brauner 137*28ef38a9SChristian Brauner /* Drop to unprivileged uid/gid */ 138*28ef38a9SChristian Brauner ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 139*28ef38a9SChristian Brauner ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 140*28ef38a9SChristian Brauner 141*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 142*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 143*28ef38a9SChristian Brauner 144*28ef38a9SChristian Brauner /* Open IPC namespace file descriptor */ 145*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/ipc", O_RDONLY); 146*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 147*28ef38a9SChristian Brauner 148*28ef38a9SChristian Brauner /* Get handle for the namespace */ 149*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 150*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 151*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 152*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 153*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 154*28ef38a9SChristian Brauner } 155*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 156*28ef38a9SChristian Brauner ASSERT_GT(handle->handle_bytes, 0); 157*28ef38a9SChristian Brauner 158*28ef38a9SChristian Brauner /* Try to open using FD_NSFS_ROOT */ 159*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 160*28ef38a9SChristian Brauner if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 161*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 162*28ef38a9SChristian Brauner return, 163*28ef38a9SChristian Brauner "open_by_handle_at with FD_NSFS_ROOT not supported"); 164*28ef38a9SChristian Brauner } 165*28ef38a9SChristian Brauner ASSERT_GE(fd, 0); 166*28ef38a9SChristian Brauner 167*28ef38a9SChristian Brauner /* Verify we opened the correct namespace */ 168*28ef38a9SChristian Brauner ASSERT_EQ(fstat(ns_fd, &st1), 0); 169*28ef38a9SChristian Brauner ASSERT_EQ(fstat(fd, &st2), 0); 170*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_ino, st2.st_ino); 171*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_dev, st2.st_dev); 172*28ef38a9SChristian Brauner 173*28ef38a9SChristian Brauner close(fd); 174*28ef38a9SChristian Brauner close(ns_fd); 175*28ef38a9SChristian Brauner free(handle); 176*28ef38a9SChristian Brauner } 177*28ef38a9SChristian Brauner 178*28ef38a9SChristian Brauner TEST(nsfs_pid_handle) 179*28ef38a9SChristian Brauner { 180*28ef38a9SChristian Brauner struct file_handle *handle; 181*28ef38a9SChristian Brauner int mount_id; 182*28ef38a9SChristian Brauner int ret; 183*28ef38a9SChristian Brauner int fd; 184*28ef38a9SChristian Brauner int ns_fd; 185*28ef38a9SChristian Brauner struct stat st1, st2; 186*28ef38a9SChristian Brauner 187*28ef38a9SChristian Brauner /* Drop to unprivileged uid/gid */ 188*28ef38a9SChristian Brauner ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 189*28ef38a9SChristian Brauner ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 190*28ef38a9SChristian Brauner 191*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 192*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 193*28ef38a9SChristian Brauner 194*28ef38a9SChristian Brauner /* Open PID namespace file descriptor */ 195*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/pid", O_RDONLY); 196*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 197*28ef38a9SChristian Brauner 198*28ef38a9SChristian Brauner /* Get handle for the namespace */ 199*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 200*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 201*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 202*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 203*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 204*28ef38a9SChristian Brauner } 205*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 206*28ef38a9SChristian Brauner ASSERT_GT(handle->handle_bytes, 0); 207*28ef38a9SChristian Brauner 208*28ef38a9SChristian Brauner /* Try to open using FD_NSFS_ROOT */ 209*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 210*28ef38a9SChristian Brauner if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 211*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 212*28ef38a9SChristian Brauner return, 213*28ef38a9SChristian Brauner "open_by_handle_at with FD_NSFS_ROOT not supported"); 214*28ef38a9SChristian Brauner } 215*28ef38a9SChristian Brauner ASSERT_GE(fd, 0); 216*28ef38a9SChristian Brauner 217*28ef38a9SChristian Brauner /* Verify we opened the correct namespace */ 218*28ef38a9SChristian Brauner ASSERT_EQ(fstat(ns_fd, &st1), 0); 219*28ef38a9SChristian Brauner ASSERT_EQ(fstat(fd, &st2), 0); 220*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_ino, st2.st_ino); 221*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_dev, st2.st_dev); 222*28ef38a9SChristian Brauner 223*28ef38a9SChristian Brauner close(fd); 224*28ef38a9SChristian Brauner close(ns_fd); 225*28ef38a9SChristian Brauner free(handle); 226*28ef38a9SChristian Brauner } 227*28ef38a9SChristian Brauner 228*28ef38a9SChristian Brauner TEST(nsfs_mnt_handle) 229*28ef38a9SChristian Brauner { 230*28ef38a9SChristian Brauner struct file_handle *handle; 231*28ef38a9SChristian Brauner int mount_id; 232*28ef38a9SChristian Brauner int ret; 233*28ef38a9SChristian Brauner int fd; 234*28ef38a9SChristian Brauner int ns_fd; 235*28ef38a9SChristian Brauner struct stat st1, st2; 236*28ef38a9SChristian Brauner 237*28ef38a9SChristian Brauner /* Drop to unprivileged uid/gid */ 238*28ef38a9SChristian Brauner ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 239*28ef38a9SChristian Brauner ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 240*28ef38a9SChristian Brauner 241*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 242*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 243*28ef38a9SChristian Brauner 244*28ef38a9SChristian Brauner /* Open mount namespace file descriptor */ 245*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/mnt", O_RDONLY); 246*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 247*28ef38a9SChristian Brauner 248*28ef38a9SChristian Brauner /* Get handle for the namespace */ 249*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 250*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 251*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 252*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 253*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 254*28ef38a9SChristian Brauner } 255*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 256*28ef38a9SChristian Brauner ASSERT_GT(handle->handle_bytes, 0); 257*28ef38a9SChristian Brauner 258*28ef38a9SChristian Brauner /* Try to open using FD_NSFS_ROOT */ 259*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 260*28ef38a9SChristian Brauner if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 261*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 262*28ef38a9SChristian Brauner return, 263*28ef38a9SChristian Brauner "open_by_handle_at with FD_NSFS_ROOT not supported"); 264*28ef38a9SChristian Brauner } 265*28ef38a9SChristian Brauner ASSERT_GE(fd, 0); 266*28ef38a9SChristian Brauner 267*28ef38a9SChristian Brauner /* Verify we opened the correct namespace */ 268*28ef38a9SChristian Brauner ASSERT_EQ(fstat(ns_fd, &st1), 0); 269*28ef38a9SChristian Brauner ASSERT_EQ(fstat(fd, &st2), 0); 270*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_ino, st2.st_ino); 271*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_dev, st2.st_dev); 272*28ef38a9SChristian Brauner 273*28ef38a9SChristian Brauner close(fd); 274*28ef38a9SChristian Brauner close(ns_fd); 275*28ef38a9SChristian Brauner free(handle); 276*28ef38a9SChristian Brauner } 277*28ef38a9SChristian Brauner 278*28ef38a9SChristian Brauner TEST(nsfs_user_handle) 279*28ef38a9SChristian Brauner { 280*28ef38a9SChristian Brauner struct file_handle *handle; 281*28ef38a9SChristian Brauner int mount_id; 282*28ef38a9SChristian Brauner int ret; 283*28ef38a9SChristian Brauner int fd; 284*28ef38a9SChristian Brauner int ns_fd; 285*28ef38a9SChristian Brauner struct stat st1, st2; 286*28ef38a9SChristian Brauner 287*28ef38a9SChristian Brauner /* Drop to unprivileged uid/gid */ 288*28ef38a9SChristian Brauner ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 289*28ef38a9SChristian Brauner ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 290*28ef38a9SChristian Brauner 291*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 292*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 293*28ef38a9SChristian Brauner 294*28ef38a9SChristian Brauner /* Open user namespace file descriptor */ 295*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/user", O_RDONLY); 296*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 297*28ef38a9SChristian Brauner 298*28ef38a9SChristian Brauner /* Get handle for the namespace */ 299*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 300*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 301*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 302*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 303*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 304*28ef38a9SChristian Brauner } 305*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 306*28ef38a9SChristian Brauner ASSERT_GT(handle->handle_bytes, 0); 307*28ef38a9SChristian Brauner 308*28ef38a9SChristian Brauner /* Try to open using FD_NSFS_ROOT */ 309*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 310*28ef38a9SChristian Brauner if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 311*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 312*28ef38a9SChristian Brauner return, 313*28ef38a9SChristian Brauner "open_by_handle_at with FD_NSFS_ROOT not supported"); 314*28ef38a9SChristian Brauner } 315*28ef38a9SChristian Brauner ASSERT_GE(fd, 0); 316*28ef38a9SChristian Brauner 317*28ef38a9SChristian Brauner /* Verify we opened the correct namespace */ 318*28ef38a9SChristian Brauner ASSERT_EQ(fstat(ns_fd, &st1), 0); 319*28ef38a9SChristian Brauner ASSERT_EQ(fstat(fd, &st2), 0); 320*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_ino, st2.st_ino); 321*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_dev, st2.st_dev); 322*28ef38a9SChristian Brauner 323*28ef38a9SChristian Brauner close(fd); 324*28ef38a9SChristian Brauner close(ns_fd); 325*28ef38a9SChristian Brauner free(handle); 326*28ef38a9SChristian Brauner } 327*28ef38a9SChristian Brauner 328*28ef38a9SChristian Brauner TEST(nsfs_cgroup_handle) 329*28ef38a9SChristian Brauner { 330*28ef38a9SChristian Brauner struct file_handle *handle; 331*28ef38a9SChristian Brauner int mount_id; 332*28ef38a9SChristian Brauner int ret; 333*28ef38a9SChristian Brauner int fd; 334*28ef38a9SChristian Brauner int ns_fd; 335*28ef38a9SChristian Brauner struct stat st1, st2; 336*28ef38a9SChristian Brauner 337*28ef38a9SChristian Brauner /* Drop to unprivileged uid/gid */ 338*28ef38a9SChristian Brauner ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 339*28ef38a9SChristian Brauner ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 340*28ef38a9SChristian Brauner 341*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 342*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 343*28ef38a9SChristian Brauner 344*28ef38a9SChristian Brauner /* Open cgroup namespace file descriptor */ 345*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/cgroup", O_RDONLY); 346*28ef38a9SChristian Brauner if (ns_fd < 0) { 347*28ef38a9SChristian Brauner SKIP(free(handle); return, "cgroup namespace not available"); 348*28ef38a9SChristian Brauner } 349*28ef38a9SChristian Brauner 350*28ef38a9SChristian Brauner /* Get handle for the namespace */ 351*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 352*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 353*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 354*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 355*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 356*28ef38a9SChristian Brauner } 357*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 358*28ef38a9SChristian Brauner ASSERT_GT(handle->handle_bytes, 0); 359*28ef38a9SChristian Brauner 360*28ef38a9SChristian Brauner /* Try to open using FD_NSFS_ROOT */ 361*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 362*28ef38a9SChristian Brauner if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 363*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 364*28ef38a9SChristian Brauner return, 365*28ef38a9SChristian Brauner "open_by_handle_at with FD_NSFS_ROOT not supported"); 366*28ef38a9SChristian Brauner } 367*28ef38a9SChristian Brauner ASSERT_GE(fd, 0); 368*28ef38a9SChristian Brauner 369*28ef38a9SChristian Brauner /* Verify we opened the correct namespace */ 370*28ef38a9SChristian Brauner ASSERT_EQ(fstat(ns_fd, &st1), 0); 371*28ef38a9SChristian Brauner ASSERT_EQ(fstat(fd, &st2), 0); 372*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_ino, st2.st_ino); 373*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_dev, st2.st_dev); 374*28ef38a9SChristian Brauner 375*28ef38a9SChristian Brauner close(fd); 376*28ef38a9SChristian Brauner close(ns_fd); 377*28ef38a9SChristian Brauner free(handle); 378*28ef38a9SChristian Brauner } 379*28ef38a9SChristian Brauner 380*28ef38a9SChristian Brauner TEST(nsfs_time_handle) 381*28ef38a9SChristian Brauner { 382*28ef38a9SChristian Brauner struct file_handle *handle; 383*28ef38a9SChristian Brauner int mount_id; 384*28ef38a9SChristian Brauner int ret; 385*28ef38a9SChristian Brauner int fd; 386*28ef38a9SChristian Brauner int ns_fd; 387*28ef38a9SChristian Brauner struct stat st1, st2; 388*28ef38a9SChristian Brauner 389*28ef38a9SChristian Brauner /* Drop to unprivileged uid/gid */ 390*28ef38a9SChristian Brauner ASSERT_EQ(setresgid(65534, 65534, 65534), 0); /* nogroup */ 391*28ef38a9SChristian Brauner ASSERT_EQ(setresuid(65534, 65534, 65534), 0); /* nobody */ 392*28ef38a9SChristian Brauner 393*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 394*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 395*28ef38a9SChristian Brauner 396*28ef38a9SChristian Brauner /* Open time namespace file descriptor */ 397*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/time", O_RDONLY); 398*28ef38a9SChristian Brauner if (ns_fd < 0) { 399*28ef38a9SChristian Brauner SKIP(free(handle); return, "time namespace not available"); 400*28ef38a9SChristian Brauner } 401*28ef38a9SChristian Brauner 402*28ef38a9SChristian Brauner /* Get handle for the namespace */ 403*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 404*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 405*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 406*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 407*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 408*28ef38a9SChristian Brauner } 409*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 410*28ef38a9SChristian Brauner ASSERT_GT(handle->handle_bytes, 0); 411*28ef38a9SChristian Brauner 412*28ef38a9SChristian Brauner /* Try to open using FD_NSFS_ROOT */ 413*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 414*28ef38a9SChristian Brauner if (fd < 0 && (errno == EINVAL || errno == EOPNOTSUPP)) { 415*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 416*28ef38a9SChristian Brauner return, 417*28ef38a9SChristian Brauner "open_by_handle_at with FD_NSFS_ROOT not supported"); 418*28ef38a9SChristian Brauner } 419*28ef38a9SChristian Brauner ASSERT_GE(fd, 0); 420*28ef38a9SChristian Brauner 421*28ef38a9SChristian Brauner /* Verify we opened the correct namespace */ 422*28ef38a9SChristian Brauner ASSERT_EQ(fstat(ns_fd, &st1), 0); 423*28ef38a9SChristian Brauner ASSERT_EQ(fstat(fd, &st2), 0); 424*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_ino, st2.st_ino); 425*28ef38a9SChristian Brauner ASSERT_EQ(st1.st_dev, st2.st_dev); 426*28ef38a9SChristian Brauner 427*28ef38a9SChristian Brauner close(fd); 428*28ef38a9SChristian Brauner close(ns_fd); 429*28ef38a9SChristian Brauner free(handle); 430*28ef38a9SChristian Brauner } 431*28ef38a9SChristian Brauner 432*28ef38a9SChristian Brauner TEST(nsfs_user_net_namespace_isolation) 433*28ef38a9SChristian Brauner { 434*28ef38a9SChristian Brauner struct file_handle *handle; 435*28ef38a9SChristian Brauner int mount_id; 436*28ef38a9SChristian Brauner int ret; 437*28ef38a9SChristian Brauner int fd; 438*28ef38a9SChristian Brauner int ns_fd; 439*28ef38a9SChristian Brauner pid_t pid; 440*28ef38a9SChristian Brauner int status; 441*28ef38a9SChristian Brauner int pipefd[2]; 442*28ef38a9SChristian Brauner char result; 443*28ef38a9SChristian Brauner 444*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 445*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 446*28ef38a9SChristian Brauner 447*28ef38a9SChristian Brauner /* Create pipe for communication */ 448*28ef38a9SChristian Brauner ASSERT_EQ(pipe(pipefd), 0); 449*28ef38a9SChristian Brauner 450*28ef38a9SChristian Brauner /* Get handle for current network namespace */ 451*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/net", O_RDONLY); 452*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 453*28ef38a9SChristian Brauner 454*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 455*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 456*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 457*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); close(pipefd[0]); 458*28ef38a9SChristian Brauner close(pipefd[1]); 459*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 460*28ef38a9SChristian Brauner } 461*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 462*28ef38a9SChristian Brauner close(ns_fd); 463*28ef38a9SChristian Brauner 464*28ef38a9SChristian Brauner pid = fork(); 465*28ef38a9SChristian Brauner ASSERT_GE(pid, 0); 466*28ef38a9SChristian Brauner 467*28ef38a9SChristian Brauner if (pid == 0) { 468*28ef38a9SChristian Brauner /* Child process */ 469*28ef38a9SChristian Brauner close(pipefd[0]); 470*28ef38a9SChristian Brauner 471*28ef38a9SChristian Brauner /* First create new user namespace to drop privileges */ 472*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWUSER); 473*28ef38a9SChristian Brauner if (ret < 0) { 474*28ef38a9SChristian Brauner write(pipefd[1], "U", 475*28ef38a9SChristian Brauner 1); /* Unable to create user namespace */ 476*28ef38a9SChristian Brauner close(pipefd[1]); 477*28ef38a9SChristian Brauner exit(0); 478*28ef38a9SChristian Brauner } 479*28ef38a9SChristian Brauner 480*28ef38a9SChristian Brauner /* Write uid/gid mappings to maintain some capabilities */ 481*28ef38a9SChristian Brauner int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 482*28ef38a9SChristian Brauner int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 483*28ef38a9SChristian Brauner int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 484*28ef38a9SChristian Brauner 485*28ef38a9SChristian Brauner if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 486*28ef38a9SChristian Brauner write(pipefd[1], "M", 1); /* Unable to set mappings */ 487*28ef38a9SChristian Brauner close(pipefd[1]); 488*28ef38a9SChristian Brauner exit(0); 489*28ef38a9SChristian Brauner } 490*28ef38a9SChristian Brauner 491*28ef38a9SChristian Brauner /* Disable setgroups to allow gid mapping */ 492*28ef38a9SChristian Brauner write(setgroups_fd, "deny", 4); 493*28ef38a9SChristian Brauner close(setgroups_fd); 494*28ef38a9SChristian Brauner 495*28ef38a9SChristian Brauner /* Map current uid/gid to root in the new namespace */ 496*28ef38a9SChristian Brauner char mapping[64]; 497*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 498*28ef38a9SChristian Brauner write(uid_map_fd, mapping, strlen(mapping)); 499*28ef38a9SChristian Brauner close(uid_map_fd); 500*28ef38a9SChristian Brauner 501*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 502*28ef38a9SChristian Brauner write(gid_map_fd, mapping, strlen(mapping)); 503*28ef38a9SChristian Brauner close(gid_map_fd); 504*28ef38a9SChristian Brauner 505*28ef38a9SChristian Brauner /* Now create new network namespace */ 506*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWNET); 507*28ef38a9SChristian Brauner if (ret < 0) { 508*28ef38a9SChristian Brauner write(pipefd[1], "N", 509*28ef38a9SChristian Brauner 1); /* Unable to create network namespace */ 510*28ef38a9SChristian Brauner close(pipefd[1]); 511*28ef38a9SChristian Brauner exit(0); 512*28ef38a9SChristian Brauner } 513*28ef38a9SChristian Brauner 514*28ef38a9SChristian Brauner /* Try to open parent's network namespace handle from new user+net namespace */ 515*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 516*28ef38a9SChristian Brauner 517*28ef38a9SChristian Brauner if (fd >= 0) { 518*28ef38a9SChristian Brauner /* Should NOT succeed - we're in a different user namespace */ 519*28ef38a9SChristian Brauner write(pipefd[1], "S", 1); /* Unexpected success */ 520*28ef38a9SChristian Brauner close(fd); 521*28ef38a9SChristian Brauner } else if (errno == ESTALE) { 522*28ef38a9SChristian Brauner /* Expected: Stale file handle */ 523*28ef38a9SChristian Brauner write(pipefd[1], "P", 1); 524*28ef38a9SChristian Brauner } else { 525*28ef38a9SChristian Brauner /* Other error */ 526*28ef38a9SChristian Brauner write(pipefd[1], "F", 1); 527*28ef38a9SChristian Brauner } 528*28ef38a9SChristian Brauner 529*28ef38a9SChristian Brauner close(pipefd[1]); 530*28ef38a9SChristian Brauner exit(0); 531*28ef38a9SChristian Brauner } 532*28ef38a9SChristian Brauner 533*28ef38a9SChristian Brauner /* Parent process */ 534*28ef38a9SChristian Brauner close(pipefd[1]); 535*28ef38a9SChristian Brauner ASSERT_EQ(read(pipefd[0], &result, 1), 1); 536*28ef38a9SChristian Brauner 537*28ef38a9SChristian Brauner waitpid(pid, &status, 0); 538*28ef38a9SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 539*28ef38a9SChristian Brauner ASSERT_EQ(WEXITSTATUS(status), 0); 540*28ef38a9SChristian Brauner 541*28ef38a9SChristian Brauner if (result == 'U') { 542*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 543*28ef38a9SChristian Brauner return, "Cannot create new user namespace"); 544*28ef38a9SChristian Brauner } 545*28ef38a9SChristian Brauner if (result == 'M') { 546*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 547*28ef38a9SChristian Brauner return, "Cannot set uid/gid mappings"); 548*28ef38a9SChristian Brauner } 549*28ef38a9SChristian Brauner if (result == 'N') { 550*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 551*28ef38a9SChristian Brauner return, "Cannot create new network namespace"); 552*28ef38a9SChristian Brauner } 553*28ef38a9SChristian Brauner 554*28ef38a9SChristian Brauner /* Should fail with permission denied since we're in a different user namespace */ 555*28ef38a9SChristian Brauner ASSERT_EQ(result, 'P'); 556*28ef38a9SChristian Brauner 557*28ef38a9SChristian Brauner close(pipefd[0]); 558*28ef38a9SChristian Brauner free(handle); 559*28ef38a9SChristian Brauner } 560*28ef38a9SChristian Brauner 561*28ef38a9SChristian Brauner TEST(nsfs_user_uts_namespace_isolation) 562*28ef38a9SChristian Brauner { 563*28ef38a9SChristian Brauner struct file_handle *handle; 564*28ef38a9SChristian Brauner int mount_id; 565*28ef38a9SChristian Brauner int ret; 566*28ef38a9SChristian Brauner int fd; 567*28ef38a9SChristian Brauner int ns_fd; 568*28ef38a9SChristian Brauner pid_t pid; 569*28ef38a9SChristian Brauner int status; 570*28ef38a9SChristian Brauner int pipefd[2]; 571*28ef38a9SChristian Brauner char result; 572*28ef38a9SChristian Brauner 573*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 574*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 575*28ef38a9SChristian Brauner 576*28ef38a9SChristian Brauner /* Create pipe for communication */ 577*28ef38a9SChristian Brauner ASSERT_EQ(pipe(pipefd), 0); 578*28ef38a9SChristian Brauner 579*28ef38a9SChristian Brauner /* Get handle for current UTS namespace */ 580*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/uts", O_RDONLY); 581*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 582*28ef38a9SChristian Brauner 583*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 584*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 585*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 586*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); close(pipefd[0]); 587*28ef38a9SChristian Brauner close(pipefd[1]); 588*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 589*28ef38a9SChristian Brauner } 590*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 591*28ef38a9SChristian Brauner close(ns_fd); 592*28ef38a9SChristian Brauner 593*28ef38a9SChristian Brauner pid = fork(); 594*28ef38a9SChristian Brauner ASSERT_GE(pid, 0); 595*28ef38a9SChristian Brauner 596*28ef38a9SChristian Brauner if (pid == 0) { 597*28ef38a9SChristian Brauner /* Child process */ 598*28ef38a9SChristian Brauner close(pipefd[0]); 599*28ef38a9SChristian Brauner 600*28ef38a9SChristian Brauner /* First create new user namespace to drop privileges */ 601*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWUSER); 602*28ef38a9SChristian Brauner if (ret < 0) { 603*28ef38a9SChristian Brauner write(pipefd[1], "U", 604*28ef38a9SChristian Brauner 1); /* Unable to create user namespace */ 605*28ef38a9SChristian Brauner close(pipefd[1]); 606*28ef38a9SChristian Brauner exit(0); 607*28ef38a9SChristian Brauner } 608*28ef38a9SChristian Brauner 609*28ef38a9SChristian Brauner /* Write uid/gid mappings to maintain some capabilities */ 610*28ef38a9SChristian Brauner int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 611*28ef38a9SChristian Brauner int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 612*28ef38a9SChristian Brauner int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 613*28ef38a9SChristian Brauner 614*28ef38a9SChristian Brauner if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 615*28ef38a9SChristian Brauner write(pipefd[1], "M", 1); /* Unable to set mappings */ 616*28ef38a9SChristian Brauner close(pipefd[1]); 617*28ef38a9SChristian Brauner exit(0); 618*28ef38a9SChristian Brauner } 619*28ef38a9SChristian Brauner 620*28ef38a9SChristian Brauner /* Disable setgroups to allow gid mapping */ 621*28ef38a9SChristian Brauner write(setgroups_fd, "deny", 4); 622*28ef38a9SChristian Brauner close(setgroups_fd); 623*28ef38a9SChristian Brauner 624*28ef38a9SChristian Brauner /* Map current uid/gid to root in the new namespace */ 625*28ef38a9SChristian Brauner char mapping[64]; 626*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 627*28ef38a9SChristian Brauner write(uid_map_fd, mapping, strlen(mapping)); 628*28ef38a9SChristian Brauner close(uid_map_fd); 629*28ef38a9SChristian Brauner 630*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 631*28ef38a9SChristian Brauner write(gid_map_fd, mapping, strlen(mapping)); 632*28ef38a9SChristian Brauner close(gid_map_fd); 633*28ef38a9SChristian Brauner 634*28ef38a9SChristian Brauner /* Now create new UTS namespace */ 635*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWUTS); 636*28ef38a9SChristian Brauner if (ret < 0) { 637*28ef38a9SChristian Brauner write(pipefd[1], "N", 638*28ef38a9SChristian Brauner 1); /* Unable to create UTS namespace */ 639*28ef38a9SChristian Brauner close(pipefd[1]); 640*28ef38a9SChristian Brauner exit(0); 641*28ef38a9SChristian Brauner } 642*28ef38a9SChristian Brauner 643*28ef38a9SChristian Brauner /* Try to open parent's UTS namespace handle from new user+uts namespace */ 644*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 645*28ef38a9SChristian Brauner 646*28ef38a9SChristian Brauner if (fd >= 0) { 647*28ef38a9SChristian Brauner /* Should NOT succeed - we're in a different user namespace */ 648*28ef38a9SChristian Brauner write(pipefd[1], "S", 1); /* Unexpected success */ 649*28ef38a9SChristian Brauner close(fd); 650*28ef38a9SChristian Brauner } else if (errno == ESTALE) { 651*28ef38a9SChristian Brauner /* Expected: Stale file handle */ 652*28ef38a9SChristian Brauner write(pipefd[1], "P", 1); 653*28ef38a9SChristian Brauner } else { 654*28ef38a9SChristian Brauner /* Other error */ 655*28ef38a9SChristian Brauner write(pipefd[1], "F", 1); 656*28ef38a9SChristian Brauner } 657*28ef38a9SChristian Brauner 658*28ef38a9SChristian Brauner close(pipefd[1]); 659*28ef38a9SChristian Brauner exit(0); 660*28ef38a9SChristian Brauner } 661*28ef38a9SChristian Brauner 662*28ef38a9SChristian Brauner /* Parent process */ 663*28ef38a9SChristian Brauner close(pipefd[1]); 664*28ef38a9SChristian Brauner ASSERT_EQ(read(pipefd[0], &result, 1), 1); 665*28ef38a9SChristian Brauner 666*28ef38a9SChristian Brauner waitpid(pid, &status, 0); 667*28ef38a9SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 668*28ef38a9SChristian Brauner ASSERT_EQ(WEXITSTATUS(status), 0); 669*28ef38a9SChristian Brauner 670*28ef38a9SChristian Brauner if (result == 'U') { 671*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 672*28ef38a9SChristian Brauner return, "Cannot create new user namespace"); 673*28ef38a9SChristian Brauner } 674*28ef38a9SChristian Brauner if (result == 'M') { 675*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 676*28ef38a9SChristian Brauner return, "Cannot set uid/gid mappings"); 677*28ef38a9SChristian Brauner } 678*28ef38a9SChristian Brauner if (result == 'N') { 679*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 680*28ef38a9SChristian Brauner return, "Cannot create new UTS namespace"); 681*28ef38a9SChristian Brauner } 682*28ef38a9SChristian Brauner 683*28ef38a9SChristian Brauner /* Should fail with ESTALE since we're in a different user namespace */ 684*28ef38a9SChristian Brauner ASSERT_EQ(result, 'P'); 685*28ef38a9SChristian Brauner 686*28ef38a9SChristian Brauner close(pipefd[0]); 687*28ef38a9SChristian Brauner free(handle); 688*28ef38a9SChristian Brauner } 689*28ef38a9SChristian Brauner 690*28ef38a9SChristian Brauner TEST(nsfs_user_ipc_namespace_isolation) 691*28ef38a9SChristian Brauner { 692*28ef38a9SChristian Brauner struct file_handle *handle; 693*28ef38a9SChristian Brauner int mount_id; 694*28ef38a9SChristian Brauner int ret; 695*28ef38a9SChristian Brauner int fd; 696*28ef38a9SChristian Brauner int ns_fd; 697*28ef38a9SChristian Brauner pid_t pid; 698*28ef38a9SChristian Brauner int status; 699*28ef38a9SChristian Brauner int pipefd[2]; 700*28ef38a9SChristian Brauner char result; 701*28ef38a9SChristian Brauner 702*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 703*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 704*28ef38a9SChristian Brauner 705*28ef38a9SChristian Brauner /* Create pipe for communication */ 706*28ef38a9SChristian Brauner ASSERT_EQ(pipe(pipefd), 0); 707*28ef38a9SChristian Brauner 708*28ef38a9SChristian Brauner /* Get handle for current IPC namespace */ 709*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/ipc", O_RDONLY); 710*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 711*28ef38a9SChristian Brauner 712*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 713*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 714*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 715*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); close(pipefd[0]); 716*28ef38a9SChristian Brauner close(pipefd[1]); 717*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 718*28ef38a9SChristian Brauner } 719*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 720*28ef38a9SChristian Brauner close(ns_fd); 721*28ef38a9SChristian Brauner 722*28ef38a9SChristian Brauner pid = fork(); 723*28ef38a9SChristian Brauner ASSERT_GE(pid, 0); 724*28ef38a9SChristian Brauner 725*28ef38a9SChristian Brauner if (pid == 0) { 726*28ef38a9SChristian Brauner /* Child process */ 727*28ef38a9SChristian Brauner close(pipefd[0]); 728*28ef38a9SChristian Brauner 729*28ef38a9SChristian Brauner /* First create new user namespace to drop privileges */ 730*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWUSER); 731*28ef38a9SChristian Brauner if (ret < 0) { 732*28ef38a9SChristian Brauner write(pipefd[1], "U", 733*28ef38a9SChristian Brauner 1); /* Unable to create user namespace */ 734*28ef38a9SChristian Brauner close(pipefd[1]); 735*28ef38a9SChristian Brauner exit(0); 736*28ef38a9SChristian Brauner } 737*28ef38a9SChristian Brauner 738*28ef38a9SChristian Brauner /* Write uid/gid mappings to maintain some capabilities */ 739*28ef38a9SChristian Brauner int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 740*28ef38a9SChristian Brauner int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 741*28ef38a9SChristian Brauner int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 742*28ef38a9SChristian Brauner 743*28ef38a9SChristian Brauner if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 744*28ef38a9SChristian Brauner write(pipefd[1], "M", 1); /* Unable to set mappings */ 745*28ef38a9SChristian Brauner close(pipefd[1]); 746*28ef38a9SChristian Brauner exit(0); 747*28ef38a9SChristian Brauner } 748*28ef38a9SChristian Brauner 749*28ef38a9SChristian Brauner /* Disable setgroups to allow gid mapping */ 750*28ef38a9SChristian Brauner write(setgroups_fd, "deny", 4); 751*28ef38a9SChristian Brauner close(setgroups_fd); 752*28ef38a9SChristian Brauner 753*28ef38a9SChristian Brauner /* Map current uid/gid to root in the new namespace */ 754*28ef38a9SChristian Brauner char mapping[64]; 755*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 756*28ef38a9SChristian Brauner write(uid_map_fd, mapping, strlen(mapping)); 757*28ef38a9SChristian Brauner close(uid_map_fd); 758*28ef38a9SChristian Brauner 759*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 760*28ef38a9SChristian Brauner write(gid_map_fd, mapping, strlen(mapping)); 761*28ef38a9SChristian Brauner close(gid_map_fd); 762*28ef38a9SChristian Brauner 763*28ef38a9SChristian Brauner /* Now create new IPC namespace */ 764*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWIPC); 765*28ef38a9SChristian Brauner if (ret < 0) { 766*28ef38a9SChristian Brauner write(pipefd[1], "N", 767*28ef38a9SChristian Brauner 1); /* Unable to create IPC namespace */ 768*28ef38a9SChristian Brauner close(pipefd[1]); 769*28ef38a9SChristian Brauner exit(0); 770*28ef38a9SChristian Brauner } 771*28ef38a9SChristian Brauner 772*28ef38a9SChristian Brauner /* Try to open parent's IPC namespace handle from new user+ipc namespace */ 773*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 774*28ef38a9SChristian Brauner 775*28ef38a9SChristian Brauner if (fd >= 0) { 776*28ef38a9SChristian Brauner /* Should NOT succeed - we're in a different user namespace */ 777*28ef38a9SChristian Brauner write(pipefd[1], "S", 1); /* Unexpected success */ 778*28ef38a9SChristian Brauner close(fd); 779*28ef38a9SChristian Brauner } else if (errno == ESTALE) { 780*28ef38a9SChristian Brauner /* Expected: Stale file handle */ 781*28ef38a9SChristian Brauner write(pipefd[1], "P", 1); 782*28ef38a9SChristian Brauner } else { 783*28ef38a9SChristian Brauner /* Other error */ 784*28ef38a9SChristian Brauner write(pipefd[1], "F", 1); 785*28ef38a9SChristian Brauner } 786*28ef38a9SChristian Brauner 787*28ef38a9SChristian Brauner close(pipefd[1]); 788*28ef38a9SChristian Brauner exit(0); 789*28ef38a9SChristian Brauner } 790*28ef38a9SChristian Brauner 791*28ef38a9SChristian Brauner /* Parent process */ 792*28ef38a9SChristian Brauner close(pipefd[1]); 793*28ef38a9SChristian Brauner ASSERT_EQ(read(pipefd[0], &result, 1), 1); 794*28ef38a9SChristian Brauner 795*28ef38a9SChristian Brauner waitpid(pid, &status, 0); 796*28ef38a9SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 797*28ef38a9SChristian Brauner ASSERT_EQ(WEXITSTATUS(status), 0); 798*28ef38a9SChristian Brauner 799*28ef38a9SChristian Brauner if (result == 'U') { 800*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 801*28ef38a9SChristian Brauner return, "Cannot create new user namespace"); 802*28ef38a9SChristian Brauner } 803*28ef38a9SChristian Brauner if (result == 'M') { 804*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 805*28ef38a9SChristian Brauner return, "Cannot set uid/gid mappings"); 806*28ef38a9SChristian Brauner } 807*28ef38a9SChristian Brauner if (result == 'N') { 808*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 809*28ef38a9SChristian Brauner return, "Cannot create new IPC namespace"); 810*28ef38a9SChristian Brauner } 811*28ef38a9SChristian Brauner 812*28ef38a9SChristian Brauner /* Should fail with ESTALE since we're in a different user namespace */ 813*28ef38a9SChristian Brauner ASSERT_EQ(result, 'P'); 814*28ef38a9SChristian Brauner 815*28ef38a9SChristian Brauner close(pipefd[0]); 816*28ef38a9SChristian Brauner free(handle); 817*28ef38a9SChristian Brauner } 818*28ef38a9SChristian Brauner 819*28ef38a9SChristian Brauner TEST(nsfs_user_mnt_namespace_isolation) 820*28ef38a9SChristian Brauner { 821*28ef38a9SChristian Brauner struct file_handle *handle; 822*28ef38a9SChristian Brauner int mount_id; 823*28ef38a9SChristian Brauner int ret; 824*28ef38a9SChristian Brauner int fd; 825*28ef38a9SChristian Brauner int ns_fd; 826*28ef38a9SChristian Brauner pid_t pid; 827*28ef38a9SChristian Brauner int status; 828*28ef38a9SChristian Brauner int pipefd[2]; 829*28ef38a9SChristian Brauner char result; 830*28ef38a9SChristian Brauner 831*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 832*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 833*28ef38a9SChristian Brauner 834*28ef38a9SChristian Brauner /* Create pipe for communication */ 835*28ef38a9SChristian Brauner ASSERT_EQ(pipe(pipefd), 0); 836*28ef38a9SChristian Brauner 837*28ef38a9SChristian Brauner /* Get handle for current mount namespace */ 838*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/mnt", O_RDONLY); 839*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 840*28ef38a9SChristian Brauner 841*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 842*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 843*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 844*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); close(pipefd[0]); 845*28ef38a9SChristian Brauner close(pipefd[1]); 846*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 847*28ef38a9SChristian Brauner } 848*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 849*28ef38a9SChristian Brauner close(ns_fd); 850*28ef38a9SChristian Brauner 851*28ef38a9SChristian Brauner pid = fork(); 852*28ef38a9SChristian Brauner ASSERT_GE(pid, 0); 853*28ef38a9SChristian Brauner 854*28ef38a9SChristian Brauner if (pid == 0) { 855*28ef38a9SChristian Brauner /* Child process */ 856*28ef38a9SChristian Brauner close(pipefd[0]); 857*28ef38a9SChristian Brauner 858*28ef38a9SChristian Brauner /* First create new user namespace to drop privileges */ 859*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWUSER); 860*28ef38a9SChristian Brauner if (ret < 0) { 861*28ef38a9SChristian Brauner write(pipefd[1], "U", 862*28ef38a9SChristian Brauner 1); /* Unable to create user namespace */ 863*28ef38a9SChristian Brauner close(pipefd[1]); 864*28ef38a9SChristian Brauner exit(0); 865*28ef38a9SChristian Brauner } 866*28ef38a9SChristian Brauner 867*28ef38a9SChristian Brauner /* Write uid/gid mappings to maintain some capabilities */ 868*28ef38a9SChristian Brauner int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 869*28ef38a9SChristian Brauner int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 870*28ef38a9SChristian Brauner int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 871*28ef38a9SChristian Brauner 872*28ef38a9SChristian Brauner if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 873*28ef38a9SChristian Brauner write(pipefd[1], "M", 1); /* Unable to set mappings */ 874*28ef38a9SChristian Brauner close(pipefd[1]); 875*28ef38a9SChristian Brauner exit(0); 876*28ef38a9SChristian Brauner } 877*28ef38a9SChristian Brauner 878*28ef38a9SChristian Brauner /* Disable setgroups to allow gid mapping */ 879*28ef38a9SChristian Brauner write(setgroups_fd, "deny", 4); 880*28ef38a9SChristian Brauner close(setgroups_fd); 881*28ef38a9SChristian Brauner 882*28ef38a9SChristian Brauner /* Map current uid/gid to root in the new namespace */ 883*28ef38a9SChristian Brauner char mapping[64]; 884*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 885*28ef38a9SChristian Brauner write(uid_map_fd, mapping, strlen(mapping)); 886*28ef38a9SChristian Brauner close(uid_map_fd); 887*28ef38a9SChristian Brauner 888*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 889*28ef38a9SChristian Brauner write(gid_map_fd, mapping, strlen(mapping)); 890*28ef38a9SChristian Brauner close(gid_map_fd); 891*28ef38a9SChristian Brauner 892*28ef38a9SChristian Brauner /* Now create new mount namespace */ 893*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWNS); 894*28ef38a9SChristian Brauner if (ret < 0) { 895*28ef38a9SChristian Brauner write(pipefd[1], "N", 896*28ef38a9SChristian Brauner 1); /* Unable to create mount namespace */ 897*28ef38a9SChristian Brauner close(pipefd[1]); 898*28ef38a9SChristian Brauner exit(0); 899*28ef38a9SChristian Brauner } 900*28ef38a9SChristian Brauner 901*28ef38a9SChristian Brauner /* Try to open parent's mount namespace handle from new user+mnt namespace */ 902*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 903*28ef38a9SChristian Brauner 904*28ef38a9SChristian Brauner if (fd >= 0) { 905*28ef38a9SChristian Brauner /* Should NOT succeed - we're in a different user namespace */ 906*28ef38a9SChristian Brauner write(pipefd[1], "S", 1); /* Unexpected success */ 907*28ef38a9SChristian Brauner close(fd); 908*28ef38a9SChristian Brauner } else if (errno == ESTALE) { 909*28ef38a9SChristian Brauner /* Expected: Stale file handle */ 910*28ef38a9SChristian Brauner write(pipefd[1], "P", 1); 911*28ef38a9SChristian Brauner } else { 912*28ef38a9SChristian Brauner /* Other error */ 913*28ef38a9SChristian Brauner write(pipefd[1], "F", 1); 914*28ef38a9SChristian Brauner } 915*28ef38a9SChristian Brauner 916*28ef38a9SChristian Brauner close(pipefd[1]); 917*28ef38a9SChristian Brauner exit(0); 918*28ef38a9SChristian Brauner } 919*28ef38a9SChristian Brauner 920*28ef38a9SChristian Brauner /* Parent process */ 921*28ef38a9SChristian Brauner close(pipefd[1]); 922*28ef38a9SChristian Brauner ASSERT_EQ(read(pipefd[0], &result, 1), 1); 923*28ef38a9SChristian Brauner 924*28ef38a9SChristian Brauner waitpid(pid, &status, 0); 925*28ef38a9SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 926*28ef38a9SChristian Brauner ASSERT_EQ(WEXITSTATUS(status), 0); 927*28ef38a9SChristian Brauner 928*28ef38a9SChristian Brauner if (result == 'U') { 929*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 930*28ef38a9SChristian Brauner return, "Cannot create new user namespace"); 931*28ef38a9SChristian Brauner } 932*28ef38a9SChristian Brauner if (result == 'M') { 933*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 934*28ef38a9SChristian Brauner return, "Cannot set uid/gid mappings"); 935*28ef38a9SChristian Brauner } 936*28ef38a9SChristian Brauner if (result == 'N') { 937*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 938*28ef38a9SChristian Brauner return, "Cannot create new mount namespace"); 939*28ef38a9SChristian Brauner } 940*28ef38a9SChristian Brauner 941*28ef38a9SChristian Brauner /* Should fail with ESTALE since we're in a different user namespace */ 942*28ef38a9SChristian Brauner ASSERT_EQ(result, 'P'); 943*28ef38a9SChristian Brauner 944*28ef38a9SChristian Brauner close(pipefd[0]); 945*28ef38a9SChristian Brauner free(handle); 946*28ef38a9SChristian Brauner } 947*28ef38a9SChristian Brauner 948*28ef38a9SChristian Brauner TEST(nsfs_user_cgroup_namespace_isolation) 949*28ef38a9SChristian Brauner { 950*28ef38a9SChristian Brauner struct file_handle *handle; 951*28ef38a9SChristian Brauner int mount_id; 952*28ef38a9SChristian Brauner int ret; 953*28ef38a9SChristian Brauner int fd; 954*28ef38a9SChristian Brauner int ns_fd; 955*28ef38a9SChristian Brauner pid_t pid; 956*28ef38a9SChristian Brauner int status; 957*28ef38a9SChristian Brauner int pipefd[2]; 958*28ef38a9SChristian Brauner char result; 959*28ef38a9SChristian Brauner 960*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 961*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 962*28ef38a9SChristian Brauner 963*28ef38a9SChristian Brauner /* Create pipe for communication */ 964*28ef38a9SChristian Brauner ASSERT_EQ(pipe(pipefd), 0); 965*28ef38a9SChristian Brauner 966*28ef38a9SChristian Brauner /* Get handle for current cgroup namespace */ 967*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/cgroup", O_RDONLY); 968*28ef38a9SChristian Brauner if (ns_fd < 0) { 969*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); close(pipefd[1]); 970*28ef38a9SChristian Brauner return, "cgroup namespace not available"); 971*28ef38a9SChristian Brauner } 972*28ef38a9SChristian Brauner 973*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 974*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 975*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 976*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); close(pipefd[0]); 977*28ef38a9SChristian Brauner close(pipefd[1]); 978*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 979*28ef38a9SChristian Brauner } 980*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 981*28ef38a9SChristian Brauner close(ns_fd); 982*28ef38a9SChristian Brauner 983*28ef38a9SChristian Brauner pid = fork(); 984*28ef38a9SChristian Brauner ASSERT_GE(pid, 0); 985*28ef38a9SChristian Brauner 986*28ef38a9SChristian Brauner if (pid == 0) { 987*28ef38a9SChristian Brauner /* Child process */ 988*28ef38a9SChristian Brauner close(pipefd[0]); 989*28ef38a9SChristian Brauner 990*28ef38a9SChristian Brauner /* First create new user namespace to drop privileges */ 991*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWUSER); 992*28ef38a9SChristian Brauner if (ret < 0) { 993*28ef38a9SChristian Brauner write(pipefd[1], "U", 994*28ef38a9SChristian Brauner 1); /* Unable to create user namespace */ 995*28ef38a9SChristian Brauner close(pipefd[1]); 996*28ef38a9SChristian Brauner exit(0); 997*28ef38a9SChristian Brauner } 998*28ef38a9SChristian Brauner 999*28ef38a9SChristian Brauner /* Write uid/gid mappings to maintain some capabilities */ 1000*28ef38a9SChristian Brauner int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 1001*28ef38a9SChristian Brauner int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 1002*28ef38a9SChristian Brauner int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 1003*28ef38a9SChristian Brauner 1004*28ef38a9SChristian Brauner if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 1005*28ef38a9SChristian Brauner write(pipefd[1], "M", 1); /* Unable to set mappings */ 1006*28ef38a9SChristian Brauner close(pipefd[1]); 1007*28ef38a9SChristian Brauner exit(0); 1008*28ef38a9SChristian Brauner } 1009*28ef38a9SChristian Brauner 1010*28ef38a9SChristian Brauner /* Disable setgroups to allow gid mapping */ 1011*28ef38a9SChristian Brauner write(setgroups_fd, "deny", 4); 1012*28ef38a9SChristian Brauner close(setgroups_fd); 1013*28ef38a9SChristian Brauner 1014*28ef38a9SChristian Brauner /* Map current uid/gid to root in the new namespace */ 1015*28ef38a9SChristian Brauner char mapping[64]; 1016*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 1017*28ef38a9SChristian Brauner write(uid_map_fd, mapping, strlen(mapping)); 1018*28ef38a9SChristian Brauner close(uid_map_fd); 1019*28ef38a9SChristian Brauner 1020*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 1021*28ef38a9SChristian Brauner write(gid_map_fd, mapping, strlen(mapping)); 1022*28ef38a9SChristian Brauner close(gid_map_fd); 1023*28ef38a9SChristian Brauner 1024*28ef38a9SChristian Brauner /* Now create new cgroup namespace */ 1025*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWCGROUP); 1026*28ef38a9SChristian Brauner if (ret < 0) { 1027*28ef38a9SChristian Brauner write(pipefd[1], "N", 1028*28ef38a9SChristian Brauner 1); /* Unable to create cgroup namespace */ 1029*28ef38a9SChristian Brauner close(pipefd[1]); 1030*28ef38a9SChristian Brauner exit(0); 1031*28ef38a9SChristian Brauner } 1032*28ef38a9SChristian Brauner 1033*28ef38a9SChristian Brauner /* Try to open parent's cgroup namespace handle from new user+cgroup namespace */ 1034*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 1035*28ef38a9SChristian Brauner 1036*28ef38a9SChristian Brauner if (fd >= 0) { 1037*28ef38a9SChristian Brauner /* Should NOT succeed - we're in a different user namespace */ 1038*28ef38a9SChristian Brauner write(pipefd[1], "S", 1); /* Unexpected success */ 1039*28ef38a9SChristian Brauner close(fd); 1040*28ef38a9SChristian Brauner } else if (errno == ESTALE) { 1041*28ef38a9SChristian Brauner /* Expected: Stale file handle */ 1042*28ef38a9SChristian Brauner write(pipefd[1], "P", 1); 1043*28ef38a9SChristian Brauner } else { 1044*28ef38a9SChristian Brauner /* Other error */ 1045*28ef38a9SChristian Brauner write(pipefd[1], "F", 1); 1046*28ef38a9SChristian Brauner } 1047*28ef38a9SChristian Brauner 1048*28ef38a9SChristian Brauner close(pipefd[1]); 1049*28ef38a9SChristian Brauner exit(0); 1050*28ef38a9SChristian Brauner } 1051*28ef38a9SChristian Brauner 1052*28ef38a9SChristian Brauner /* Parent process */ 1053*28ef38a9SChristian Brauner close(pipefd[1]); 1054*28ef38a9SChristian Brauner ASSERT_EQ(read(pipefd[0], &result, 1), 1); 1055*28ef38a9SChristian Brauner 1056*28ef38a9SChristian Brauner waitpid(pid, &status, 0); 1057*28ef38a9SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 1058*28ef38a9SChristian Brauner ASSERT_EQ(WEXITSTATUS(status), 0); 1059*28ef38a9SChristian Brauner 1060*28ef38a9SChristian Brauner if (result == 'U') { 1061*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 1062*28ef38a9SChristian Brauner return, "Cannot create new user namespace"); 1063*28ef38a9SChristian Brauner } 1064*28ef38a9SChristian Brauner if (result == 'M') { 1065*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 1066*28ef38a9SChristian Brauner return, "Cannot set uid/gid mappings"); 1067*28ef38a9SChristian Brauner } 1068*28ef38a9SChristian Brauner if (result == 'N') { 1069*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 1070*28ef38a9SChristian Brauner return, "Cannot create new cgroup namespace"); 1071*28ef38a9SChristian Brauner } 1072*28ef38a9SChristian Brauner 1073*28ef38a9SChristian Brauner /* Should fail with ESTALE since we're in a different user namespace */ 1074*28ef38a9SChristian Brauner ASSERT_EQ(result, 'P'); 1075*28ef38a9SChristian Brauner 1076*28ef38a9SChristian Brauner close(pipefd[0]); 1077*28ef38a9SChristian Brauner free(handle); 1078*28ef38a9SChristian Brauner } 1079*28ef38a9SChristian Brauner 1080*28ef38a9SChristian Brauner TEST(nsfs_user_pid_namespace_isolation) 1081*28ef38a9SChristian Brauner { 1082*28ef38a9SChristian Brauner struct file_handle *handle; 1083*28ef38a9SChristian Brauner int mount_id; 1084*28ef38a9SChristian Brauner int ret; 1085*28ef38a9SChristian Brauner int fd; 1086*28ef38a9SChristian Brauner int ns_fd; 1087*28ef38a9SChristian Brauner pid_t pid; 1088*28ef38a9SChristian Brauner int status; 1089*28ef38a9SChristian Brauner int pipefd[2]; 1090*28ef38a9SChristian Brauner char result; 1091*28ef38a9SChristian Brauner 1092*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 1093*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 1094*28ef38a9SChristian Brauner 1095*28ef38a9SChristian Brauner /* Create pipe for communication */ 1096*28ef38a9SChristian Brauner ASSERT_EQ(pipe(pipefd), 0); 1097*28ef38a9SChristian Brauner 1098*28ef38a9SChristian Brauner /* Get handle for current PID namespace */ 1099*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/pid", O_RDONLY); 1100*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 1101*28ef38a9SChristian Brauner 1102*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 1103*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 1104*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 1105*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); close(pipefd[0]); 1106*28ef38a9SChristian Brauner close(pipefd[1]); 1107*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 1108*28ef38a9SChristian Brauner } 1109*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 1110*28ef38a9SChristian Brauner close(ns_fd); 1111*28ef38a9SChristian Brauner 1112*28ef38a9SChristian Brauner pid = fork(); 1113*28ef38a9SChristian Brauner ASSERT_GE(pid, 0); 1114*28ef38a9SChristian Brauner 1115*28ef38a9SChristian Brauner if (pid == 0) { 1116*28ef38a9SChristian Brauner /* Child process */ 1117*28ef38a9SChristian Brauner close(pipefd[0]); 1118*28ef38a9SChristian Brauner 1119*28ef38a9SChristian Brauner /* First create new user namespace to drop privileges */ 1120*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWUSER); 1121*28ef38a9SChristian Brauner if (ret < 0) { 1122*28ef38a9SChristian Brauner write(pipefd[1], "U", 1123*28ef38a9SChristian Brauner 1); /* Unable to create user namespace */ 1124*28ef38a9SChristian Brauner close(pipefd[1]); 1125*28ef38a9SChristian Brauner exit(0); 1126*28ef38a9SChristian Brauner } 1127*28ef38a9SChristian Brauner 1128*28ef38a9SChristian Brauner /* Write uid/gid mappings to maintain some capabilities */ 1129*28ef38a9SChristian Brauner int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 1130*28ef38a9SChristian Brauner int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 1131*28ef38a9SChristian Brauner int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 1132*28ef38a9SChristian Brauner 1133*28ef38a9SChristian Brauner if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 1134*28ef38a9SChristian Brauner write(pipefd[1], "M", 1); /* Unable to set mappings */ 1135*28ef38a9SChristian Brauner close(pipefd[1]); 1136*28ef38a9SChristian Brauner exit(0); 1137*28ef38a9SChristian Brauner } 1138*28ef38a9SChristian Brauner 1139*28ef38a9SChristian Brauner /* Disable setgroups to allow gid mapping */ 1140*28ef38a9SChristian Brauner write(setgroups_fd, "deny", 4); 1141*28ef38a9SChristian Brauner close(setgroups_fd); 1142*28ef38a9SChristian Brauner 1143*28ef38a9SChristian Brauner /* Map current uid/gid to root in the new namespace */ 1144*28ef38a9SChristian Brauner char mapping[64]; 1145*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 1146*28ef38a9SChristian Brauner write(uid_map_fd, mapping, strlen(mapping)); 1147*28ef38a9SChristian Brauner close(uid_map_fd); 1148*28ef38a9SChristian Brauner 1149*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 1150*28ef38a9SChristian Brauner write(gid_map_fd, mapping, strlen(mapping)); 1151*28ef38a9SChristian Brauner close(gid_map_fd); 1152*28ef38a9SChristian Brauner 1153*28ef38a9SChristian Brauner /* Now create new PID namespace - requires fork to take effect */ 1154*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWPID); 1155*28ef38a9SChristian Brauner if (ret < 0) { 1156*28ef38a9SChristian Brauner write(pipefd[1], "N", 1157*28ef38a9SChristian Brauner 1); /* Unable to create PID namespace */ 1158*28ef38a9SChristian Brauner close(pipefd[1]); 1159*28ef38a9SChristian Brauner exit(0); 1160*28ef38a9SChristian Brauner } 1161*28ef38a9SChristian Brauner 1162*28ef38a9SChristian Brauner /* Fork again for PID namespace to take effect */ 1163*28ef38a9SChristian Brauner pid_t child_pid = fork(); 1164*28ef38a9SChristian Brauner if (child_pid < 0) { 1165*28ef38a9SChristian Brauner write(pipefd[1], "N", 1166*28ef38a9SChristian Brauner 1); /* Unable to fork in PID namespace */ 1167*28ef38a9SChristian Brauner close(pipefd[1]); 1168*28ef38a9SChristian Brauner exit(0); 1169*28ef38a9SChristian Brauner } 1170*28ef38a9SChristian Brauner 1171*28ef38a9SChristian Brauner if (child_pid == 0) { 1172*28ef38a9SChristian Brauner /* Grandchild in new PID namespace */ 1173*28ef38a9SChristian Brauner /* Try to open parent's PID namespace handle from new user+pid namespace */ 1174*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 1175*28ef38a9SChristian Brauner 1176*28ef38a9SChristian Brauner if (fd >= 0) { 1177*28ef38a9SChristian Brauner /* Should NOT succeed - we're in a different user namespace */ 1178*28ef38a9SChristian Brauner write(pipefd[1], "S", 1179*28ef38a9SChristian Brauner 1); /* Unexpected success */ 1180*28ef38a9SChristian Brauner close(fd); 1181*28ef38a9SChristian Brauner } else if (errno == ESTALE) { 1182*28ef38a9SChristian Brauner /* Expected: Stale file handle */ 1183*28ef38a9SChristian Brauner write(pipefd[1], "P", 1); 1184*28ef38a9SChristian Brauner } else { 1185*28ef38a9SChristian Brauner /* Other error */ 1186*28ef38a9SChristian Brauner write(pipefd[1], "F", 1); 1187*28ef38a9SChristian Brauner } 1188*28ef38a9SChristian Brauner 1189*28ef38a9SChristian Brauner close(pipefd[1]); 1190*28ef38a9SChristian Brauner exit(0); 1191*28ef38a9SChristian Brauner } 1192*28ef38a9SChristian Brauner 1193*28ef38a9SChristian Brauner /* Wait for grandchild */ 1194*28ef38a9SChristian Brauner waitpid(child_pid, NULL, 0); 1195*28ef38a9SChristian Brauner exit(0); 1196*28ef38a9SChristian Brauner } 1197*28ef38a9SChristian Brauner 1198*28ef38a9SChristian Brauner /* Parent process */ 1199*28ef38a9SChristian Brauner close(pipefd[1]); 1200*28ef38a9SChristian Brauner ASSERT_EQ(read(pipefd[0], &result, 1), 1); 1201*28ef38a9SChristian Brauner 1202*28ef38a9SChristian Brauner waitpid(pid, &status, 0); 1203*28ef38a9SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 1204*28ef38a9SChristian Brauner ASSERT_EQ(WEXITSTATUS(status), 0); 1205*28ef38a9SChristian Brauner 1206*28ef38a9SChristian Brauner if (result == 'U') { 1207*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 1208*28ef38a9SChristian Brauner return, "Cannot create new user namespace"); 1209*28ef38a9SChristian Brauner } 1210*28ef38a9SChristian Brauner if (result == 'M') { 1211*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 1212*28ef38a9SChristian Brauner return, "Cannot set uid/gid mappings"); 1213*28ef38a9SChristian Brauner } 1214*28ef38a9SChristian Brauner if (result == 'N') { 1215*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 1216*28ef38a9SChristian Brauner return, "Cannot create new PID namespace"); 1217*28ef38a9SChristian Brauner } 1218*28ef38a9SChristian Brauner 1219*28ef38a9SChristian Brauner /* Should fail with ESTALE since we're in a different user namespace */ 1220*28ef38a9SChristian Brauner ASSERT_EQ(result, 'P'); 1221*28ef38a9SChristian Brauner 1222*28ef38a9SChristian Brauner close(pipefd[0]); 1223*28ef38a9SChristian Brauner free(handle); 1224*28ef38a9SChristian Brauner } 1225*28ef38a9SChristian Brauner 1226*28ef38a9SChristian Brauner TEST(nsfs_user_time_namespace_isolation) 1227*28ef38a9SChristian Brauner { 1228*28ef38a9SChristian Brauner struct file_handle *handle; 1229*28ef38a9SChristian Brauner int mount_id; 1230*28ef38a9SChristian Brauner int ret; 1231*28ef38a9SChristian Brauner int fd; 1232*28ef38a9SChristian Brauner int ns_fd; 1233*28ef38a9SChristian Brauner pid_t pid; 1234*28ef38a9SChristian Brauner int status; 1235*28ef38a9SChristian Brauner int pipefd[2]; 1236*28ef38a9SChristian Brauner char result; 1237*28ef38a9SChristian Brauner 1238*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 1239*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 1240*28ef38a9SChristian Brauner 1241*28ef38a9SChristian Brauner /* Create pipe for communication */ 1242*28ef38a9SChristian Brauner ASSERT_EQ(pipe(pipefd), 0); 1243*28ef38a9SChristian Brauner 1244*28ef38a9SChristian Brauner /* Get handle for current time namespace */ 1245*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/time", O_RDONLY); 1246*28ef38a9SChristian Brauner if (ns_fd < 0) { 1247*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); close(pipefd[1]); 1248*28ef38a9SChristian Brauner return, "time namespace not available"); 1249*28ef38a9SChristian Brauner } 1250*28ef38a9SChristian Brauner 1251*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 1252*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 1253*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 1254*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); close(pipefd[0]); 1255*28ef38a9SChristian Brauner close(pipefd[1]); 1256*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 1257*28ef38a9SChristian Brauner } 1258*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 1259*28ef38a9SChristian Brauner close(ns_fd); 1260*28ef38a9SChristian Brauner 1261*28ef38a9SChristian Brauner pid = fork(); 1262*28ef38a9SChristian Brauner ASSERT_GE(pid, 0); 1263*28ef38a9SChristian Brauner 1264*28ef38a9SChristian Brauner if (pid == 0) { 1265*28ef38a9SChristian Brauner /* Child process */ 1266*28ef38a9SChristian Brauner close(pipefd[0]); 1267*28ef38a9SChristian Brauner 1268*28ef38a9SChristian Brauner /* First create new user namespace to drop privileges */ 1269*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWUSER); 1270*28ef38a9SChristian Brauner if (ret < 0) { 1271*28ef38a9SChristian Brauner write(pipefd[1], "U", 1272*28ef38a9SChristian Brauner 1); /* Unable to create user namespace */ 1273*28ef38a9SChristian Brauner close(pipefd[1]); 1274*28ef38a9SChristian Brauner exit(0); 1275*28ef38a9SChristian Brauner } 1276*28ef38a9SChristian Brauner 1277*28ef38a9SChristian Brauner /* Write uid/gid mappings to maintain some capabilities */ 1278*28ef38a9SChristian Brauner int uid_map_fd = open("/proc/self/uid_map", O_WRONLY); 1279*28ef38a9SChristian Brauner int gid_map_fd = open("/proc/self/gid_map", O_WRONLY); 1280*28ef38a9SChristian Brauner int setgroups_fd = open("/proc/self/setgroups", O_WRONLY); 1281*28ef38a9SChristian Brauner 1282*28ef38a9SChristian Brauner if (uid_map_fd < 0 || gid_map_fd < 0 || setgroups_fd < 0) { 1283*28ef38a9SChristian Brauner write(pipefd[1], "M", 1); /* Unable to set mappings */ 1284*28ef38a9SChristian Brauner close(pipefd[1]); 1285*28ef38a9SChristian Brauner exit(0); 1286*28ef38a9SChristian Brauner } 1287*28ef38a9SChristian Brauner 1288*28ef38a9SChristian Brauner /* Disable setgroups to allow gid mapping */ 1289*28ef38a9SChristian Brauner write(setgroups_fd, "deny", 4); 1290*28ef38a9SChristian Brauner close(setgroups_fd); 1291*28ef38a9SChristian Brauner 1292*28ef38a9SChristian Brauner /* Map current uid/gid to root in the new namespace */ 1293*28ef38a9SChristian Brauner char mapping[64]; 1294*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getuid()); 1295*28ef38a9SChristian Brauner write(uid_map_fd, mapping, strlen(mapping)); 1296*28ef38a9SChristian Brauner close(uid_map_fd); 1297*28ef38a9SChristian Brauner 1298*28ef38a9SChristian Brauner snprintf(mapping, sizeof(mapping), "0 %d 1", getgid()); 1299*28ef38a9SChristian Brauner write(gid_map_fd, mapping, strlen(mapping)); 1300*28ef38a9SChristian Brauner close(gid_map_fd); 1301*28ef38a9SChristian Brauner 1302*28ef38a9SChristian Brauner /* Now create new time namespace - requires fork to take effect */ 1303*28ef38a9SChristian Brauner ret = unshare(CLONE_NEWTIME); 1304*28ef38a9SChristian Brauner if (ret < 0) { 1305*28ef38a9SChristian Brauner write(pipefd[1], "N", 1306*28ef38a9SChristian Brauner 1); /* Unable to create time namespace */ 1307*28ef38a9SChristian Brauner close(pipefd[1]); 1308*28ef38a9SChristian Brauner exit(0); 1309*28ef38a9SChristian Brauner } 1310*28ef38a9SChristian Brauner 1311*28ef38a9SChristian Brauner /* Fork again for time namespace to take effect */ 1312*28ef38a9SChristian Brauner pid_t child_pid = fork(); 1313*28ef38a9SChristian Brauner if (child_pid < 0) { 1314*28ef38a9SChristian Brauner write(pipefd[1], "N", 1315*28ef38a9SChristian Brauner 1); /* Unable to fork in time namespace */ 1316*28ef38a9SChristian Brauner close(pipefd[1]); 1317*28ef38a9SChristian Brauner exit(0); 1318*28ef38a9SChristian Brauner } 1319*28ef38a9SChristian Brauner 1320*28ef38a9SChristian Brauner if (child_pid == 0) { 1321*28ef38a9SChristian Brauner /* Grandchild in new time namespace */ 1322*28ef38a9SChristian Brauner /* Try to open parent's time namespace handle from new user+time namespace */ 1323*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY); 1324*28ef38a9SChristian Brauner 1325*28ef38a9SChristian Brauner if (fd >= 0) { 1326*28ef38a9SChristian Brauner /* Should NOT succeed - we're in a different user namespace */ 1327*28ef38a9SChristian Brauner write(pipefd[1], "S", 1328*28ef38a9SChristian Brauner 1); /* Unexpected success */ 1329*28ef38a9SChristian Brauner close(fd); 1330*28ef38a9SChristian Brauner } else if (errno == ESTALE) { 1331*28ef38a9SChristian Brauner /* Expected: Stale file handle */ 1332*28ef38a9SChristian Brauner write(pipefd[1], "P", 1); 1333*28ef38a9SChristian Brauner } else { 1334*28ef38a9SChristian Brauner /* Other error */ 1335*28ef38a9SChristian Brauner write(pipefd[1], "F", 1); 1336*28ef38a9SChristian Brauner } 1337*28ef38a9SChristian Brauner 1338*28ef38a9SChristian Brauner close(pipefd[1]); 1339*28ef38a9SChristian Brauner exit(0); 1340*28ef38a9SChristian Brauner } 1341*28ef38a9SChristian Brauner 1342*28ef38a9SChristian Brauner /* Wait for grandchild */ 1343*28ef38a9SChristian Brauner waitpid(child_pid, NULL, 0); 1344*28ef38a9SChristian Brauner exit(0); 1345*28ef38a9SChristian Brauner } 1346*28ef38a9SChristian Brauner 1347*28ef38a9SChristian Brauner /* Parent process */ 1348*28ef38a9SChristian Brauner close(pipefd[1]); 1349*28ef38a9SChristian Brauner ASSERT_EQ(read(pipefd[0], &result, 1), 1); 1350*28ef38a9SChristian Brauner 1351*28ef38a9SChristian Brauner waitpid(pid, &status, 0); 1352*28ef38a9SChristian Brauner ASSERT_TRUE(WIFEXITED(status)); 1353*28ef38a9SChristian Brauner ASSERT_EQ(WEXITSTATUS(status), 0); 1354*28ef38a9SChristian Brauner 1355*28ef38a9SChristian Brauner if (result == 'U') { 1356*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 1357*28ef38a9SChristian Brauner return, "Cannot create new user namespace"); 1358*28ef38a9SChristian Brauner } 1359*28ef38a9SChristian Brauner if (result == 'M') { 1360*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 1361*28ef38a9SChristian Brauner return, "Cannot set uid/gid mappings"); 1362*28ef38a9SChristian Brauner } 1363*28ef38a9SChristian Brauner if (result == 'N') { 1364*28ef38a9SChristian Brauner SKIP(free(handle); close(pipefd[0]); 1365*28ef38a9SChristian Brauner return, "Cannot create new time namespace"); 1366*28ef38a9SChristian Brauner } 1367*28ef38a9SChristian Brauner 1368*28ef38a9SChristian Brauner /* Should fail with ESTALE since we're in a different user namespace */ 1369*28ef38a9SChristian Brauner ASSERT_EQ(result, 'P'); 1370*28ef38a9SChristian Brauner 1371*28ef38a9SChristian Brauner close(pipefd[0]); 1372*28ef38a9SChristian Brauner free(handle); 1373*28ef38a9SChristian Brauner } 1374*28ef38a9SChristian Brauner 1375*28ef38a9SChristian Brauner TEST(nsfs_open_flags) 1376*28ef38a9SChristian Brauner { 1377*28ef38a9SChristian Brauner struct file_handle *handle; 1378*28ef38a9SChristian Brauner int mount_id; 1379*28ef38a9SChristian Brauner int ret; 1380*28ef38a9SChristian Brauner int fd; 1381*28ef38a9SChristian Brauner int ns_fd; 1382*28ef38a9SChristian Brauner 1383*28ef38a9SChristian Brauner handle = malloc(sizeof(*handle) + MAX_HANDLE_SZ); 1384*28ef38a9SChristian Brauner ASSERT_NE(handle, NULL); 1385*28ef38a9SChristian Brauner 1386*28ef38a9SChristian Brauner /* Open a namespace file descriptor */ 1387*28ef38a9SChristian Brauner ns_fd = open("/proc/self/ns/net", O_RDONLY); 1388*28ef38a9SChristian Brauner ASSERT_GE(ns_fd, 0); 1389*28ef38a9SChristian Brauner 1390*28ef38a9SChristian Brauner /* Get handle for the namespace */ 1391*28ef38a9SChristian Brauner handle->handle_bytes = MAX_HANDLE_SZ; 1392*28ef38a9SChristian Brauner ret = name_to_handle_at(ns_fd, "", handle, &mount_id, AT_EMPTY_PATH); 1393*28ef38a9SChristian Brauner if (ret < 0 && errno == EOPNOTSUPP) { 1394*28ef38a9SChristian Brauner SKIP(free(handle); close(ns_fd); 1395*28ef38a9SChristian Brauner return, "nsfs doesn't support file handles"); 1396*28ef38a9SChristian Brauner } 1397*28ef38a9SChristian Brauner ASSERT_EQ(ret, 0); 1398*28ef38a9SChristian Brauner ASSERT_GT(handle->handle_bytes, 0); 1399*28ef38a9SChristian Brauner 1400*28ef38a9SChristian Brauner /* Test invalid flags that should fail */ 1401*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_WRONLY); 1402*28ef38a9SChristian Brauner ASSERT_LT(fd, 0); 1403*28ef38a9SChristian Brauner ASSERT_EQ(errno, EPERM); 1404*28ef38a9SChristian Brauner 1405*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDWR); 1406*28ef38a9SChristian Brauner ASSERT_LT(fd, 0); 1407*28ef38a9SChristian Brauner ASSERT_EQ(errno, EPERM); 1408*28ef38a9SChristian Brauner 1409*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_TRUNC); 1410*28ef38a9SChristian Brauner ASSERT_LT(fd, 0); 1411*28ef38a9SChristian Brauner ASSERT_EQ(errno, EPERM); 1412*28ef38a9SChristian Brauner 1413*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_DIRECT); 1414*28ef38a9SChristian Brauner ASSERT_LT(fd, 0); 1415*28ef38a9SChristian Brauner ASSERT_EQ(errno, EINVAL); 1416*28ef38a9SChristian Brauner 1417*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_TMPFILE); 1418*28ef38a9SChristian Brauner ASSERT_LT(fd, 0); 1419*28ef38a9SChristian Brauner ASSERT_EQ(errno, EINVAL); 1420*28ef38a9SChristian Brauner 1421*28ef38a9SChristian Brauner fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_DIRECTORY); 1422*28ef38a9SChristian Brauner ASSERT_LT(fd, 0); 1423*28ef38a9SChristian Brauner ASSERT_EQ(errno, ENOTDIR); 1424*28ef38a9SChristian Brauner 1425*28ef38a9SChristian Brauner close(ns_fd); 1426*28ef38a9SChristian Brauner free(handle); 1427*28ef38a9SChristian Brauner } 1428*28ef38a9SChristian Brauner 1429*28ef38a9SChristian Brauner TEST_HARNESS_MAIN 1430