1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <sched.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <sys/wait.h> 9 #include <unistd.h> 10 #include "../kselftest_harness.h" 11 12 /* 13 * The fields of a uid_map/gid_map line are stored in u32. Values that 14 * do not fit, and negative values, must be rejected with EINVAL instead 15 * of being silently truncated, and in-range values must still be 16 * accepted. 17 */ 18 19 static int write_file(const char *path, const char *buf) 20 { 21 ssize_t len = strlen(buf); 22 ssize_t ret; 23 int fd; 24 25 fd = open(path, O_WRONLY | O_CLOEXEC); 26 if (fd < 0) 27 return -errno; 28 ret = write(fd, buf, len); 29 if (ret < 0) 30 ret = -errno; 31 close(fd); 32 if (ret < 0) 33 return ret; 34 return ret == len ? 0 : -EIO; 35 } 36 37 static ssize_t read_file(const char *path, char *buf, size_t size) 38 { 39 ssize_t ret; 40 int fd; 41 42 fd = open(path, O_RDONLY | O_CLOEXEC); 43 if (fd < 0) 44 return -errno; 45 ret = read(fd, buf, size - 1); 46 if (ret < 0) 47 ret = -errno; 48 else 49 buf[ret] = '\0'; 50 close(fd); 51 return ret; 52 } 53 54 /* Enter a fresh user namespace, remembering the outer ids. */ 55 static int enter_userns(uid_t *uid, gid_t *gid) 56 { 57 *uid = geteuid(); 58 *gid = getegid(); 59 if (unshare(CLONE_NEWUSER) < 0) 60 return -errno; 61 /* Required before an unprivileged gid_map write. */ 62 return write_file("/proc/self/setgroups", "deny"); 63 } 64 65 static void expect_rejected(struct __test_metadata *_metadata, 66 const char *path, const char *line) 67 { 68 char buf[256]; 69 70 TH_LOG("writing \"%s\" to %s", line, path); 71 EXPECT_EQ(write_file(path, line), -EINVAL); 72 /* Nothing may have been installed. */ 73 EXPECT_EQ(read_file(path, buf, sizeof(buf)), 0) { 74 TH_LOG("installed: %s", buf); 75 } 76 } 77 78 static void expect_accepted(struct __test_metadata *_metadata, 79 const char *path, const char *line, 80 unsigned int first, unsigned int lower_first, 81 unsigned int count) 82 { 83 unsigned int f, l, c; 84 char buf[256]; 85 86 TH_LOG("writing \"%s\" to %s", line, path); 87 ASSERT_EQ(write_file(path, line), 0); 88 89 ASSERT_GT(read_file(path, buf, sizeof(buf)), 0); 90 ASSERT_EQ(sscanf(buf, "%u %u %u", &f, &l, &c), 3); 91 EXPECT_EQ(f, first); 92 EXPECT_EQ(l, lower_first); 93 EXPECT_EQ(c, count); 94 /* Exactly one extent. */ 95 EXPECT_EQ(strchr(buf, '\n'), buf + strlen(buf) - 1); 96 } 97 98 TEST(uid_map_first_above_u32) 99 { 100 char line[64]; 101 uid_t uid; 102 gid_t gid; 103 int ret; 104 105 ret = enter_userns(&uid, &gid); 106 if (ret) 107 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 108 snprintf(line, sizeof(line), "4294967301 %u 1", uid); 109 expect_rejected(_metadata, "/proc/self/uid_map", line); 110 } 111 112 TEST(uid_map_lower_first_above_u32) 113 { 114 char line[64]; 115 uid_t uid; 116 gid_t gid; 117 int ret; 118 119 ret = enter_userns(&uid, &gid); 120 if (ret) 121 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 122 snprintf(line, sizeof(line), "0 %llu 1", (1ULL << 32) + uid); 123 expect_rejected(_metadata, "/proc/self/uid_map", line); 124 } 125 126 TEST(uid_map_count_above_u32) 127 { 128 char line[64]; 129 uid_t uid; 130 gid_t gid; 131 int ret; 132 133 ret = enter_userns(&uid, &gid); 134 if (ret) 135 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 136 snprintf(line, sizeof(line), "0 %u 4294967297", uid); 137 expect_rejected(_metadata, "/proc/self/uid_map", line); 138 } 139 140 TEST(gid_map_first_above_u32) 141 { 142 char line[64]; 143 uid_t uid; 144 gid_t gid; 145 int ret; 146 147 ret = enter_userns(&uid, &gid); 148 if (ret) 149 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 150 snprintf(line, sizeof(line), "4294967301 %u 1", gid); 151 expect_rejected(_metadata, "/proc/self/gid_map", line); 152 } 153 154 TEST(uid_map_first_negative) 155 { 156 char line[64]; 157 uid_t uid; 158 gid_t gid; 159 int ret; 160 161 ret = enter_userns(&uid, &gid); 162 if (ret) 163 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 164 snprintf(line, sizeof(line), "-1 %u 1", uid); 165 expect_rejected(_metadata, "/proc/self/uid_map", line); 166 } 167 168 TEST(uid_map_lower_first_negative) 169 { 170 uid_t uid; 171 gid_t gid; 172 int ret; 173 174 ret = enter_userns(&uid, &gid); 175 if (ret) 176 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 177 expect_rejected(_metadata, "/proc/self/uid_map", "0 -1 1"); 178 } 179 180 TEST(uid_map_count_negative) 181 { 182 char line[64]; 183 uid_t uid; 184 gid_t gid; 185 int ret; 186 187 ret = enter_userns(&uid, &gid); 188 if (ret) 189 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 190 snprintf(line, sizeof(line), "0 %u -1", uid); 191 expect_rejected(_metadata, "/proc/self/uid_map", line); 192 } 193 194 TEST(uid_map_in_range) 195 { 196 char line[64]; 197 uid_t uid; 198 gid_t gid; 199 int ret; 200 201 ret = enter_userns(&uid, &gid); 202 if (ret) 203 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 204 snprintf(line, sizeof(line), "5 %u 1", uid); 205 expect_accepted(_metadata, "/proc/self/uid_map", line, 5, uid, 1); 206 } 207 208 TEST(uid_map_zero) 209 { 210 char line[64]; 211 uid_t uid; 212 gid_t gid; 213 int ret; 214 215 ret = enter_userns(&uid, &gid); 216 if (ret) 217 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 218 snprintf(line, sizeof(line), "0 %u 1", uid); 219 expect_accepted(_metadata, "/proc/self/uid_map", line, 0, uid, 1); 220 } 221 222 /* 4294967295 is (u32)-1, which map_write() refuses as a starting id. */ 223 TEST(uid_map_largest_first) 224 { 225 char line[64]; 226 uid_t uid; 227 gid_t gid; 228 int ret; 229 230 ret = enter_userns(&uid, &gid); 231 if (ret) 232 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 233 snprintf(line, sizeof(line), "4294967294 %u 1", uid); 234 expect_accepted(_metadata, "/proc/self/uid_map", line, 235 4294967294U, uid, 1); 236 } 237 238 TEST(uid_map_extra_spaces) 239 { 240 char line[64]; 241 uid_t uid; 242 gid_t gid; 243 int ret; 244 245 ret = enter_userns(&uid, &gid); 246 if (ret) 247 SKIP(return, "cannot set up user namespace: %s", strerror(-ret)); 248 snprintf(line, sizeof(line), "0 %u 1", uid); 249 expect_accepted(_metadata, "/proc/self/uid_map", line, 0, uid, 1); 250 } 251 252 /* 253 * An unprivileged writer may only map a single id, so the largest count 254 * needs a privileged parent writing the map of a child namespace. With 255 * first and lower_first 0, the no-wrap rule allows up to 4294967295. 256 */ 257 TEST(uid_map_largest_count) 258 { 259 unsigned int first, lower_first, count; 260 int to_child[2], from_child[2]; 261 char path[64], buf[256]; 262 pid_t pid; 263 char c; 264 265 if (geteuid() != 0) 266 SKIP(return, "needs root in the initial user namespace"); 267 ASSERT_GT(read_file("/proc/self/uid_map", buf, sizeof(buf)), 0); 268 ASSERT_EQ(sscanf(buf, "%u %u %u", &first, &lower_first, &count), 3); 269 if (first != 0 || lower_first != 0 || count != 4294967295U) 270 SKIP(return, "not in the initial user namespace"); 271 272 ASSERT_EQ(pipe(to_child), 0); 273 ASSERT_EQ(pipe(from_child), 0); 274 pid = fork(); 275 ASSERT_GE(pid, 0); 276 if (pid == 0) { 277 close(to_child[1]); 278 close(from_child[0]); 279 c = unshare(CLONE_NEWUSER) ? 'F' : 'K'; 280 if (write(from_child[1], &c, 1) != 1) 281 _exit(1); 282 /* Stay alive until the parent is done with our uid_map. */ 283 if (read(to_child[0], &c, 1) < 0) 284 _exit(1); 285 _exit(0); 286 } 287 close(to_child[0]); 288 close(from_child[1]); 289 290 ASSERT_EQ(read(from_child[0], &c, 1), 1); 291 ASSERT_EQ(c, 'K'); 292 snprintf(path, sizeof(path), "/proc/%d/uid_map", pid); 293 expect_accepted(_metadata, path, "0 0 4294967295", 0, 0, 4294967295U); 294 295 close(to_child[1]); 296 EXPECT_EQ(waitpid(pid, NULL, 0), pid); 297 } 298 299 TEST_HARNESS_MAIN 300