linux-kernelarm64archlinux-arm

why is the open() syscall supported on some Linux systems and not others?


I am inlining syscalls. Yes, I understand this is problematic but I have a good reason. I've tracked down my bug considerably and I'm just asking why has __NR_open disappeared on this arm64 Arch Linux system?

5.0.1-1-ARCH #1 SMP Sun Mar 10 15:08:34 MDT 2019 aarch64 GNU/Linux

Again, my code is inlining syscalls. This inlining approach works on another X86_64 system and indeed inlining mmap() works on this system. However, inlining open() on this arm64 Arch Linux failed with EFAULT.

Tracking down my bug, first, __NR_open is NOT even defined in this build environment. Second, regular open() calls open64() which executes an svc instruction with x8 set to #56, __NR_openat. Third, __NR_open is normally defined as 5 and that number has been repurposed to __NR_setxattr. This explains the EFAULT.

Basically, open() gets converted into openat() in a user library on this system and the __NR_open syscall has completely disappeared, taken over by a new syscall. What I don't understand is that __NR_open is defined in the canonical source for arm64 but just not on this Arch Linux arm64 system.

My bug fix is simple: inline openat() instead. But my question is why was this deleted and why is this not considered broken from a Linux POV? I'm thinking of Linus saying WE DO NOT BREAK USERSPACE! and I'm not thinking about this from a POSIX POV. Indeed The Linux Programming Interface doesn't cover this deletion at least not explicitly.


Solution

  • The file you are looking at, arch/arm64/include/asm/unistd32.h, is the system call definitions for the arm32 compat mode.

    The system call definitions for native aarch64 are from the generic system call table include/uapi/asm-generic/unistd.h, which you can see does not define __NR_open. The system call was not deleted - it never existed on aarch64.

    The reason that __NR_open is not defined in the generic table is that the openat(2) system call was introduced later and is a strict superset of the _NR_open functionality, so there is no point in new architecture ports (created after openat(2) was introduced) supplying that system call - it is redundant. The POSIX open() function is supplied by the userspace C library, calling into the openat(2) system call.

    Old architecture ports that existed prior to openat(2) - like x86, and arm32 - must continue to include open(2), because old programs/library binaries certainly exist for those architectures that call the open(2) system call. This concern does not apply to a new architecture port - the "breaking userspace" guarantee is that if it worked yesterday it will work today, but it does not say that if it worked on an existing architecture it can be recompiled and work on some new architecture.