From: Xinhui Yang <[email protected]> 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 <[email protected]> Reviewed-by: Pierrick Bouvier <[email protected]> Signed-off-by: Helge Deller <[email protected]> --- linux-user/syscall.c | 104 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 7d7a7b489c..37ede95510 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9713,6 +9713,19 @@ _syscall5(int, sys_move_mount, int, __from_dfd, const char *, __from_pathname, int, __to_dfd, const char *, __to_pathname, unsigned int, flag) #endif +#if defined(TARGET_NR_fsopen) && defined(NR_fsopen) +#define __NR_sys_fsopen __NR_fsopen +_syscall2(int, sys_fsopen, const char *, fs_name, unsigned int, flags); +#define __NR_sys_fsconfig __NR_fsconfig +_syscall5(int, sys_fsconfig, int, fs_fd, unsigned int, cmd, const char *, key, + const void *, value, int, aux) +#define __NR_sys_fsmount __NR_fsmount +_syscall3(int, sys_fsmount, int, fs_fd, unsigned int, flags, + unsigned int, ms_flags) +#define __NR_sys_fspick __NR_fspick +_syscall3(int, sys_fspick, int, dfd, const char *, path, unsigned int, flags) +#endif + /* This is an internal helper for do_syscall so that it is easier * to have a single return point, so that actions, such as logging * of syscall results, can be performed. @@ -14412,6 +14425,97 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, return do_map_shadow_stack(cpu_env, arg1, arg2, arg3); #endif +#if defined(TARGET_NR_fsopen) && defined(NR_fsopen) + case TARGET_NR_fsopen: + { + p = lock_user_string(arg1); + if (!p) { + return -TARGET_EFAULT; + } + ret = get_errno(sys_fsopen(p, arg2)); + unlock_user(p, arg1, 0); + } + return ret; + case TARGET_NR_fsconfig: + { + /* + * fsconfig(int, int, char *, void *, int) + * NOTE: p4 is nullable and its type might not be a string. + */ + void *p3, *p4; + int cmd = (int) arg2; + switch (cmd) { + case FSCONFIG_SET_BINARY: + case FSCONFIG_SET_STRING: + case FSCONFIG_SET_PATH: + case FSCONFIG_SET_PATH_EMPTY: + p3 = lock_user_string(arg3); + if (!p3) { + return -TARGET_EFAULT; + } + if (cmd != FSCONFIG_SET_BINARY) { + /* key and value must be strings. */ + p4 = lock_user_string(arg4); + } else { + /* + * Otherwise the value must be a raw buffer with its + * length specified in arg5 (aux). + */ + p4 = lock_user(VERIFY_READ, arg4, arg5, 1); + } + if (!p4) { + unlock_user(p3, arg3, 0); + return -TARGET_EFAULT; + } + ret = get_errno(sys_fsconfig(arg1, arg2, p3, p4, arg5)); + unlock_user(p3, arg3, 0); + unlock_user(p4, arg4, 0); + break; + + case FSCONFIG_SET_FLAG: + case FSCONFIG_SET_FD: + /* arg4 (value) must be NULL. */ + if (arg4) { + return -TARGET_EFAULT; + } + p3 = lock_user_string(arg3); + if (!p3) { + return -TARGET_EFAULT; + } + ret = get_errno(sys_fsconfig(arg1, arg2, p3, NULL, arg5)); + unlock_user(p3, arg3, 0); + break; + case FSCONFIG_CMD_CREATE: + case FSCONFIG_CMD_RECONFIGURE: +#ifdef FSCONFIG_CMD_CREATE_EXCL + /* + * FSCONFIG_CMD_CREATE_EXCL is only available since Linux + * 6.6. Guarding it to allow building with pre-6.6 headers. + */ + case FSCONFIG_CMD_CREATE_EXCL: +#endif + /* key and value must be NULL, aux must be 0. */ + if (arg3 || arg4 || arg5) { + return -TARGET_EFAULT; + } + ret = get_errno(sys_fsconfig(arg1, arg2, NULL, NULL, 0)); + break; + default: + return -TARGET_EFAULT; + } + } + return ret; + case TARGET_NR_fsmount: + ret = get_errno(sys_fsmount(arg1, arg2, arg3)); + return ret; + case TARGET_NR_fspick: + { + p = lock_user_string(arg2); + ret = get_errno(sys_fspick(arg1, p, arg3)); + unlock_user(p, arg2, 0); + } + return ret; +#endif default: qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num); return -TARGET_ENOSYS; -- 2.54.0
