unix: Faccess: check CAP_DAC_OVERRIDE on Linux

CL 126516 added support for flags argument, implemented in the same way
as glibc does (it tries to guess what the kernel would do).

CL 246537 added using faccess2(2) Linux syscall which supports the flags
directly. For older kernels, though, the syscall is not available, and
the code uses glibc-like fallback.

There is one very specific scenario in which the fallback fails.
The scenario involves all these conditions:
 - no faccessat2 support available (i.e. either Linux kernel < 5.8,
   or a seccomp set up to disable faccessat2);
 - the current user is not root (i.e. geteuid() != 0);
 - CAP_DAC_OVERRIDE capability is set for the current process;
 - the file to be executed does not have executable permission
   bit set for either the current EUID or EGID;
 - the file to be executed have at least one executable bit set.

Unfortunately, this set of conditions was observed in the wild -- a
container run as a non-root user with the binary file owned by root with
executable permission set for a user only [1]. Essentially it means it
is not as rare as it may seem.

Now, CAP_DAC_OVERRIDE essentially makes the kernel bypass most of the
checks, so execve(2) and friends work the same was as for root user,
i.e. if at least one executable bit it set, the permission to execute
is granted (see generic_permission() function in the Linux kernel).

Modify the code to check for CAP_DAC_OVERRIDE and mimic the kernel
behavior for permission checks.

This is essentially the same fix as CL 468735 for Go syscall package.

Tested on CentOS 7 with the repro similar to the one from [2].

[1] https://github.com/opencontainers/runc/issues/3715
[2] https://github.com/golang/go/issues/58552#issuecomment-1432505621

Change-Id: I726b6acab6a6e6d0358ef98e6a582b405c347614
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Reviewed-on: https://go-review.googlesource.com/c/sys/+/468877
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
1 file changed
tree: 107c330d9dde389c863350017b94663b1316cac8
  1. cpu/
  2. execabs/
  3. internal/
  4. plan9/
  5. unix/
  6. windows/
  7. .gitattributes
  8. .gitignore
  9. codereview.cfg
  10. CONTRIBUTING.md
  11. go.mod
  12. LICENSE
  13. PATENTS
  14. README.md
README.md

sys

Go Reference

This repository holds supplemental Go packages for low-level interactions with the operating system.

Download/Install

The easiest way to install is to run go get -u golang.org/x/sys. You can also manually git clone the repository to $GOPATH/src/golang.org/x/sys.

Report Issues / Send Patches

This repository uses Gerrit for code changes. To learn how to submit changes to this repository, see https://golang.org/doc/contribute.html.

The main issue tracker for the sys repository is located at https://github.com/golang/go/issues. Prefix your issue with “x/sys:” in the subject line, so it is easy to find.