[systemd-devel] [PATCH] Fix broken syscall(__NR_fanotify_mark... on 32bit mips.

fykcee1 at gmail.com fykcee1 at gmail.com
Tue Apr 19 19:06:34 PDT 2011


2011/4/20 Lennart Poettering <lennart at poettering.net>:
> On Wed, 20.04.11 09:15, fykcee1 at gmail.com (fykcee1 at gmail.com) wrote:
>
>>
>> 2011/4/20 Lennart Poettering <lennart at poettering.net>
>> >
>> > On Thu, 14.04.11 17:34, fykcee1 at gmail.com (fykcee1 at gmail.com) wrote:
>> >
>> > > diff --git a/src/missing.h b/src/missing.h
>> > > index 35e209f..b367831 100644
>> > > --- a/src/missing.h
>> > > +++ b/src/missing.h
>> > > @@ -125,7 +125,12 @@ static inline int fanotify_init(unsigned int flags, unsigned int event_f_flags)
>> > >
>> > >  static inline int fanotify_mark(int fanotify_fd, unsigned int flags, uint64_t mask,
>> > >                                  int dfd, const char *pathname) {
>> > > -        return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname);
>> > > +        if (sizeof(void *) == 4)
>> > > +                return syscall(__NR_fanotify_mark, fanotify_fd, flags,
>> > > +                               *((uint32_t *) &mask), *((uint32_t *) &mask + 1),
>> > > +                               dfd, pathname);
>> > > +        else /* 64bit */
>> > > +                return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname);
>> > >  }
>> > >
>> > >  #ifndef BTRFS_IOCTL_MAGIC
>> >
>> > Hmm, wouldn't this break x86-32?
>> It works fine on my asus laptop with a 32bit CPU Pentium-M.
>>
>> We pass two 32bit arguments instead of one 64bit argument. syscall()
>> doesn't know the prototype, I guess it will only fetch 9 native-width
>> arguments(1 syscall number + 8 parameters) from the stack.
Think it again, I find the above description isn't correct. I guess
the syscall() works like following:
1. syscall() do indirect system call.
2. kernel system call entry handler fetch 8 arguments from some
registers + user stack.

Note, the same system call can have 32bit and 64bit varieties. kernel
will fetch arguments properly. e.g. all <32bit arguments are promoted
to 32bit arguments, according to some arch ABI, kernel system call
entry handler of 32bit variety fetches 8 32bit arguments, and then
dispatches it to specific system call handler.

In this example, in case of 64bit mips kernel + 32bit userland(o32 ABI):
1. syscall(__NR_fanotify_mark, fanotify_fd, flags, mask_low,
mask_high, dfd, pathname)
2. kernel fetches 4 32bit arguments from register a0-a3, and 4 32bit
arguments from user stack. see
http://lxr.linux.no/linux+v2.6.38/arch/mips/kernel/scall64-o32.S.
3. Process indirect syscall (sys32_syscall), just do a shift, redirect
to sys_32_fanotify_mark.
4. In sys_32_fanotify_mark, it merge_64(mask_low, merge_high), and
calls sys_fanotify_mark. see
http://lxr.linux.no/linux+v2.6.38/arch/mips/kernel/linux32.c#L346

>
> Hmm, I am not sure I understand this? How is it possible that both ways
> work on x86? There must be quite a difference between passing 6 or 7
> arguments to syscall.
>
> Or are you suggesting that the current invocation is broken even on x86,
> just doesn't become visible since only the lower 32 bit of "mask" are
> used?
>
>> > Also, I'd very much prefer if this could be done with compile time
>> > checks instead of "if". i.e.
>> >
>> > #ifdef __mips__
>> Actually it's not only related to mips, but also to all arch that
>> force 64-aligned for 64bit argument (Aurelien said this can also be
>> reproduced on powerpc and arm). So what I want is:
>> #if PTR_BYTES == 4
>> ....
>>
>> I tried to find some macro like PTR_BYTES or PTR_SIZE, but failed. Is
>> such macro available?
>
> I think "#ifndef __LP64__" does what you want?
Got it, thanks.



-- 
Regards,
- cee1


More information about the systemd-devel mailing list