@samitouri / QOSamiQemu / commits / 767c32fe69

linux-user: implement fsmount(2) series of syscalls

This series of syscalls replaces the old mount(2) syscall with a series of syscalls that operates around a filesystem context. This series of syscalls is available since Linux 5.2 and glibc 2.36+. Their users include systemd since v259 and libmount from util-linux, and possibly other widely used projects. Preliminary checks are implemented to ensure the validity of the interface. v2: Add syscall wrappers in case the build machine does not support the fsmount() syscalls. (added by Helge Deller) Signed-off-by: Xinhui Yang <cyan@cyano.uk> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@oss.qualcomm.com> Signed-off-by: Helge Deller <deller@gmx.de>

Xinhui Yang committed May 29, 2026 at 14:53 UTC 767c32fe69834344bf71f4071ff33292cd46f626
1 file changed +104
linux-user/syscall.c
+104
@@ -9713,6 +9713,19 @@ _syscall5(int, sys_move_mount, int, __from_dfd, const char *, __from_pathname,
9713 int, __to_dfd, const char *, __to_pathname, unsigned int, flag)
9714 #endif
9715
9716 +#if defined(TARGET_NR_fsopen) && defined(NR_fsopen)
9717 +#define __NR_sys_fsopen __NR_fsopen
9718 +_syscall2(int, sys_fsopen, const char *, fs_name, unsigned int, flags);
9719 +#define __NR_sys_fsconfig __NR_fsconfig
9720 +_syscall5(int, sys_fsconfig, int, fs_fd, unsigned int, cmd, const char *, key,
9721 + const void *, value, int, aux)
9722 +#define __NR_sys_fsmount __NR_fsmount
9723 +_syscall3(int, sys_fsmount, int, fs_fd, unsigned int, flags,
9724 + unsigned int, ms_flags)
9725 +#define __NR_sys_fspick __NR_fspick
9726 +_syscall3(int, sys_fspick, int, dfd, const char *, path, unsigned int, flags)
9727 +#endif
9728 +
9729 /* This is an internal helper for do_syscall so that it is easier
9730 * to have a single return point, so that actions, such as logging
9731 * of syscall results, can be performed.
@@ -14412,6 +14425,97 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
14425 return do_map_shadow_stack(cpu_env, arg1, arg2, arg3);
14426 #endif
14427
14428 +#if defined(TARGET_NR_fsopen) && defined(NR_fsopen)
14429 + case TARGET_NR_fsopen:
14430 + {
14431 + p = lock_user_string(arg1);
14432 + if (!p) {
14433 + return -TARGET_EFAULT;
14434 + }
14435 + ret = get_errno(sys_fsopen(p, arg2));
14436 + unlock_user(p, arg1, 0);
14437 + }
14438 + return ret;
14439 + case TARGET_NR_fsconfig:
14440 + {
14441 + /*
14442 + * fsconfig(int, int, char *, void *, int)
14443 + * NOTE: p4 is nullable and its type might not be a string.
14444 + */
14445 + void *p3, *p4;
14446 + int cmd = (int) arg2;
14447 + switch (cmd) {
14448 + case FSCONFIG_SET_BINARY:
14449 + case FSCONFIG_SET_STRING:
14450 + case FSCONFIG_SET_PATH:
14451 + case FSCONFIG_SET_PATH_EMPTY:
14452 + p3 = lock_user_string(arg3);
14453 + if (!p3) {
14454 + return -TARGET_EFAULT;
14455 + }
14456 + if (cmd != FSCONFIG_SET_BINARY) {
14457 + /* key and value must be strings. */
14458 + p4 = lock_user_string(arg4);
14459 + } else {
14460 + /*
14461 + * Otherwise the value must be a raw buffer with its
14462 + * length specified in arg5 (aux).
14463 + */
14464 + p4 = lock_user(VERIFY_READ, arg4, arg5, 1);
14465 + }
14466 + if (!p4) {
14467 + unlock_user(p3, arg3, 0);
14468 + return -TARGET_EFAULT;
14469 + }
14470 + ret = get_errno(sys_fsconfig(arg1, arg2, p3, p4, arg5));
14471 + unlock_user(p3, arg3, 0);
14472 + unlock_user(p4, arg4, 0);
14473 + break;
14474 +
14475 + case FSCONFIG_SET_FLAG:
14476 + case FSCONFIG_SET_FD:
14477 + /* arg4 (value) must be NULL. */
14478 + if (arg4) {
14479 + return -TARGET_EFAULT;
14480 + }
14481 + p3 = lock_user_string(arg3);
14482 + if (!p3) {
14483 + return -TARGET_EFAULT;
14484 + }
14485 + ret = get_errno(sys_fsconfig(arg1, arg2, p3, NULL, arg5));
14486 + unlock_user(p3, arg3, 0);
14487 + break;
14488 + case FSCONFIG_CMD_CREATE:
14489 + case FSCONFIG_CMD_RECONFIGURE:
14490 +#ifdef FSCONFIG_CMD_CREATE_EXCL
14491 + /*
14492 + * FSCONFIG_CMD_CREATE_EXCL is only available since Linux
14493 + * 6.6. Guarding it to allow building with pre-6.6 headers.
14494 + */
14495 + case FSCONFIG_CMD_CREATE_EXCL:
14496 +#endif
14497 + /* key and value must be NULL, aux must be 0. */
14498 + if (arg3 || arg4 || arg5) {
14499 + return -TARGET_EFAULT;
14500 + }
14501 + ret = get_errno(sys_fsconfig(arg1, arg2, NULL, NULL, 0));
14502 + break;
14503 + default:
14504 + return -TARGET_EFAULT;
14505 + }
14506 + }
14507 + return ret;
14508 + case TARGET_NR_fsmount:
14509 + ret = get_errno(sys_fsmount(arg1, arg2, arg3));
14510 + return ret;
14511 + case TARGET_NR_fspick:
14512 + {
14513 + p = lock_user_string(arg2);
14514 + ret = get_errno(sys_fspick(arg1, p, arg3));
14515 + unlock_user(p, arg2, 0);
14516 + }
14517 + return ret;
14518 +#endif
14519 default:
14520 qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
14521 return -TARGET_ENOSYS;