unix: add openat2 for linux openat2 is a new syscall added to Linux 5.6. It provides a superset of openat(2) functionality, providing a way to extend it in the future, and (for now) adding flags telling the kernel how to resolve the path. For more info on openat2, see https://lwn.net/Articles/803237/ A primitive test case is added to check that Openat2 works as it should. Tested to skip on kernel 5.5 and pass on 5.6. Change-Id: Ib8bbd71791762f043200543cecdea16d2fd3c81d Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com> Reviewed-on: https://go-review.googlesource.com/c/sys/+/227280 Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
diff --git a/unix/linux/types.go b/unix/linux/types.go index 1e90b2e..10f1ea4 100644 --- a/unix/linux/types.go +++ b/unix/linux/types.go
@@ -106,6 +106,7 @@ #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter.h> #include <linux/netlink.h> +#include <linux/openat2.h> #include <linux/perf_event.h> #include <linux/random.h> #include <linux/rtc.h> @@ -833,6 +834,18 @@ AT_EACCESS = C.AT_EACCESS ) +type OpenHow C.struct_open_how + +const SizeofOpenHow = C.sizeof_struct_open_how + +const ( + RESOLVE_BENEATH = C.RESOLVE_BENEATH + RESOLVE_IN_ROOT = C.RESOLVE_IN_ROOT + RESOLVE_NO_MAGICLINKS = C.RESOLVE_NO_MAGICLINKS + RESOLVE_NO_SYMLINKS = C.RESOLVE_NO_SYMLINKS + RESOLVE_NO_XDEV = C.RESOLVE_NO_XDEV +) + type PollFd C.struct_pollfd const (
diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go index bbe1abb..2b151eb 100644 --- a/unix/syscall_linux.go +++ b/unix/syscall_linux.go
@@ -133,6 +133,12 @@ return openat(dirfd, path, flags|O_LARGEFILE, mode) } +//sys openat2(dirfd int, path string, open_how *OpenHow, size int) (fd int, err error) + +func Openat2(dirfd int, path string, how *OpenHow) (fd int, err error) { + return openat2(dirfd, path, how, SizeofOpenHow) +} + //sys ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {
diff --git a/unix/syscall_linux_test.go b/unix/syscall_linux_test.go index e572376..8adb426 100644 --- a/unix/syscall_linux_test.go +++ b/unix/syscall_linux_test.go
@@ -663,3 +663,24 @@ t.Fatalf("unexpected return from prctl; got %v, expected %v", v, 1) } } + +func TestOpenat2(t *testing.T) { + how := &unix.OpenHow{ + Flags: unix.O_RDONLY, + Resolve: unix.RESOLVE_NO_MAGICLINKS, + } + fd, err := unix.Openat2(-1, "/proc/self/fd/1", how) + switch err { + case nil: + unix.Close(fd) + t.Fatal("expected ELOOP, got nil") + case unix.ELOOP: + return + case unix.ENOSYS: + t.Skip("old kernel? (need Linux >= 5.6)") + case unix.ENOENT: + t.Skipf("openat2: %v, skipping test", err) + default: + t.Fatalf("unexpected error from openat2: %v", err) + } +}
diff --git a/unix/zsyscall_linux.go b/unix/zsyscall_linux.go index fd2dae8..5c5b742 100644 --- a/unix/zsyscall_linux.go +++ b/unix/zsyscall_linux.go
@@ -83,6 +83,22 @@ // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func openat2(dirfd int, path string, open_how *OpenHow, size int) (fd int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_OPENAT2, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(open_how)), uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { r0, _, e1 := Syscall6(SYS_PPOLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)), 0, 0) n = int(r0)
diff --git a/unix/ztypes_linux.go b/unix/ztypes_linux.go index 9c43c26..781a5ea 100644 --- a/unix/ztypes_linux.go +++ b/unix/ztypes_linux.go
@@ -691,6 +691,22 @@ AT_EACCESS = 0x200 ) +type OpenHow struct { + Flags uint64 + Mode uint64 + Resolve uint64 +} + +const SizeofOpenHow = 0x18 + +const ( + RESOLVE_BENEATH = 0x8 + RESOLVE_IN_ROOT = 0x10 + RESOLVE_NO_MAGICLINKS = 0x2 + RESOLVE_NO_SYMLINKS = 0x4 + RESOLVE_NO_XDEV = 0x1 +) + type PollFd struct { Fd int32 Events int16