From 2d0c73638b2c8ff6b776ac86fdcf56fa33e362db Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 3 Nov 2023 16:59:16 +0100 Subject: [PATCH] unix: use fchmodat2 in Fchmodat The fchmodat2 syscall was added in Linux kernel 6.6. Use it in Fchmodat if flags are given. It will return ENOSYS on older kernels (or EINVAL or any other bogus error in some container implementations). Fixes golang/go#61636 Change-Id: Ibbc9a08733b7186907b2fe5837cb997446c38357 Reviewed-on: https://go-review.googlesource.com/c/sys/+/539635 Reviewed-by: Heschi Kreinick LUCI-TryBot-Result: Go LUCI Reviewed-by: Bryan Mills Reviewed-by: Mauri de Souza Meneguzzo --- unix/syscall_linux.go | 26 +++++++++++++++++--------- unix/zsyscall_linux.go | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/unix/syscall_linux.go b/unix/syscall_linux.go index a5e1c10e3..9b636ca07 100644 --- a/unix/syscall_linux.go +++ b/unix/syscall_linux.go @@ -61,15 +61,23 @@ func FanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname string) ( } //sys fchmodat(dirfd int, path string, mode uint32) (err error) - -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - // Linux fchmodat doesn't support the flags parameter. Mimick glibc's behavior - // and check the flags. Otherwise the mode would be applied to the symlink - // destination which is not what the user expects. - if flags&^AT_SYMLINK_NOFOLLOW != 0 { - return EINVAL - } else if flags&AT_SYMLINK_NOFOLLOW != 0 { - return EOPNOTSUPP +//sys fchmodat2(dirfd int, path string, mode uint32, flags int) (err error) + +func Fchmodat(dirfd int, path string, mode uint32, flags int) error { + // Linux fchmodat doesn't support the flags parameter, but fchmodat2 does. + // Try fchmodat2 if flags are specified. + if flags != 0 { + err := fchmodat2(dirfd, path, mode, flags) + if err == ENOSYS { + // fchmodat2 isn't available. If the flags are known to be valid, + // return EOPNOTSUPP to indicate that fchmodat doesn't support them. + if flags&^(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) != 0 { + return EINVAL + } else if flags&(AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH) != 0 { + return EOPNOTSUPP + } + } + return err } return fchmodat(dirfd, path, mode) } diff --git a/unix/zsyscall_linux.go b/unix/zsyscall_linux.go index faca7a557..1488d2712 100644 --- a/unix/zsyscall_linux.go +++ b/unix/zsyscall_linux.go @@ -37,6 +37,21 @@ func fchmodat(dirfd int, path string, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat2(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FCHMODAT2, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ioctl(fd int, req uint, arg uintptr) (err error) { _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) if e1 != 0 {