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;


Reply via email to