On 25.04.20 10:39, Laurent Vivier wrote:
> Le 24/04/2020 à 23:04, Helge Deller a écrit :
>> The signalfd4() syscall takes optional O_NONBLOCK and O_CLOEXEC fcntl
>> flags.  If the user gave any other invalid flags, the host syscall will
>> return correct error codes, so simply drop the extra check here.
>>
>> Signed-off-by: Helge Deller <del...@gmx.de>
>>
>> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
>> index 05f03919ff..ebf0d38321 100644
>> --- a/linux-user/syscall.c
>> +++ b/linux-user/syscall.c
>> @@ -7176,9 +7176,6 @@ static abi_long do_signalfd4(int fd, abi_long mask, 
>> int flags)
>>      sigset_t host_mask;
>>      abi_long ret;
>>
>> -    if (flags & ~(TARGET_O_NONBLOCK | TARGET_O_CLOEXEC)) {
>> -        return -TARGET_EINVAL;
>> -    }
>>      if (!lock_user_struct(VERIFY_READ, target_mask, mask, 1)) {
>>          return -TARGET_EFAULT;
>>      }
>>
>
> Perhaps we want to trigger the TARGET_EINVAL before the TARGET_EFAULT if
> we have both cases?
>
> But I've checked the kernel, and the kernel does a copy_from_user()
> before checking the flags, but it returns EINVAL rather than EFAULT.

That's not the full picture, since the kernel is not consistent here!
In the compat-case (32bit userspace on 64bit kernel) it returns correctly
EINVAL and EFAULT:
        if (sigsetsize != sizeof(compat_sigset_t))
                return -EINVAL;
        if (get_compat_sigset(&mask, user_mask))
                return -EFAULT;
while in the non-compat case it returns EINVAL only:
        if (sizemask != sizeof(sigset_t) ||
            copy_from_user(&mask, user_mask, sizeof(mask)))
                return -EINVAL;

I think the kernel should be fixed here...

> We can remove the flags checking but we should also change TARGET_EFAULT
> by TARGET_EINVAL.

According to the different behaviour of the kernel mentioned above
you won't get it correct either way.

Helge

Reply via email to