aboutsummaryrefslogtreecommitdiff
path: root/src/syscall/syscall_linux.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2018-07-27 10:48:18 -0700
committerIan Lance Taylor <iant@golang.org>2018-07-27 21:13:43 +0000
commitd970519086765367f545186d860080059c69fad8 (patch)
tree6c6606c562a92d518c25db68823f0b8532ecef0e /src/syscall/syscall_linux.go
parent902fc114272978a40d2e65c2510a18e870077559 (diff)
downloadgo-d970519086765367f545186d860080059c69fad8.tar.xz
syscall: support Faccessat flags argument
The Linux kernel faccessat system call does not take a flags parameter. The flag parameter to the C library faccessat function is implemented in C. The syscall.Faccessat function takes a flags parameter. In older releases we have passed the flags parameter to the kernel, which ignored it. In CL 120015 we started returning an error if any flags were set. That seems clearly better than ignoring them, but it turns out that some code was using the flags. The code was previously subtly broken. Now it is obviously broken. That is better, but we can do better still: we can implement the flags as the C library does. That is what this CL does. Change-Id: I259bd6f240c3951e939b81c3032dead3d9c567b4 Reviewed-on: https://go-review.googlesource.com/126415 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/syscall/syscall_linux.go')
-rw-r--r--src/syscall/syscall_linux.go66
1 files changed, 63 insertions, 3 deletions
diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go
index 1a304c4966..21c509f8d4 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -40,10 +40,70 @@ func Creat(path string, mode uint32) (fd int, err error) {
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
if flags & ^(_AT_SYMLINK_NOFOLLOW|_AT_EACCESS) != 0 {
return EINVAL
- } else if flags&(_AT_SYMLINK_NOFOLLOW|_AT_EACCESS) != 0 {
- return EOPNOTSUPP
}
- return faccessat(dirfd, path, mode)
+
+ // The Linux kernel faccessat system call does not take any flags.
+ // The glibc faccessat implements the flags itself; see
+ // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/faccessat.c;hb=HEAD
+ // Because people naturally expect syscall.Faccessat to act
+ // like C faccessat, we do the same.
+
+ if flags == 0 {
+ return faccessat(dirfd, path, mode)
+ }
+
+ var st Stat_t
+ if err := fstatat(dirfd, path, &st, flags&_AT_SYMLINK_NOFOLLOW); err != nil {
+ return err
+ }
+
+ mode &= 7
+ if mode == 0 {
+ return nil
+ }
+
+ var uid int
+ if flags&_AT_EACCESS != 0 {
+ uid = Geteuid()
+ } else {
+ uid = Getuid()
+ }
+
+ if uid == 0 {
+ if mode&1 == 0 {
+ // Root can read and write any file.
+ return nil
+ }
+ if st.Mode&0111 != 0 {
+ // Root can execute any file that anybody can execute.
+ return nil
+ }
+ return EACCES
+ }
+
+ var fmode uint32
+ if uint32(uid) == st.Uid {
+ fmode = (st.Mode >> 6) & 7
+ } else {
+ var gid int
+ if flags&_AT_EACCESS != 0 {
+ gid = Getegid()
+ } else {
+ gid = Getgid()
+ }
+
+ if uint32(gid) == st.Gid {
+ fmode = (st.Mode >> 3) & 7
+ } else {
+ fmode = st.Mode & 7
+ }
+ }
+
+ if fmode&mode == mode {
+ return nil
+ }
+
+ return EACCES
}
//sys fchmodat(dirfd int, path string, mode uint32) (err error)