Why runc seccomp filtering for the chmod syscall does not work on aarch64?
TLDR, because the chmod
syscall does not exist for aarch64, and you should use fchmodat
.
When using libseccomp with runc, there's no easy way to detect that the specified syscall does not exist for a given arch.
On x86_64:
000000000043c340 <__chmod>:
59927 43c340:»··b8 5a 00 00 00 »··mov $0x5a,%eax
59928 43c345:»··0f 05 »··syscall
59929 43c347:»··48 3d 01 f0 ff ff »··cmp $0xfffffffffffff001,%rax
Syscall number is 0x5a
On aarch64:
0x000000000041672c <__chmod+8>: 60 0c 80 92 mov x0, #0xffffffffffffff9c // #-100
0x0000000000416730 <__chmod+12>: e1 03 03 aa mov x1, x3
0x0000000000416734 <__chmod+16>: e2 03 02 2a mov w2, w2
=> 0x0000000000416738 <__chmod+20>: a8 06 80 d2 mov x8, #0x35 // #53
0x000000000041673c <__chmod+24>: 01 00 00 d4 svc #0x0
0x0000000000416740 <__chmod+28>: 1f 04 40 b1 cmn x0, #0x1, lsl #12
0x0000000000416744 <__chmod+32>: 48 00 00 54 b.hi 0x41674c <__chmod+40> // b.pmore
Syscall number is 0x35
.
Does that match what's defined in libseccomp?
For x86, src/arch-x86_64-syscalls.c
:
const struct arch_syscall_def x86_64_syscall_table[] = { \
/* CUT */
{ "chmod", 90 },
It matches!
For arm, src/arch-aarch64-syscalls.c
:
const struct arch_syscall_def aarch64_syscall_table[] = { \
/* CUT */
{ "chmod", __PNR_chmod },
/* CUT */
{ "fchmodat", 53 },
Gulp, there's a PNR...
But, the syscall number of fchmodat
matches what we found in the disassembled code :-)
What's PNR? Checking in the code documentation...
RETURN VALUE top
In the case of seccomp_syscall_resolve_name(),
seccomp_syscall_resolve_name_arch(), and
seccomp_syscall_resolve_name_rewrite() the associated syscall number
is returned, with the negative pseudo syscall number being returned
in cases where the given syscall does not exist for the architecture.
So, basically PNR is a negative pseudo syscall number when the syscall does not exist for the specified architecture...