mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add a new RPC ConnectWithCreds to allow gofer to connect to a unix domain socket with application's credentials
This commit is contained in:
+28
-3
@@ -53,6 +53,11 @@ var caps = []string{
|
||||
"CAP_SYS_CHROOT",
|
||||
}
|
||||
|
||||
var udsOpenCaps = []string{
|
||||
"CAP_SETUID",
|
||||
"CAP_SETGID",
|
||||
}
|
||||
|
||||
// goferCaps is the minimal set of capabilities needed by the Gofer to operate
|
||||
// on files.
|
||||
var goferCaps = &specs.LinuxCapabilities{
|
||||
@@ -61,6 +66,12 @@ var goferCaps = &specs.LinuxCapabilities{
|
||||
Permitted: caps,
|
||||
}
|
||||
|
||||
var goferUdsOpenCaps = &specs.LinuxCapabilities{
|
||||
Bounding: udsOpenCaps,
|
||||
Effective: udsOpenCaps,
|
||||
Permitted: udsOpenCaps,
|
||||
}
|
||||
|
||||
// goferSyncFDs contains file descriptors that are used for synchronization
|
||||
// of the Gofer startup process against other processes.
|
||||
type goferSyncFDs struct {
|
||||
@@ -180,7 +191,11 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomm
|
||||
overrides["apply-caps"] = "false"
|
||||
overrides["setup-root"] = "false"
|
||||
args := prepareArgs(g.Name(), f, overrides)
|
||||
util.Fatalf("setCapsAndCallSelf(%v, %v): %v", args, goferCaps, setCapsAndCallSelf(args, goferCaps))
|
||||
capsToApply := goferCaps
|
||||
if conf.GetHostUDS().AllowOpen() {
|
||||
capsToApply = specutils.MergeCapabilities(capsToApply, goferUdsOpenCaps)
|
||||
}
|
||||
util.Fatalf("setCapsAndCallSelf(%v, %v): %v", args, capsToApply, setCapsAndCallSelf(args, capsToApply))
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
@@ -252,6 +267,12 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomm
|
||||
}
|
||||
log.Infof("Process chroot'd to %q", root)
|
||||
|
||||
ruid := unix.Getuid()
|
||||
euid := unix.Geteuid()
|
||||
rgid := unix.Getgid()
|
||||
egid := unix.Getegid()
|
||||
log.Debugf("Process running as uid=%d euid=%d gid=%d egid=%d", ruid, euid, rgid, egid)
|
||||
|
||||
// Initialize filters.
|
||||
opts := filter.Options{
|
||||
UDSOpenEnabled: conf.GetHostUDS().AllowOpen(),
|
||||
@@ -264,7 +285,7 @@ func (g *Gofer) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomm
|
||||
util.Fatalf("installing seccomp filters: %v", err)
|
||||
}
|
||||
|
||||
return g.serve(spec, conf, root)
|
||||
return g.serve(spec, conf, root, ruid, euid, rgid, egid)
|
||||
}
|
||||
|
||||
func newSocket(ioFD int) *unet.Socket {
|
||||
@@ -275,7 +296,7 @@ func newSocket(ioFD int) *unet.Socket {
|
||||
return socket
|
||||
}
|
||||
|
||||
func (g *Gofer) serve(spec *specs.Spec, conf *config.Config, root string) subcommands.ExitStatus {
|
||||
func (g *Gofer) serve(spec *specs.Spec, conf *config.Config, root string, ruid int, euid int, rgid int, egid int) subcommands.ExitStatus {
|
||||
type connectionConfig struct {
|
||||
sock *unet.Socket
|
||||
mountPath string
|
||||
@@ -288,6 +309,10 @@ func (g *Gofer) serve(spec *specs.Spec, conf *config.Config, root string) subcom
|
||||
HostUDS: conf.GetHostUDS(),
|
||||
HostFifo: conf.HostFifo,
|
||||
DonateMountPointFD: conf.DirectFS,
|
||||
RUID: ruid,
|
||||
EUID: euid,
|
||||
RGID: rgid,
|
||||
EGID: egid,
|
||||
})
|
||||
|
||||
ioFDs := g.ioFDs
|
||||
|
||||
@@ -208,7 +208,9 @@ var udsCommonSyscalls = seccomp.MakeSyscallRules(map[uintptr]seccomp.SyscallRule
|
||||
})
|
||||
|
||||
var udsOpenSyscalls = seccomp.MakeSyscallRules(map[uintptr]seccomp.SyscallRule{
|
||||
unix.SYS_CONNECT: seccomp.MatchAll{},
|
||||
unix.SYS_CONNECT: seccomp.MatchAll{},
|
||||
unix.SYS_SETREUID: seccomp.MatchAll{},
|
||||
unix.SYS_SETREGID: seccomp.MatchAll{},
|
||||
})
|
||||
|
||||
var udsCreateSyscalls = seccomp.MakeSyscallRules(map[uintptr]seccomp.SyscallRule{
|
||||
|
||||
@@ -17,14 +17,17 @@
|
||||
package fsgofer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
@@ -64,6 +67,18 @@ type Config struct {
|
||||
// DonateMountPointFD indicates whether a host FD to the mount point should
|
||||
// be donated to the client on Mount RPC.
|
||||
DonateMountPointFD bool
|
||||
|
||||
// Gofer process's RUID.
|
||||
RUID int
|
||||
|
||||
// Gofer process's EUID.
|
||||
EUID int
|
||||
|
||||
// Gofer process's RGID.
|
||||
RGID int
|
||||
|
||||
// Gofer process's EGID.
|
||||
EGID int
|
||||
}
|
||||
|
||||
var procSelfFD *rwfd.FD
|
||||
@@ -178,6 +193,7 @@ func (s *LisafsServer) SupportedMessages() []lisafs.MID {
|
||||
lisafs.BindAt,
|
||||
lisafs.Listen,
|
||||
lisafs.Accept,
|
||||
lisafs.ConnectWithCreds,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,6 +839,50 @@ func (fd *controlFDLisa) Connect(sockType uint32) (int, error) {
|
||||
return sock, nil
|
||||
}
|
||||
|
||||
// ConnectWithCreds implements lisafs.ControlFDImpl.ConnectWithCreds.
|
||||
func (fd *controlFDLisa) ConnectWithCreds(sockType uint32, uid lisafs.UID, gid lisafs.GID) (int, error) {
|
||||
serverConfig := fd.Conn().ServerImpl().(*LisafsServer).config
|
||||
if !serverConfig.HostUDS.AllowOpen() {
|
||||
logRejectedUdsConnectOnce.Do(func() {
|
||||
log.Warningf("Rejecting attempt to connect to unix domain socket from host filesystem: %q. If you want to allow this, set flag --host-uds=open", fd.ControlFD.Node().FilePath())
|
||||
})
|
||||
return -1, unix.EPERM
|
||||
}
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
_, _, err := unix.Syscall(unix.SYS_SETREGID, uintptr(serverConfig.RGID), uintptr(gid), 0)
|
||||
if !errors.Is(err, syscall.Errno(0)) {
|
||||
log.Warningf("Failed to set egid; err: %v", err)
|
||||
} else {
|
||||
log.Debugf("Successfully set egid to %d", gid)
|
||||
}
|
||||
|
||||
_, _, err = unix.Syscall(unix.SYS_SETREUID, uintptr(serverConfig.RUID), uintptr(uid), 0)
|
||||
if !errors.Is(err, syscall.Errno(0)) {
|
||||
log.Warningf("Failed to set euid; err: %v", err)
|
||||
} else {
|
||||
log.Debugf("Successfully set euid to %d", uid)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_, _, err := unix.Syscall(unix.SYS_SETREUID, uintptr(serverConfig.RUID), uintptr(serverConfig.EUID), 0)
|
||||
if !errors.Is(err, unix.Errno(0)) {
|
||||
log.Warningf("Failed to restore euid; err: %v", err)
|
||||
} else {
|
||||
log.Debugf("Successfully restored euid to %d", serverConfig.EUID)
|
||||
}
|
||||
_, _, err = unix.Syscall(unix.SYS_SETREGID, uintptr(serverConfig.RGID), uintptr(serverConfig.EGID), 0)
|
||||
if !errors.Is(err, unix.Errno(0)) {
|
||||
log.Warningf("Failed to restore egid; err: %v", err)
|
||||
} else {
|
||||
log.Debugf("Successfully restored egid to %d", serverConfig.EGID)
|
||||
}
|
||||
}()
|
||||
|
||||
return fd.Connect(sockType)
|
||||
}
|
||||
|
||||
// BindAt implements lisafs.ControlFDImpl.BindAt.
|
||||
func (fd *controlFDLisa) BindAt(name string, sockType uint32, mode linux.FileMode, uid lisafs.UID, gid lisafs.GID) (*lisafs.ControlFD, linux.Statx, *lisafs.BoundSocketFD, int, error) {
|
||||
if !fd.Conn().ServerImpl().(*LisafsServer).config.HostUDS.AllowCreate() {
|
||||
|
||||
Reference in New Issue
Block a user