On 5/27/2026 3:11 AM, Xinhui Yang wrote:
> 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.
>
> Signed-off-by: Xinhui Yang <[email protected]>
> ---
> linux-user/syscall.c | 81 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 81 insertions(+)
>
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 7d7a7b489c..2ff80f4dfa 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -14412,6 +14412,87 @@ 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)
> + case TARGET_NR_fsopen:
> + {
> + p = lock_user_string(arg1);
> + if (!p) {
> + return -TARGET_EFAULT;
> + }
> + ret = get_errno(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 (cmd != FSCONFIG_SET_BINARY) {
> + /* key and value must be strings. */
> + p4 = lock_user_string(arg4);
> + } else {
> + /* Otherise the value must be a raw buffer. */
> + p4 = lock_user(VERIFY_READ, arg4, arg5, 1);
> + }
> + if (!p3 || !p4) {
> + return -TARGET_EFAULT;
> + }
Might leave with locked p3 is p4 fails.
You can add another early return just after p3 and unlock p3 in this if.
> + ret = get_errno(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:
> + /* value must be NULL. */
> + p3 = lock_user_string(arg3);
> + if (!p3 || arg4) {
> + return -TARGET_EFAULT;
> + }
> + ret = get_errno(fsconfig(arg1, arg2, p3, NULL, arg5));
Similar to above (if arg4) { unlock... }
> + 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(fsconfig(arg1, arg2, NULL, NULL, 0));
> + break;
> + default:
> + return -TARGET_EFAULT;
> + }
> + }
> + return ret;
> + case TARGET_NR_fsmount:
> + ret = get_errno(fsmount(arg1, arg2, arg3));
> + return ret;
> + case TARGET_NR_fspick:
> + {
> + p = lock_user_string(arg2);
> + ret = get_errno(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;