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
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