diff --git a/vendor.conf b/vendor.conf index dffc7049c..fea47e480 100644 --- a/vendor.conf +++ b/vendor.conf @@ -41,4 +41,4 @@ github.com/boltdb/bolt e9cf4fae01b5a8ff89d0ec6b32f0d9c9f79aefdd google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4 github.com/dmcgowan/go-tar go1.10 -github.com/stevvooe/ttrpc 45d16b41b590938186c5c7cde8088607b3933231 +github.com/stevvooe/ttrpc 76e68349ad9ab4d03d764c713826d31216715e4f diff --git a/vendor/github.com/stevvooe/ttrpc/unixcreds.go b/vendor/github.com/stevvooe/ttrpc/unixcreds_linux.go similarity index 61% rename from vendor/github.com/stevvooe/ttrpc/unixcreds.go rename to vendor/github.com/stevvooe/ttrpc/unixcreds_linux.go index 5de8b922f..812d927dc 100644 --- a/vendor/github.com/stevvooe/ttrpc/unixcreds.go +++ b/vendor/github.com/stevvooe/ttrpc/unixcreds_linux.go @@ -1,5 +1,3 @@ -// +build linux freebsd solaris - package ttrpc import ( @@ -20,17 +18,21 @@ func (fn UnixCredentialsFunc) Handshake(ctx context.Context, conn net.Conn) (net return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: require unix socket") } - // TODO(stevvooe): Calling (*UnixConn).File causes a 5x performance - // decrease vs just accessing the fd directly. Need to do some more - // troubleshooting to isolate this to Go runtime or kernel. - fp, err := uc.File() + rs, err := uc.SyscallConn() if err != nil { - return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: failed to get unix file") + return nil, nil, errors.Wrap(err, "ttrpc.UnixCredentialsFunc: (net.UnixConn).SyscallConn failed") + } + var ( + ucred *unix.Ucred + ucredErr error + ) + if err := rs.Control(func(fd uintptr) { + ucred, ucredErr = unix.GetsockoptUcred(int(fd), unix.SOL_SOCKET, unix.SO_PEERCRED) + }); err != nil { + return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: (*syscall.RawConn).Control failed") } - defer fp.Close() // this gets duped and must be closed when this method is complete. - ucred, err := unix.GetsockoptUcred(int(fp.Fd()), unix.SOL_SOCKET, unix.SO_PEERCRED) - if err != nil { + if ucredErr != nil { return nil, nil, errors.Wrapf(err, "ttrpc.UnixCredentialsFunc: failed to retrieve socket peer credentials") } @@ -41,6 +43,14 @@ func (fn UnixCredentialsFunc) Handshake(ctx context.Context, conn net.Conn) (net return uc, ucred, nil } +// UnixSocketRequireUidGid requires specific *effective* UID/GID, rather than the real UID/GID. +// +// For example, if a daemon binary is owned by the root (UID 0) with SUID bit but running as an +// unprivileged user (UID 1001), the effective UID becomes 0, and the real UID becomes 1001. +// So calling this function with uid=0 allows a connection from effective UID 0 but rejects +// a connection from effective UID 1001. +// +// See socket(7), SO_PEERCRED: "The returned credentials are those that were in effect at the time of the call to connect(2) or socketpair(2)." func UnixSocketRequireUidGid(uid, gid int) UnixCredentialsFunc { return func(ucred *unix.Ucred) error { return requireUidGid(ucred, uid, gid) @@ -51,14 +61,14 @@ func UnixSocketRequireRoot() UnixCredentialsFunc { return UnixSocketRequireUidGid(0, 0) } -// UnixSocketRequireSameUser resolves the current unix user and returns a +// UnixSocketRequireSameUser resolves the current effective unix user and returns a // UnixCredentialsFunc that will validate incoming unix connections against the // current credentials. // // This is useful when using abstract sockets that are accessible by all users. func UnixSocketRequireSameUser() UnixCredentialsFunc { - uid, gid := os.Getuid(), os.Getgid() - return UnixSocketRequireUidGid(uid, gid) + euid, egid := os.Geteuid(), os.Getegid() + return UnixSocketRequireUidGid(euid, egid) } func requireRoot(ucred *unix.Ucred) error {