[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#618562: syscall in libc6 is broken for __NR_fanotify_mark



On Wed, Mar 16, 2011 at 12:36:30PM +0000, Chen Jie wrote:
> Package: libc6
> Version: 2.11.2-10
> 
> syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname),
> failed with 'Invalid argument'.
> strace shows 'syscall' didn't pass the correct parameters:
>     syscall(0x10f1, 0x3, 0x11, 0, 0x20, 0, 0xffffff9c, 0x4013e0)
>     ( The expected one is: syscall(0x10f1, 0x3, 0x17, 0x20, 0, -100, 0x4013e0) )

So let me summarize the difference between the real and expected values:
- arg1: 0x10f1 in both cases, no problem
- arg2: 0x3 in both cases, no problem
- arg3: 0x11 in the syscall, 0x17 expected. The problem is actually the
  test program which uses %d to display an hexadecimal number 0x11 = 17.
  No problem on the glibc side here.
- arg4: 0 in the syscall, not expected, will explain below why.
- arg5 (syscall) / arg4 (expected): 0x20 in both cases, no problem
- arg6 (syscall) / arg5 (expected): 0 in both cases, no problem
- arg7 (syscall) / arg6 (expected) 0xffffff9c in the syscall, -100 
  expected. This is actually the same value.
- arg8 (syscall) / arg7 (expected): 0x4013e0 in both cases, no problem.

So the only non-explained problem is the 4th argument as displayed by
strace. The syscall() function takes a variable number of arguments, and
pass them to the __NR_syscall syscall (4000), which is the indirect
syscall, as shown in the code below:

   eecd0:       3c1c0009        lui     gp,0x9
   eecd4:       279c5c90        addiu   gp,gp,23696
   eecd8:       0399e021        addu    gp,gp,t9
   eecdc:       24020fa0        li      v0,4000
   eece0:       0000000c        syscall
   eece4:       14e0fff6        bnez    a3,eecc0 <syslog+0x54>
   eece8:       00200825        move    at,at
   eecec:       03e00008        jr      ra
   eecf0:       00200825        move    at,at

syscall() follows the MIPS ABI, which means a 64-bit argument has to be
64-bit aligned. That's why the arguments are organized as below:
- a0:    0x000010f1
- a1:    0x00000003
- a2:    0x00000011
- a3:    not used (due to 64-bit alignement)
- sp+16: 0x00000020
- sp+20: 0x00000000
- sp+24: 0xffffff9c
- sp+28: 0x004013e0

On the kernel side, the arguments are simply shifted by one (to remove 
the syscall number), without taking into account the ABI and the real
syscall called. That's why there is an additional argument to the 
syscall.

Now I don't think there is any way to fix it on the libc6 side.
syscall() doesn't know what are the type of the passed arguments, and is
following the MIPS ABI. It might be fixed on the kernel side, but it
means having a table with the type of all arguments. It doesn't seems to
be easy to do.

That said, there is an easy workaround by passing only 32-bit values to
the syscall() function on a 32-bit machine.

-- 
Aurelien Jarno	                        GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net



Reply to: