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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'vfs-6.15-rc1.overlayfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs overlayfs updates from Christian Brauner:
"Currently overlayfs uses the mounter's credentials for its
override_creds() calls. That provides a consistent permission model.

This patches allows a caller to instruct overlayfs to use its
credentials instead. The caller must be located in the same user
namespace hierarchy as the user namespace the overlayfs instance will
be mounted in. This provides a consistent and simple security model.

With this it is possible to e.g., mount an overlayfs instance where
the mounter must have CAP_SYS_ADMIN but the credentials used for
override_creds() have dropped CAP_SYS_ADMIN. It also allows the usage
of custom fs{g,u}id different from the callers and other tweaks"

* tag 'vfs-6.15-rc1.overlayfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
selftests/ovl: add third selftest for "override_creds"
selftests/ovl: add second selftest for "override_creds"
selftests/filesystems: add utils.{c,h}
selftests/ovl: add first selftest for "override_creds"
ovl: allow to specify override credentials

+926 -12
+19 -5
Documentation/filesystems/overlayfs.rst
··· 292 292 Permission model 293 293 ---------------- 294 294 295 + An overlay filesystem stashes credentials that will be used when 296 + accessing lower or upper filesystems. 297 + 298 + In the old mount api the credentials of the task calling mount(2) are 299 + stashed. In the new mount api the credentials of the task creating the 300 + superblock through FSCONFIG_CMD_CREATE command of fsconfig(2) are 301 + stashed. 302 + 303 + Starting with kernel v6.15 it is possible to use the "override_creds" 304 + mount option which will cause the credentials of the calling task to be 305 + recorded. Note that "override_creds" is only meaningful when used with 306 + the new mount api as the old mount api combines setting options and 307 + superblock creation in a single mount(2) syscall. 308 + 295 309 Permission checking in the overlay filesystem follows these principles: 296 310 297 311 1) permission check SHOULD return the same result before and after copy up 298 312 299 313 2) task creating the overlay mount MUST NOT gain additional privileges 300 314 301 - 3) non-mounting task MAY gain additional privileges through the overlay, 315 + 3) task[*] MAY gain additional privileges through the overlay, 302 316 compared to direct access on underlying lower or upper filesystems 303 317 304 318 This is achieved by performing two permission checks on each access: ··· 320 306 a) check if current task is allowed access based on local DAC (owner, 321 307 group, mode and posix acl), as well as MAC checks 322 308 323 - b) check if mounting task would be allowed real operation on lower or 309 + b) check if stashed credentials would be allowed real operation on lower or 324 310 upper layer based on underlying filesystem permissions, again including 325 311 MAC checks 326 312 ··· 329 315 permissions (used by NFS, for example) being ignored (3). 330 316 331 317 Check (b) ensures that no task gains permissions to underlying layers that 332 - the mounting task does not have (2). This also means that it is possible 318 + the stashed credentials do not have (2). This also means that it is possible 333 319 to create setups where the consistency rule (1) does not hold; normally, 334 - however, the mounting task will have sufficient privileges to perform all 335 - operations. 320 + however, the stashed credentials will have sufficient privileges to 321 + perform all operations. 336 322 337 323 Another way to demonstrate this model is drawing parallels between:: 338 324
+25
fs/overlayfs/params.c
··· 59 59 Opt_metacopy, 60 60 Opt_verity, 61 61 Opt_volatile, 62 + Opt_override_creds, 62 63 }; 63 64 64 65 static const struct constant_table ovl_parameter_bool[] = { ··· 156 155 fsparam_enum("metacopy", Opt_metacopy, ovl_parameter_bool), 157 156 fsparam_enum("verity", Opt_verity, ovl_parameter_verity), 158 157 fsparam_flag("volatile", Opt_volatile), 158 + fsparam_flag_no("override_creds", Opt_override_creds), 159 159 {} 160 160 }; 161 161 ··· 664 662 case Opt_userxattr: 665 663 config->userxattr = true; 666 664 break; 665 + case Opt_override_creds: { 666 + const struct cred *cred = NULL; 667 + 668 + if (result.negated) { 669 + swap(cred, ofs->creator_cred); 670 + put_cred(cred); 671 + break; 672 + } 673 + 674 + if (!current_in_userns(fc->user_ns)) { 675 + err = -EINVAL; 676 + break; 677 + } 678 + 679 + cred = prepare_creds(); 680 + if (cred) 681 + swap(cred, ofs->creator_cred); 682 + else 683 + err = -ENOMEM; 684 + 685 + put_cred(cred); 686 + break; 687 + } 667 688 default: 668 689 pr_err("unrecognized mount option \"%s\" or missing value\n", 669 690 param->key);
+15 -1
fs/overlayfs/super.c
··· 1305 1305 { 1306 1306 struct ovl_fs *ofs = sb->s_fs_info; 1307 1307 struct ovl_fs_context *ctx = fc->fs_private; 1308 + const struct cred *old_cred = NULL; 1308 1309 struct dentry *root_dentry; 1309 1310 struct ovl_entry *oe; 1310 1311 struct ovl_layer *layers; ··· 1319 1318 sb->s_d_op = &ovl_dentry_operations; 1320 1319 1321 1320 err = -ENOMEM; 1322 - ofs->creator_cred = cred = prepare_creds(); 1321 + if (!ofs->creator_cred) 1322 + ofs->creator_cred = cred = prepare_creds(); 1323 + else 1324 + cred = (struct cred *)ofs->creator_cred; 1323 1325 if (!cred) 1324 1326 goto out_err; 1327 + 1328 + old_cred = ovl_override_creds(sb); 1325 1329 1326 1330 err = ovl_fs_params_verify(ctx, &ofs->config); 1327 1331 if (err) ··· 1487 1481 1488 1482 sb->s_root = root_dentry; 1489 1483 1484 + ovl_revert_creds(old_cred); 1490 1485 return 0; 1491 1486 1492 1487 out_free_oe: 1493 1488 ovl_free_entry(oe); 1494 1489 out_err: 1490 + /* 1491 + * Revert creds before calling ovl_free_fs() which will call 1492 + * put_cred() and put_cred() requires that the cred's that are 1493 + * put are not the caller's creds, i.e., current->cred. 1494 + */ 1495 + if (old_cred) 1496 + ovl_revert_creds(old_cred); 1495 1497 ovl_free_fs(ofs); 1496 1498 sb->s_fs_info = NULL; 1497 1499 return err;
+9 -2
tools/testing/selftests/filesystems/overlayfs/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 - TEST_GEN_PROGS := dev_in_maps set_layers_via_fds 3 + CFLAGS += -Wall 4 + CFLAGS += $(KHDR_INCLUDES) 5 + LDLIBS += -lcap 4 6 5 - CFLAGS := -Wall -Werror 7 + LOCAL_HDRS += wrappers.h log.h 8 + 9 + TEST_GEN_PROGS := dev_in_maps 10 + TEST_GEN_PROGS += set_layers_via_fds 6 11 7 12 include ../../lib.mk 13 + 14 + $(OUTPUT)/set_layers_via_fds: ../utils.c
+312 -4
tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c
··· 6 6 #include <sched.h> 7 7 #include <stdio.h> 8 8 #include <string.h> 9 + #include <sys/socket.h> 9 10 #include <sys/stat.h> 11 + #include <sys/sysmacros.h> 10 12 #include <sys/mount.h> 11 13 #include <unistd.h> 12 14 13 15 #include "../../kselftest_harness.h" 16 + #include "../../pidfd/pidfd.h" 14 17 #include "log.h" 18 + #include "../utils.h" 15 19 #include "wrappers.h" 16 20 17 21 FIXTURE(set_layers_via_fds) { 22 + int pidfd; 18 23 }; 19 24 20 25 FIXTURE_SETUP(set_layers_via_fds) 21 26 { 22 - ASSERT_EQ(mkdir("/set_layers_via_fds", 0755), 0); 23 - ASSERT_EQ(mkdir("/set_layers_via_fds_tmpfs", 0755), 0); 27 + self->pidfd = -EBADF; 28 + EXPECT_EQ(mkdir("/set_layers_via_fds", 0755), 0); 29 + EXPECT_EQ(mkdir("/set_layers_via_fds_tmpfs", 0755), 0); 24 30 } 25 31 26 32 FIXTURE_TEARDOWN(set_layers_via_fds) 27 33 { 34 + if (self->pidfd >= 0) { 35 + EXPECT_EQ(sys_pidfd_send_signal(self->pidfd, SIGKILL, NULL, 0), 0); 36 + EXPECT_EQ(close(self->pidfd), 0); 37 + } 28 38 umount2("/set_layers_via_fds", 0); 29 - ASSERT_EQ(rmdir("/set_layers_via_fds"), 0); 39 + EXPECT_EQ(rmdir("/set_layers_via_fds"), 0); 30 40 31 41 umount2("/set_layers_via_fds_tmpfs", 0); 32 - ASSERT_EQ(rmdir("/set_layers_via_fds_tmpfs"), 0); 42 + EXPECT_EQ(rmdir("/set_layers_via_fds_tmpfs"), 0); 33 43 } 34 44 35 45 TEST_F(set_layers_via_fds, set_layers_via_fds) ··· 224 214 225 215 fd_overlay = sys_fsmount(fd_context, 0, 0); 226 216 ASSERT_GE(fd_overlay, 0); 217 + ASSERT_EQ(close(fd_context), 0); 218 + ASSERT_EQ(close(fd_overlay), 0); 219 + } 220 + 221 + TEST_F(set_layers_via_fds, set_override_creds) 222 + { 223 + int fd_context, fd_tmpfs, fd_overlay; 224 + int layer_fds[] = { [0 ... 3] = -EBADF }; 225 + pid_t pid; 226 + int pidfd; 227 + 228 + ASSERT_EQ(unshare(CLONE_NEWNS), 0); 229 + ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0); 230 + 231 + fd_context = sys_fsopen("tmpfs", 0); 232 + ASSERT_GE(fd_context, 0); 233 + 234 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0); 235 + fd_tmpfs = sys_fsmount(fd_context, 0, 0); 236 + ASSERT_GE(fd_tmpfs, 0); 237 + ASSERT_EQ(close(fd_context), 0); 238 + 239 + ASSERT_EQ(mkdirat(fd_tmpfs, "w", 0755), 0); 240 + ASSERT_EQ(mkdirat(fd_tmpfs, "u", 0755), 0); 241 + ASSERT_EQ(mkdirat(fd_tmpfs, "l1", 0755), 0); 242 + ASSERT_EQ(mkdirat(fd_tmpfs, "l2", 0755), 0); 243 + 244 + layer_fds[0] = openat(fd_tmpfs, "w", O_DIRECTORY); 245 + ASSERT_GE(layer_fds[0], 0); 246 + 247 + layer_fds[1] = openat(fd_tmpfs, "u", O_DIRECTORY); 248 + ASSERT_GE(layer_fds[1], 0); 249 + 250 + layer_fds[2] = openat(fd_tmpfs, "l1", O_DIRECTORY); 251 + ASSERT_GE(layer_fds[2], 0); 252 + 253 + layer_fds[3] = openat(fd_tmpfs, "l2", O_DIRECTORY); 254 + ASSERT_GE(layer_fds[3], 0); 255 + 256 + ASSERT_EQ(sys_move_mount(fd_tmpfs, "", -EBADF, "/tmp", MOVE_MOUNT_F_EMPTY_PATH), 0); 257 + ASSERT_EQ(close(fd_tmpfs), 0); 258 + 259 + fd_context = sys_fsopen("overlay", 0); 260 + ASSERT_GE(fd_context, 0); 261 + 262 + ASSERT_NE(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir", NULL, layer_fds[2]), 0); 263 + 264 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "workdir", NULL, layer_fds[0]), 0); 265 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "upperdir", NULL, layer_fds[1]), 0); 266 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[2]), 0); 267 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[3]), 0); 268 + 269 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_STRING, "metacopy", "on", 0), 0); 270 + 271 + pid = create_child(&pidfd, 0); 272 + ASSERT_GE(pid, 0); 273 + if (pid == 0) { 274 + if (sys_fsconfig(fd_context, FSCONFIG_SET_FLAG, "override_creds", NULL, 0)) { 275 + TH_LOG("sys_fsconfig should have succeeded"); 276 + _exit(EXIT_FAILURE); 277 + } 278 + 279 + _exit(EXIT_SUCCESS); 280 + } 281 + ASSERT_GE(sys_waitid(P_PID, pid, NULL, WEXITED), 0); 282 + ASSERT_GE(close(pidfd), 0); 283 + 284 + pid = create_child(&pidfd, 0); 285 + ASSERT_GE(pid, 0); 286 + if (pid == 0) { 287 + if (sys_fsconfig(fd_context, FSCONFIG_SET_FLAG, "nooverride_creds", NULL, 0)) { 288 + TH_LOG("sys_fsconfig should have succeeded"); 289 + _exit(EXIT_FAILURE); 290 + } 291 + 292 + _exit(EXIT_SUCCESS); 293 + } 294 + ASSERT_GE(sys_waitid(P_PID, pid, NULL, WEXITED), 0); 295 + ASSERT_GE(close(pidfd), 0); 296 + 297 + pid = create_child(&pidfd, 0); 298 + ASSERT_GE(pid, 0); 299 + if (pid == 0) { 300 + if (sys_fsconfig(fd_context, FSCONFIG_SET_FLAG, "override_creds", NULL, 0)) { 301 + TH_LOG("sys_fsconfig should have succeeded"); 302 + _exit(EXIT_FAILURE); 303 + } 304 + 305 + _exit(EXIT_SUCCESS); 306 + } 307 + ASSERT_GE(sys_waitid(P_PID, pid, NULL, WEXITED), 0); 308 + ASSERT_GE(close(pidfd), 0); 309 + 310 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0); 311 + 312 + fd_overlay = sys_fsmount(fd_context, 0, 0); 313 + ASSERT_GE(fd_overlay, 0); 314 + 315 + ASSERT_EQ(sys_move_mount(fd_overlay, "", -EBADF, "/set_layers_via_fds", MOVE_MOUNT_F_EMPTY_PATH), 0); 316 + 317 + ASSERT_EQ(close(fd_context), 0); 318 + ASSERT_EQ(close(fd_overlay), 0); 319 + } 320 + 321 + TEST_F(set_layers_via_fds, set_override_creds_invalid) 322 + { 323 + int fd_context, fd_tmpfs, fd_overlay, ret; 324 + int layer_fds[] = { [0 ... 3] = -EBADF }; 325 + pid_t pid; 326 + int fd_userns1, fd_userns2; 327 + int ipc_sockets[2]; 328 + char c; 329 + const unsigned int predictable_fd_context_nr = 123; 330 + 331 + fd_userns1 = get_userns_fd(0, 0, 10000); 332 + ASSERT_GE(fd_userns1, 0); 333 + 334 + fd_userns2 = get_userns_fd(0, 1234, 10000); 335 + ASSERT_GE(fd_userns2, 0); 336 + 337 + ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets); 338 + ASSERT_GE(ret, 0); 339 + 340 + pid = create_child(&self->pidfd, 0); 341 + ASSERT_GE(pid, 0); 342 + if (pid == 0) { 343 + if (close(ipc_sockets[0])) { 344 + TH_LOG("close should have succeeded"); 345 + _exit(EXIT_FAILURE); 346 + } 347 + 348 + if (!switch_userns(fd_userns2, 0, 0, false)) { 349 + TH_LOG("switch_userns should have succeeded"); 350 + _exit(EXIT_FAILURE); 351 + } 352 + 353 + if (read_nointr(ipc_sockets[1], &c, 1) != 1) { 354 + TH_LOG("read_nointr should have succeeded"); 355 + _exit(EXIT_FAILURE); 356 + } 357 + 358 + if (close(ipc_sockets[1])) { 359 + TH_LOG("close should have succeeded"); 360 + _exit(EXIT_FAILURE); 361 + } 362 + 363 + if (!sys_fsconfig(predictable_fd_context_nr, FSCONFIG_SET_FLAG, "override_creds", NULL, 0)) { 364 + TH_LOG("sys_fsconfig should have failed"); 365 + _exit(EXIT_FAILURE); 366 + } 367 + 368 + _exit(EXIT_SUCCESS); 369 + } 370 + 371 + ASSERT_EQ(close(ipc_sockets[1]), 0); 372 + ASSERT_EQ(switch_userns(fd_userns1, 0, 0, false), true); 373 + ASSERT_EQ(unshare(CLONE_NEWNS), 0); 374 + ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0); 375 + 376 + fd_context = sys_fsopen("tmpfs", 0); 377 + ASSERT_GE(fd_context, 0); 378 + 379 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0); 380 + fd_tmpfs = sys_fsmount(fd_context, 0, 0); 381 + ASSERT_GE(fd_tmpfs, 0); 382 + ASSERT_EQ(close(fd_context), 0); 383 + 384 + ASSERT_EQ(mkdirat(fd_tmpfs, "w", 0755), 0); 385 + ASSERT_EQ(mkdirat(fd_tmpfs, "u", 0755), 0); 386 + ASSERT_EQ(mkdirat(fd_tmpfs, "l1", 0755), 0); 387 + ASSERT_EQ(mkdirat(fd_tmpfs, "l2", 0755), 0); 388 + 389 + layer_fds[0] = openat(fd_tmpfs, "w", O_DIRECTORY); 390 + ASSERT_GE(layer_fds[0], 0); 391 + 392 + layer_fds[1] = openat(fd_tmpfs, "u", O_DIRECTORY); 393 + ASSERT_GE(layer_fds[1], 0); 394 + 395 + layer_fds[2] = openat(fd_tmpfs, "l1", O_DIRECTORY); 396 + ASSERT_GE(layer_fds[2], 0); 397 + 398 + layer_fds[3] = openat(fd_tmpfs, "l2", O_DIRECTORY); 399 + ASSERT_GE(layer_fds[3], 0); 400 + 401 + ASSERT_EQ(sys_move_mount(fd_tmpfs, "", -EBADF, "/tmp", MOVE_MOUNT_F_EMPTY_PATH), 0); 402 + ASSERT_EQ(close(fd_tmpfs), 0); 403 + 404 + fd_context = sys_fsopen("overlay", 0); 405 + ASSERT_GE(fd_context, 0); 406 + ASSERT_EQ(dup3(fd_context, predictable_fd_context_nr, 0), predictable_fd_context_nr); 407 + ASSERT_EQ(close(fd_context), 0); 408 + fd_context = predictable_fd_context_nr; 409 + ASSERT_EQ(write_nointr(ipc_sockets[0], "1", 1), 1); 410 + ASSERT_EQ(close(ipc_sockets[0]), 0); 411 + 412 + ASSERT_EQ(wait_for_pid(pid), 0); 413 + ASSERT_EQ(close(self->pidfd), 0); 414 + self->pidfd = -EBADF; 415 + 416 + ASSERT_NE(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir", NULL, layer_fds[2]), 0); 417 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "workdir", NULL, layer_fds[0]), 0); 418 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "upperdir", NULL, layer_fds[1]), 0); 419 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[2]), 0); 420 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[3]), 0); 421 + 422 + for (int i = 0; i < ARRAY_SIZE(layer_fds); i++) 423 + ASSERT_EQ(close(layer_fds[i]), 0); 424 + 425 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FLAG, "userxattr", NULL, 0), 0); 426 + 427 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0); 428 + 429 + fd_overlay = sys_fsmount(fd_context, 0, 0); 430 + ASSERT_GE(fd_overlay, 0); 431 + 432 + ASSERT_EQ(sys_move_mount(fd_overlay, "", -EBADF, "/set_layers_via_fds", MOVE_MOUNT_F_EMPTY_PATH), 0); 433 + 434 + ASSERT_EQ(close(fd_context), 0); 435 + ASSERT_EQ(close(fd_overlay), 0); 436 + ASSERT_EQ(close(fd_userns1), 0); 437 + ASSERT_EQ(close(fd_userns2), 0); 438 + } 439 + 440 + TEST_F(set_layers_via_fds, set_override_creds_nomknod) 441 + { 442 + int fd_context, fd_tmpfs, fd_overlay; 443 + int layer_fds[] = { [0 ... 3] = -EBADF }; 444 + pid_t pid; 445 + int pidfd; 446 + 447 + ASSERT_EQ(unshare(CLONE_NEWNS), 0); 448 + ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0); 449 + 450 + fd_context = sys_fsopen("tmpfs", 0); 451 + ASSERT_GE(fd_context, 0); 452 + 453 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0); 454 + fd_tmpfs = sys_fsmount(fd_context, 0, 0); 455 + ASSERT_GE(fd_tmpfs, 0); 456 + ASSERT_EQ(close(fd_context), 0); 457 + 458 + ASSERT_EQ(mkdirat(fd_tmpfs, "w", 0755), 0); 459 + ASSERT_EQ(mkdirat(fd_tmpfs, "u", 0755), 0); 460 + ASSERT_EQ(mkdirat(fd_tmpfs, "l1", 0755), 0); 461 + ASSERT_EQ(mkdirat(fd_tmpfs, "l2", 0755), 0); 462 + 463 + layer_fds[0] = openat(fd_tmpfs, "w", O_DIRECTORY); 464 + ASSERT_GE(layer_fds[0], 0); 465 + 466 + layer_fds[1] = openat(fd_tmpfs, "u", O_DIRECTORY); 467 + ASSERT_GE(layer_fds[1], 0); 468 + 469 + layer_fds[2] = openat(fd_tmpfs, "l1", O_DIRECTORY); 470 + ASSERT_GE(layer_fds[2], 0); 471 + 472 + layer_fds[3] = openat(fd_tmpfs, "l2", O_DIRECTORY); 473 + ASSERT_GE(layer_fds[3], 0); 474 + 475 + ASSERT_EQ(sys_move_mount(fd_tmpfs, "", -EBADF, "/tmp", MOVE_MOUNT_F_EMPTY_PATH), 0); 476 + ASSERT_EQ(close(fd_tmpfs), 0); 477 + 478 + fd_context = sys_fsopen("overlay", 0); 479 + ASSERT_GE(fd_context, 0); 480 + 481 + ASSERT_NE(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir", NULL, layer_fds[2]), 0); 482 + 483 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "workdir", NULL, layer_fds[0]), 0); 484 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "upperdir", NULL, layer_fds[1]), 0); 485 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[2]), 0); 486 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[3]), 0); 487 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FLAG, "userxattr", NULL, 0), 0); 488 + 489 + pid = create_child(&pidfd, 0); 490 + ASSERT_GE(pid, 0); 491 + if (pid == 0) { 492 + if (!cap_down(CAP_MKNOD)) 493 + _exit(EXIT_FAILURE); 494 + 495 + if (!cap_down(CAP_SYS_ADMIN)) 496 + _exit(EXIT_FAILURE); 497 + 498 + if (sys_fsconfig(fd_context, FSCONFIG_SET_FLAG, "override_creds", NULL, 0)) 499 + _exit(EXIT_FAILURE); 500 + 501 + _exit(EXIT_SUCCESS); 502 + } 503 + ASSERT_EQ(sys_waitid(P_PID, pid, NULL, WEXITED), 0); 504 + ASSERT_GE(close(pidfd), 0); 505 + 506 + ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0); 507 + 508 + fd_overlay = sys_fsmount(fd_context, 0, 0); 509 + ASSERT_GE(fd_overlay, 0); 510 + 511 + ASSERT_EQ(sys_move_mount(fd_overlay, "", -EBADF, "/set_layers_via_fds", MOVE_MOUNT_F_EMPTY_PATH), 0); 512 + ASSERT_EQ(mknodat(fd_overlay, "dev-zero", S_IFCHR | 0644, makedev(1, 5)), -1); 513 + ASSERT_EQ(errno, EPERM); 514 + 227 515 ASSERT_EQ(close(fd_context), 0); 228 516 ASSERT_EQ(close(fd_overlay), 0); 229 517 }
+501
tools/testing/selftests/filesystems/utils.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #ifndef _GNU_SOURCE 3 + #define _GNU_SOURCE 4 + #endif 5 + #include <fcntl.h> 6 + #include <sys/types.h> 7 + #include <dirent.h> 8 + #include <grp.h> 9 + #include <linux/limits.h> 10 + #include <sched.h> 11 + #include <stdio.h> 12 + #include <stdlib.h> 13 + #include <sys/eventfd.h> 14 + #include <sys/fsuid.h> 15 + #include <sys/prctl.h> 16 + #include <sys/socket.h> 17 + #include <sys/stat.h> 18 + #include <sys/types.h> 19 + #include <sys/wait.h> 20 + #include <sys/xattr.h> 21 + 22 + #include "utils.h" 23 + 24 + #define MAX_USERNS_LEVEL 32 25 + 26 + #define syserror(format, ...) \ 27 + ({ \ 28 + fprintf(stderr, "%m - " format "\n", ##__VA_ARGS__); \ 29 + (-errno); \ 30 + }) 31 + 32 + #define syserror_set(__ret__, format, ...) \ 33 + ({ \ 34 + typeof(__ret__) __internal_ret__ = (__ret__); \ 35 + errno = labs(__ret__); \ 36 + fprintf(stderr, "%m - " format "\n", ##__VA_ARGS__); \ 37 + __internal_ret__; \ 38 + }) 39 + 40 + #define STRLITERALLEN(x) (sizeof(""x"") - 1) 41 + 42 + #define INTTYPE_TO_STRLEN(type) \ 43 + (2 + (sizeof(type) <= 1 \ 44 + ? 3 \ 45 + : sizeof(type) <= 2 \ 46 + ? 5 \ 47 + : sizeof(type) <= 4 \ 48 + ? 10 \ 49 + : sizeof(type) <= 8 ? 20 : sizeof(int[-2 * (sizeof(type) > 8)]))) 50 + 51 + #define list_for_each(__iterator, __list) \ 52 + for (__iterator = (__list)->next; __iterator != __list; __iterator = __iterator->next) 53 + 54 + typedef enum idmap_type_t { 55 + ID_TYPE_UID, 56 + ID_TYPE_GID 57 + } idmap_type_t; 58 + 59 + struct id_map { 60 + idmap_type_t map_type; 61 + __u32 nsid; 62 + __u32 hostid; 63 + __u32 range; 64 + }; 65 + 66 + struct list { 67 + void *elem; 68 + struct list *next; 69 + struct list *prev; 70 + }; 71 + 72 + struct userns_hierarchy { 73 + int fd_userns; 74 + int fd_event; 75 + unsigned int level; 76 + struct list id_map; 77 + }; 78 + 79 + static inline void list_init(struct list *list) 80 + { 81 + list->elem = NULL; 82 + list->next = list->prev = list; 83 + } 84 + 85 + static inline int list_empty(const struct list *list) 86 + { 87 + return list == list->next; 88 + } 89 + 90 + static inline void __list_add(struct list *new, struct list *prev, struct list *next) 91 + { 92 + next->prev = new; 93 + new->next = next; 94 + new->prev = prev; 95 + prev->next = new; 96 + } 97 + 98 + static inline void list_add_tail(struct list *head, struct list *list) 99 + { 100 + __list_add(list, head->prev, head); 101 + } 102 + 103 + static inline void list_del(struct list *list) 104 + { 105 + struct list *next, *prev; 106 + 107 + next = list->next; 108 + prev = list->prev; 109 + next->prev = prev; 110 + prev->next = next; 111 + } 112 + 113 + static ssize_t read_nointr(int fd, void *buf, size_t count) 114 + { 115 + ssize_t ret; 116 + 117 + do { 118 + ret = read(fd, buf, count); 119 + } while (ret < 0 && errno == EINTR); 120 + 121 + return ret; 122 + } 123 + 124 + static ssize_t write_nointr(int fd, const void *buf, size_t count) 125 + { 126 + ssize_t ret; 127 + 128 + do { 129 + ret = write(fd, buf, count); 130 + } while (ret < 0 && errno == EINTR); 131 + 132 + return ret; 133 + } 134 + 135 + #define __STACK_SIZE (8 * 1024 * 1024) 136 + static pid_t do_clone(int (*fn)(void *), void *arg, int flags) 137 + { 138 + void *stack; 139 + 140 + stack = malloc(__STACK_SIZE); 141 + if (!stack) 142 + return -ENOMEM; 143 + 144 + #ifdef __ia64__ 145 + return __clone2(fn, stack, __STACK_SIZE, flags | SIGCHLD, arg, NULL); 146 + #else 147 + return clone(fn, stack + __STACK_SIZE, flags | SIGCHLD, arg, NULL); 148 + #endif 149 + } 150 + 151 + static int get_userns_fd_cb(void *data) 152 + { 153 + for (;;) 154 + pause(); 155 + _exit(0); 156 + } 157 + 158 + static int wait_for_pid(pid_t pid) 159 + { 160 + int status, ret; 161 + 162 + again: 163 + ret = waitpid(pid, &status, 0); 164 + if (ret == -1) { 165 + if (errno == EINTR) 166 + goto again; 167 + 168 + return -1; 169 + } 170 + 171 + if (!WIFEXITED(status)) 172 + return -1; 173 + 174 + return WEXITSTATUS(status); 175 + } 176 + 177 + static int write_id_mapping(idmap_type_t map_type, pid_t pid, const char *buf, size_t buf_size) 178 + { 179 + int fd = -EBADF, setgroups_fd = -EBADF; 180 + int fret = -1; 181 + int ret; 182 + char path[STRLITERALLEN("/proc/") + INTTYPE_TO_STRLEN(pid_t) + 183 + STRLITERALLEN("/setgroups") + 1]; 184 + 185 + if (geteuid() != 0 && map_type == ID_TYPE_GID) { 186 + ret = snprintf(path, sizeof(path), "/proc/%d/setgroups", pid); 187 + if (ret < 0 || ret >= sizeof(path)) 188 + goto out; 189 + 190 + setgroups_fd = open(path, O_WRONLY | O_CLOEXEC); 191 + if (setgroups_fd < 0 && errno != ENOENT) { 192 + syserror("Failed to open \"%s\"", path); 193 + goto out; 194 + } 195 + 196 + if (setgroups_fd >= 0) { 197 + ret = write_nointr(setgroups_fd, "deny\n", STRLITERALLEN("deny\n")); 198 + if (ret != STRLITERALLEN("deny\n")) { 199 + syserror("Failed to write \"deny\" to \"/proc/%d/setgroups\"", pid); 200 + goto out; 201 + } 202 + } 203 + } 204 + 205 + ret = snprintf(path, sizeof(path), "/proc/%d/%cid_map", pid, map_type == ID_TYPE_UID ? 'u' : 'g'); 206 + if (ret < 0 || ret >= sizeof(path)) 207 + goto out; 208 + 209 + fd = open(path, O_WRONLY | O_CLOEXEC); 210 + if (fd < 0) { 211 + syserror("Failed to open \"%s\"", path); 212 + goto out; 213 + } 214 + 215 + ret = write_nointr(fd, buf, buf_size); 216 + if (ret != buf_size) { 217 + syserror("Failed to write %cid mapping to \"%s\"", 218 + map_type == ID_TYPE_UID ? 'u' : 'g', path); 219 + goto out; 220 + } 221 + 222 + fret = 0; 223 + out: 224 + close(fd); 225 + close(setgroups_fd); 226 + 227 + return fret; 228 + } 229 + 230 + static int map_ids_from_idmap(struct list *idmap, pid_t pid) 231 + { 232 + int fill, left; 233 + char mapbuf[4096] = {}; 234 + bool had_entry = false; 235 + idmap_type_t map_type, u_or_g; 236 + 237 + if (list_empty(idmap)) 238 + return 0; 239 + 240 + for (map_type = ID_TYPE_UID, u_or_g = 'u'; 241 + map_type <= ID_TYPE_GID; map_type++, u_or_g = 'g') { 242 + char *pos = mapbuf; 243 + int ret; 244 + struct list *iterator; 245 + 246 + 247 + list_for_each(iterator, idmap) { 248 + struct id_map *map = iterator->elem; 249 + if (map->map_type != map_type) 250 + continue; 251 + 252 + had_entry = true; 253 + 254 + left = 4096 - (pos - mapbuf); 255 + fill = snprintf(pos, left, "%u %u %u\n", map->nsid, map->hostid, map->range); 256 + /* 257 + * The kernel only takes <= 4k for writes to 258 + * /proc/<pid>/{g,u}id_map 259 + */ 260 + if (fill <= 0 || fill >= left) 261 + return syserror_set(-E2BIG, "Too many %cid mappings defined", u_or_g); 262 + 263 + pos += fill; 264 + } 265 + if (!had_entry) 266 + continue; 267 + 268 + ret = write_id_mapping(map_type, pid, mapbuf, pos - mapbuf); 269 + if (ret < 0) 270 + return syserror("Failed to write mapping: %s", mapbuf); 271 + 272 + memset(mapbuf, 0, sizeof(mapbuf)); 273 + } 274 + 275 + return 0; 276 + } 277 + 278 + static int get_userns_fd_from_idmap(struct list *idmap) 279 + { 280 + int ret; 281 + pid_t pid; 282 + char path_ns[STRLITERALLEN("/proc/") + INTTYPE_TO_STRLEN(pid_t) + 283 + STRLITERALLEN("/ns/user") + 1]; 284 + 285 + pid = do_clone(get_userns_fd_cb, NULL, CLONE_NEWUSER | CLONE_NEWNS); 286 + if (pid < 0) 287 + return -errno; 288 + 289 + ret = map_ids_from_idmap(idmap, pid); 290 + if (ret < 0) 291 + return ret; 292 + 293 + ret = snprintf(path_ns, sizeof(path_ns), "/proc/%d/ns/user", pid); 294 + if (ret < 0 || (size_t)ret >= sizeof(path_ns)) 295 + ret = -EIO; 296 + else 297 + ret = open(path_ns, O_RDONLY | O_CLOEXEC | O_NOCTTY); 298 + 299 + (void)kill(pid, SIGKILL); 300 + (void)wait_for_pid(pid); 301 + return ret; 302 + } 303 + 304 + int get_userns_fd(unsigned long nsid, unsigned long hostid, unsigned long range) 305 + { 306 + struct list head, uid_mapl, gid_mapl; 307 + struct id_map uid_map = { 308 + .map_type = ID_TYPE_UID, 309 + .nsid = nsid, 310 + .hostid = hostid, 311 + .range = range, 312 + }; 313 + struct id_map gid_map = { 314 + .map_type = ID_TYPE_GID, 315 + .nsid = nsid, 316 + .hostid = hostid, 317 + .range = range, 318 + }; 319 + 320 + list_init(&head); 321 + uid_mapl.elem = &uid_map; 322 + gid_mapl.elem = &gid_map; 323 + list_add_tail(&head, &uid_mapl); 324 + list_add_tail(&head, &gid_mapl); 325 + 326 + return get_userns_fd_from_idmap(&head); 327 + } 328 + 329 + bool switch_ids(uid_t uid, gid_t gid) 330 + { 331 + if (setgroups(0, NULL)) 332 + return syserror("failure: setgroups"); 333 + 334 + if (setresgid(gid, gid, gid)) 335 + return syserror("failure: setresgid"); 336 + 337 + if (setresuid(uid, uid, uid)) 338 + return syserror("failure: setresuid"); 339 + 340 + /* Ensure we can access proc files from processes we can ptrace. */ 341 + if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0)) 342 + return syserror("failure: make dumpable"); 343 + 344 + return true; 345 + } 346 + 347 + static int create_userns_hierarchy(struct userns_hierarchy *h); 348 + 349 + static int userns_fd_cb(void *data) 350 + { 351 + struct userns_hierarchy *h = data; 352 + char c; 353 + int ret; 354 + 355 + ret = read_nointr(h->fd_event, &c, 1); 356 + if (ret < 0) 357 + return syserror("failure: read from socketpair"); 358 + 359 + /* Only switch ids if someone actually wrote a mapping for us. */ 360 + if (c == '1') { 361 + if (!switch_ids(0, 0)) 362 + return syserror("failure: switch ids to 0"); 363 + } 364 + 365 + ret = write_nointr(h->fd_event, "1", 1); 366 + if (ret < 0) 367 + return syserror("failure: write to socketpair"); 368 + 369 + ret = create_userns_hierarchy(++h); 370 + if (ret < 0) 371 + return syserror("failure: userns level %d", h->level); 372 + 373 + return 0; 374 + } 375 + 376 + static int create_userns_hierarchy(struct userns_hierarchy *h) 377 + { 378 + int fret = -1; 379 + char c; 380 + int fd_socket[2]; 381 + int fd_userns = -EBADF, ret = -1; 382 + ssize_t bytes; 383 + pid_t pid; 384 + char path[256]; 385 + 386 + if (h->level == MAX_USERNS_LEVEL) 387 + return 0; 388 + 389 + ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, fd_socket); 390 + if (ret < 0) 391 + return syserror("failure: create socketpair"); 392 + 393 + /* Note the CLONE_FILES | CLONE_VM when mucking with fds and memory. */ 394 + h->fd_event = fd_socket[1]; 395 + pid = do_clone(userns_fd_cb, h, CLONE_NEWUSER | CLONE_FILES | CLONE_VM); 396 + if (pid < 0) { 397 + syserror("failure: userns level %d", h->level); 398 + goto out_close; 399 + } 400 + 401 + ret = map_ids_from_idmap(&h->id_map, pid); 402 + if (ret < 0) { 403 + kill(pid, SIGKILL); 404 + syserror("failure: writing id mapping for userns level %d for %d", h->level, pid); 405 + goto out_wait; 406 + } 407 + 408 + if (!list_empty(&h->id_map)) 409 + bytes = write_nointr(fd_socket[0], "1", 1); /* Inform the child we wrote a mapping. */ 410 + else 411 + bytes = write_nointr(fd_socket[0], "0", 1); /* Inform the child we didn't write a mapping. */ 412 + if (bytes < 0) { 413 + kill(pid, SIGKILL); 414 + syserror("failure: write to socketpair"); 415 + goto out_wait; 416 + } 417 + 418 + /* Wait for child to set*id() and become dumpable. */ 419 + bytes = read_nointr(fd_socket[0], &c, 1); 420 + if (bytes < 0) { 421 + kill(pid, SIGKILL); 422 + syserror("failure: read from socketpair"); 423 + goto out_wait; 424 + } 425 + 426 + snprintf(path, sizeof(path), "/proc/%d/ns/user", pid); 427 + fd_userns = open(path, O_RDONLY | O_CLOEXEC); 428 + if (fd_userns < 0) { 429 + kill(pid, SIGKILL); 430 + syserror("failure: open userns level %d for %d", h->level, pid); 431 + goto out_wait; 432 + } 433 + 434 + fret = 0; 435 + 436 + out_wait: 437 + if (!wait_for_pid(pid) && !fret) { 438 + h->fd_userns = fd_userns; 439 + fd_userns = -EBADF; 440 + } 441 + 442 + out_close: 443 + if (fd_userns >= 0) 444 + close(fd_userns); 445 + close(fd_socket[0]); 446 + close(fd_socket[1]); 447 + return fret; 448 + } 449 + 450 + /* caps_down - lower all effective caps */ 451 + int caps_down(void) 452 + { 453 + bool fret = false; 454 + cap_t caps = NULL; 455 + int ret = -1; 456 + 457 + caps = cap_get_proc(); 458 + if (!caps) 459 + goto out; 460 + 461 + ret = cap_clear_flag(caps, CAP_EFFECTIVE); 462 + if (ret) 463 + goto out; 464 + 465 + ret = cap_set_proc(caps); 466 + if (ret) 467 + goto out; 468 + 469 + fret = true; 470 + 471 + out: 472 + cap_free(caps); 473 + return fret; 474 + } 475 + 476 + /* cap_down - lower an effective cap */ 477 + int cap_down(cap_value_t down) 478 + { 479 + bool fret = false; 480 + cap_t caps = NULL; 481 + cap_value_t cap = down; 482 + int ret = -1; 483 + 484 + caps = cap_get_proc(); 485 + if (!caps) 486 + goto out; 487 + 488 + ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, 0); 489 + if (ret) 490 + goto out; 491 + 492 + ret = cap_set_proc(caps); 493 + if (ret) 494 + goto out; 495 + 496 + fret = true; 497 + 498 + out: 499 + cap_free(caps); 500 + return fret; 501 + }
+45
tools/testing/selftests/filesystems/utils.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __IDMAP_UTILS_H 4 + #define __IDMAP_UTILS_H 5 + 6 + #ifndef _GNU_SOURCE 7 + #define _GNU_SOURCE 8 + #endif 9 + #include <errno.h> 10 + #include <linux/types.h> 11 + #include <sched.h> 12 + #include <signal.h> 13 + #include <stdbool.h> 14 + #include <stdio.h> 15 + #include <stdlib.h> 16 + #include <string.h> 17 + #include <syscall.h> 18 + #include <sys/capability.h> 19 + #include <sys/fsuid.h> 20 + #include <sys/types.h> 21 + #include <unistd.h> 22 + 23 + extern int get_userns_fd(unsigned long nsid, unsigned long hostid, 24 + unsigned long range); 25 + 26 + extern int caps_down(void); 27 + extern int cap_down(cap_value_t down); 28 + 29 + extern bool switch_ids(uid_t uid, gid_t gid); 30 + 31 + static inline bool switch_userns(int fd, uid_t uid, gid_t gid, bool drop_caps) 32 + { 33 + if (setns(fd, CLONE_NEWUSER)) 34 + return false; 35 + 36 + if (!switch_ids(uid, gid)) 37 + return false; 38 + 39 + if (drop_caps && !caps_down()) 40 + return false; 41 + 42 + return true; 43 + } 44 + 45 + #endif /* __IDMAP_UTILS_H */