Open edigaryev opened 1 month ago
Related Issues and Documentation
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
I've actually toyed a bit with the Golang's source code, and this patch seems to work just fine on GOARCH=amd64
:
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index e4b9ce1bf4..6359b129ff 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -109,6 +109,9 @@ type SysProcAttr struct {
// functionality is supported by the kernel, or -1. Note *PidFD is
// changed only if the process starts successfully.
PidFD *int
+ // Landlock LSM
+ UseLandlock bool
+ LandlockRuleset int
}
var (
@@ -645,6 +648,19 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att
}
}
+ // Landlock LSM
+ if sys.UseLandlock {
+ _, _, err1 = RawSyscall(SYS_PRCTL, PR_SET_NO_NEW_PRIVS, 1, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+
+ _, _, err1 = RawSyscall(SYS_LANDLOCK_RESTRICT_SELF, uintptr(sys.LandlockRuleset), 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
// Time to exec.
_, _, err1 = RawSyscall(SYS_EXECVE,
uintptr(unsafe.Pointer(argv0)),
diff --git a/src/syscall/zsysnum_linux_amd64.go b/src/syscall/zsysnum_linux_amd64.go
index 576c7c36a6..5b32beb830 100644
--- a/src/syscall/zsysnum_linux_amd64.go
+++ b/src/syscall/zsysnum_linux_amd64.go
@@ -309,4 +309,5 @@ const (
SYS_FANOTIFY_INIT = 300
SYS_FANOTIFY_MARK = 301
SYS_PRLIMIT64 = 302
+ SYS_LANDLOCK_RESTRICT_SELF = 446
)
This clearly needs more documentation and a thorough analysis of whether (1) the placement of Landlock LSM invocation is correct and whether (2) the ruleset FD won't be closed at the point of landlock_restrict_self(2)
invocation.
But besides that, the system call constant values defined in src/syscall/zsysnum_linux_*.go
seem to be wildly outdated.
To implement the support for all architectures, one only needs a single SYS_LANDLOCK_RESTRICT_SELF
system call constant, but mksysnum_linux.pl
seems to generate a bunch of other (unneeded) definitions too.
What is the correct approach to add new system call definitions in this case? As far as I understand it's not possible to use golang.org/x/sys/unix
(which has this definition) from core Golang's repository.
New system calls needed by the standard library are put into internal/syscall/unix.
Proposal Details
This is a continuation of https://github.com/golang/go/issues/47049, which was retracted with the following comment:
I have a Golang binary that gets deployed once and then it
os/exec
's thegit
binary with various arguments under the hood hundreds of thousands of times to process lots of untrusted repositories on the internet.This
git
invocation ideally should only access a single temporary directory that we create for it and doesn't need anything else, yet the invoking Golang binary needs an access to much more files and directories, including the networking. So basically, I'm looking to exercise the least privilege principle here.Unfortunately due to Go's runtime and the use of threads, it seems to be somewhat complicated to use
fork(2)
, and even if it would work, it would mean re-inventing theos/exec
.It'd be great if one could do something like this on instead:
There's a nice
github.com/landlock-lsm/go-landlock
package with a very ergonomic API that can be adapted to emit the ruleset file-descriptor instead of restricting the current process with a couple of line changes.To get the
fd
for the*syscall.SysProcAttr
above, the user might do something like this:/cc @rsc