Skip to content

x/sys/unix: Faccessat() fails to account for secondary group memberships when flags != 0 #39660

@makholm

Description

@makholm

Go's Facessat() implementation fails to account for secondary group memberships when flags != 0 when determining whether a given file access is allowed. This causes it to return an error where file access would actually be allowed. The following example demonstrates the problem, with a file that is only readable because of secondary group membership:

$ go version
go version go1.13.5 linux/amd64
$ cat test.go
package main

import (
	"fmt"
	"os"
	"syscall"
	"golang.org/x/sys/unix"
)

func main() {
	path := os.Args[1]
	err := syscall.Faccessat(0, path, unix.R_OK, unix.AT_EACCESS)
	fmt.Printf("uid %v, euid %v, gid %v, egid %v, path %v, err: %v\n", syscall.Getuid(), syscall.Geteuid(), syscall.Getgid(), syscall.Getegid(), path, err)
}
$ go build -o test
$ id
uid=501(lma) gid=20(dialout) groups=20(dialout),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),114(lpadmin),115(sambashare),116(docker)
$ ls -l file
-rwxrwx--- 1 root adm 6 Jun 17 20:19 file
$ cat file
Hello
$ ./test $(pwd)/file
uid 501, euid 501, gid 20, egid 20, path /home/lma/faccessat/file, err: permission denied
$

The go implementation (https://golang.org/src/syscall/syscall_linux.go) references the glibc implementation (https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/faccessat.c;hb=HEAD) but where glibc calls __group_member() to check group memberships if file's gid != user's gid, the go implementation just does a last-resort check of world/other permissions.

Naturally, I'd expect syscall.Faccessat() to act like C faccessat()... :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions