diff options
| author | Joseph Richey <joerichey@google.com> | 2018-04-19 11:14:12 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-04-19 11:14:12 -0700 |
| commit | 3e32282af2f62829c711593a670e5d893df45196 (patch) | |
| tree | a201198a2f48222b2613d301b7ba6bb0e492d41e /security/privileges.go | |
| parent | 6c4ba88620db97ab90736595ede937f3610f161d (diff) | |
| parent | aa88bf4527cced6e3e16ca3e5ae07076cc8217f0 (diff) | |
Merge pull request #97 from ebiggers/privileges_fix
security: drop and regain privileges in all threads
Diffstat (limited to 'security/privileges.go')
| -rw-r--r-- | security/privileges.go | 83 |
1 files changed, 65 insertions, 18 deletions
diff --git a/security/privileges.go b/security/privileges.go index 7d69da9..24cd345 100644 --- a/security/privileges.go +++ b/security/privileges.go @@ -24,21 +24,61 @@ // - Maintaining the link between the root and user keyrings. package security +// Use the libc versions of setreuid, setregid, and setgroups instead of the +// "sys/unix" versions. The "sys/unix" versions use the raw syscalls which +// operate on the calling thread only, whereas the libc versions operate on the +// whole process. And we need to operate on the whole process, firstly for +// pam_fscrypt to prevent the privileges of Go worker threads from diverging +// from the PAM stack's "main" thread, violating libc's assumption and causing +// an abort() later in the PAM stack; and secondly because Go code may migrate +// between OS-level threads while it's running. +// +// See also: https://github.com/golang/go/issues/1435 +// +// Also we need to wrap the libc functions in our own C functions rather than +// calling them directly because in the glibc headers (but not necessarily in +// the headers for other C libraries that may be used on Linux) they are +// declared to take __uid_t and __gid_t arguments rather than uid_t and gid_t. +// And while these are typedef'ed to the same underlying type, before Go 1.10, +// cgo maps them to different Go types. + +/* +#include <sys/types.h> +#include <unistd.h> // setreuid, setregid +#include <grp.h> // setgroups + +static int my_setreuid(uid_t ruid, uid_t euid) +{ + return setreuid(ruid, euid); +} + +static int my_setregid(gid_t rgid, gid_t egid) +{ + return setregid(rgid, egid); +} + +static int my_setgroups(size_t size, const gid_t *list) +{ + return setgroups(size, list); +} +*/ +import "C" + import ( "log" "os" "os/user" + "syscall" "github.com/pkg/errors" - "golang.org/x/sys/unix" "github.com/google/fscrypt/util" ) -// SetThreadPrivileges temporarily drops the privileges of the current thread to -// have the effective uid/gid of the target user. The privileges can be changed -// again with another call to SetThreadPrivileges. -func SetThreadPrivileges(target *user.User) error { +// SetProcessPrivileges temporarily drops the privileges of the current process +// to have the effective uid/gid of the target user. The privileges can be +// changed again with another call to SetProcessPrivileges. +func SetProcessPrivileges(target *user.User) error { euid := util.AtoiOrPanic(target.Uid) egid := util.AtoiOrPanic(target.Gid) if os.Geteuid() == euid { @@ -71,15 +111,21 @@ func SetThreadPrivileges(target *user.User) error { } func setUids(ruid, euid int) error { - err := unix.Setreuid(ruid, euid) - log.Printf("Setreuid(%d, %d) = %v", ruid, euid, err) - return errors.Wrapf(err, "setting uids") + res, err := C.my_setreuid(C.uid_t(ruid), C.uid_t(euid)) + log.Printf("setreuid(%d, %d) = %d (errno %v)", ruid, euid, res, err) + if res == 0 { + return nil + } + return errors.Wrapf(err.(syscall.Errno), "setting uids") } func setGids(rgid, egid int) error { - err := unix.Setregid(rgid, egid) - log.Printf("Setregid(%d, %d) = %v", rgid, egid, err) - return errors.Wrapf(err, "setting gids") + res, err := C.my_setregid(C.gid_t(rgid), C.gid_t(egid)) + log.Printf("setregid(%d, %d) = %d (errno %v)", rgid, egid, res, err) + if res == 0 { + return nil + } + return errors.Wrapf(err.(syscall.Errno), "setting gids") } func setGroups(target *user.User) error { @@ -87,13 +133,14 @@ func setGroups(target *user.User) error { if err != nil { return util.SystemError(err.Error()) } - - gids := make([]int, len(groupStrings)) + gids := make([]C.gid_t, len(groupStrings)) for i, groupString := range groupStrings { - gids[i] = util.AtoiOrPanic(groupString) + gids[i] = C.gid_t(util.AtoiOrPanic(groupString)) } - - err = unix.Setgroups(gids) - log.Printf("Setgroups(%v) = %v", gids, err) - return errors.Wrapf(err, "setting groups") + res, err := C.my_setgroups(C.size_t(len(groupStrings)), &gids[0]) + log.Printf("setgroups(%v) = %d (errno %v)", gids, res, err) + if res == 0 { + return nil + } + return errors.Wrapf(err.(syscall.Errno), "setting groups") } |