mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Get rid of fchdir(2) usage in directfs.
fchdir(2) was only needed to support connect(2) and bind(2), which are the
only filesystem operations that force host path traversal. The sandbox process
does not have the container filesystem in its mount namespace. It does not even
have procfs, so we can't use a path like /proc/self/fd/{socket-fd}. So earlier
we were using fchdir(2) to go into the socket's parent directory and use a
relative path.
However, allowing fchdir(2) makes it harder to reason about the sandbox process
state because it modifies the process's CWD. Directfs seccomp filters today do
not allow the usage of AT_FDCWD, but that could change in the future.
Operations that rely on the sandbox CWD need to synchronize using
pkg/sentry/fsutil/chdir package, like directfs does today. If they don't then
we could have nasty bugs.
Now we fallback to using LISAFS in such scenarios. This makes bind(2) and
connect(2) a little slower because now directfs has to perform a LISAFS walk
to get a LISAFS FD to the socket and then make the Connect/Bind RPC. But this
allows us to remove fchdir, socket, connect, bind, listen and accept from the
directfs seccomp filters. The rationale is that if making 2 relatively-rare
operations slightly slower helps us avoid chdir(2) and these other socket-based
syscalls, then it is overall a win.
Reported-by: Etienne Perot <eperot@google.com>
PiperOrigin-RevId: 516931050
This commit is contained in:
@@ -98,7 +98,6 @@ go_library(
|
||||
"//pkg/sentry/fsimpl/lock",
|
||||
"//pkg/sentry/fsmetric",
|
||||
"//pkg/sentry/fsutil",
|
||||
"//pkg/sentry/fsutil/chdir",
|
||||
"//pkg/sentry/hostfd",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
|
||||
@@ -490,7 +490,7 @@ func (fs *filesystem) restoreRoot(ctx context.Context, opts *vfs.CompleteRestore
|
||||
case *lisafsDentry:
|
||||
return dt.restoreFile(ctx, &rootInode, opts)
|
||||
case *directfsDentry:
|
||||
dt.rootControlFDLisa = fs.client.NewFD(rootInode.ControlFD)
|
||||
dt.controlFDLisa = fs.client.NewFD(rootInode.ControlFD)
|
||||
return dt.restoreFile(ctx, rootHostFD, opts)
|
||||
default:
|
||||
panic("unknown dentry implementation")
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/fsutil"
|
||||
"gvisor.dev/gvisor/pkg/lisafs"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsutil/chdir"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/unix/transport"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
@@ -78,7 +77,7 @@ func (fs *filesystem) getDirectfsRootDentry(ctx context.Context, rootHostFD int,
|
||||
rootControlFD.Close(ctx, false /* flush */)
|
||||
return nil, err
|
||||
}
|
||||
d.impl.(*directfsDentry).rootControlFDLisa = rootControlFD
|
||||
d.impl.(*directfsDentry).controlFDLisa = rootControlFD
|
||||
return d, nil
|
||||
}
|
||||
|
||||
@@ -95,12 +94,16 @@ type directfsDentry struct {
|
||||
// controlFD is the host FD to this file. controlFD is immutable.
|
||||
controlFD int
|
||||
|
||||
// rootControlFDLisa is a lisafs control FD on this dentry. This is only set
|
||||
// when this dentry represents the root of the current mount. This is
|
||||
// required in cases where we require dentry.parent to perform operations.
|
||||
// But for the root dentry, the parent is not available. So we fallback to
|
||||
// using lisafs RPCs. rootControlFDLisa is immutable.
|
||||
rootControlFDLisa lisafs.ClientFD `state:"nosave"`
|
||||
// controlFDLisa is a lisafs control FD on this dentry.
|
||||
// This is used to fallback to using lisafs RPCs in the following cases:
|
||||
// * When parent dentry is required to perform operations but
|
||||
// dentry.parent = nil (root dentry).
|
||||
// * For path-based syscalls (like connect(2) and bind(2)) on sockets.
|
||||
//
|
||||
// For the root dentry, controlFDLisa is always set and is immutable.
|
||||
// For sockets, controlFDLisa is protected by dentry.handleMu and is
|
||||
// immutable after initialization.
|
||||
controlFDLisa lisafs.ClientFD `state:"nosave"`
|
||||
}
|
||||
|
||||
// newDirectfsDentry creates a new dentry representing the given file. The dentry
|
||||
@@ -147,10 +150,10 @@ func (fs *filesystem) newDirectfsDentry(controlFD int) (*dentry, error) {
|
||||
func (d *directfsDentry) openHandle(ctx context.Context, flags uint32) (handle, error) {
|
||||
if d.parent == nil {
|
||||
// This is a mount point. We don't have parent. Fallback to using lisafs.
|
||||
if !d.rootControlFDLisa.Ok() {
|
||||
panic("directfsDentry.rootControlFDLisa is not set for mount point file")
|
||||
if !d.controlFDLisa.Ok() {
|
||||
panic("directfsDentry.controlFDLisa is not set for mount point dentry")
|
||||
}
|
||||
openFD, hostFD, err := d.rootControlFDLisa.OpenAt(ctx, flags)
|
||||
openFD, hostFD, err := d.controlFDLisa.OpenAt(ctx, flags)
|
||||
if err != nil {
|
||||
return noHandle, err
|
||||
}
|
||||
@@ -172,6 +175,55 @@ func (d *directfsDentry) openHandle(ctx context.Context, flags uint32) (handle,
|
||||
return handle{fd: int32(openFD)}, nil
|
||||
}
|
||||
|
||||
// Precondition: fs.renameMu is locked.
|
||||
func (d *directfsDentry) ensureLisafsControlFD(ctx context.Context) error {
|
||||
d.handleMu.Lock()
|
||||
defer d.handleMu.Unlock()
|
||||
if d.controlFDLisa.Ok() {
|
||||
return nil
|
||||
}
|
||||
|
||||
var names []string
|
||||
root := d
|
||||
for root.parent != nil {
|
||||
names = append(names, root.name)
|
||||
root = root.parent.impl.(*directfsDentry)
|
||||
}
|
||||
if !root.controlFDLisa.Ok() {
|
||||
panic("controlFDLisa is not set for mount point dentry")
|
||||
}
|
||||
if len(names) == 0 {
|
||||
return nil // d == root
|
||||
}
|
||||
// Reverse names.
|
||||
last := len(names) - 1
|
||||
for i := 0; i < len(names)/2; i++ {
|
||||
names[i], names[last-i] = names[last-i], names[i]
|
||||
}
|
||||
status, inodes, err := root.controlFDLisa.WalkMultiple(ctx, names)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
// Close everything except for inodes[last] if it exists.
|
||||
for i := 0; i < len(inodes) && i < last; i++ {
|
||||
flush := i == last-1 || i == len(inodes)-1
|
||||
d.fs.client.CloseFD(ctx, inodes[i].ControlFD, flush)
|
||||
}
|
||||
}()
|
||||
switch status {
|
||||
case lisafs.WalkComponentDoesNotExist:
|
||||
return unix.ENOENT
|
||||
case lisafs.WalkComponentSymlink:
|
||||
log.Warningf("intermediate path component was a symlink? names = %v, inodes = %+v", names, inodes)
|
||||
return unix.ELOOP
|
||||
case lisafs.WalkSuccess:
|
||||
d.controlFDLisa = d.fs.client.NewFD(inodes[last].ControlFD)
|
||||
return nil
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
// Precondition: d.metadataMu must be locked.
|
||||
//
|
||||
// +checklocks:d.metadataMu
|
||||
@@ -226,11 +278,11 @@ func (d *directfsDentry) chmod(ctx context.Context, mode uint16) error {
|
||||
|
||||
// This is a mount point socket. We don't have a parent FD. Fallback to using
|
||||
// lisafs.
|
||||
if !d.rootControlFDLisa.Ok() {
|
||||
panic("directfsDentry.rootControlFDLisa is not set for mount point socket")
|
||||
if !d.controlFDLisa.Ok() {
|
||||
panic("directfsDentry.controlFDLisa is not set for mount point socket")
|
||||
}
|
||||
|
||||
return chmod(ctx, d.rootControlFDLisa, mode)
|
||||
return chmod(ctx, d.controlFDLisa, mode)
|
||||
}
|
||||
|
||||
// Preconditions:
|
||||
@@ -274,8 +326,8 @@ func (d *directfsDentry) utimensat(ctx context.Context, stat *linux.Statx) error
|
||||
|
||||
// This is a mount point symlink. We don't have a parent FD. Fallback to
|
||||
// using lisafs.
|
||||
if !d.rootControlFDLisa.Ok() {
|
||||
panic("directfsDentry.rootControlFDLisa is not set for mount point symlink")
|
||||
if !d.controlFDLisa.Ok() {
|
||||
panic("directfsDentry.controlFDLisa is not set for mount point symlink")
|
||||
}
|
||||
|
||||
setStat := linux.Statx{
|
||||
@@ -283,7 +335,7 @@ func (d *directfsDentry) utimensat(ctx context.Context, stat *linux.Statx) error
|
||||
Atime: stat.Atime,
|
||||
Mtime: stat.Mtime,
|
||||
}
|
||||
_, failureErr, err := d.rootControlFDLisa.SetStat(ctx, &setStat)
|
||||
_, failureErr, err := d.controlFDLisa.SetStat(ctx, &setStat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -352,8 +404,8 @@ func (d *directfsDentry) destroy(ctx context.Context) {
|
||||
if d.controlFD >= 0 {
|
||||
_ = unix.Close(d.controlFD)
|
||||
}
|
||||
if d.rootControlFDLisa.Ok() {
|
||||
d.rootControlFDLisa.Close(ctx, true /* flush */)
|
||||
if d.controlFDLisa.Ok() {
|
||||
d.controlFDLisa.Close(ctx, true /* flush */)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,75 +480,29 @@ func (d *directfsDentry) mknod(ctx context.Context, name string, creds *auth.Cre
|
||||
return d.getCreatedChild(name, int(creds.EffectiveKUID), int(creds.EffectiveKGID), false /* isDir */)
|
||||
}
|
||||
|
||||
type boundSocketFD struct {
|
||||
sock int
|
||||
}
|
||||
|
||||
// Close closes the host and gofer-backed FDs associated to this bound socket.
|
||||
func (fd *boundSocketFD) Close(ctx context.Context) {
|
||||
_ = unix.Close(fd.sock)
|
||||
}
|
||||
|
||||
// NotificationFD is a host FD that can be used to notify when new clients
|
||||
// connect to the socket.
|
||||
func (fd *boundSocketFD) NotificationFD() int32 {
|
||||
return int32(fd.sock)
|
||||
}
|
||||
|
||||
// Listen makes a Listen RPC.
|
||||
func (fd *boundSocketFD) Listen(ctx context.Context, backlog int32) error {
|
||||
return unix.Listen(int(fd.sock), int(backlog))
|
||||
}
|
||||
|
||||
// Accept makes an Accept RPC.
|
||||
func (fd *boundSocketFD) Accept(ctx context.Context) (int, error) {
|
||||
flags := unix.O_NONBLOCK | unix.O_CLOEXEC
|
||||
nfd, _, err := unix.Accept4(int(fd.sock), flags)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return nfd, nil
|
||||
}
|
||||
|
||||
// Precondition: opts.Endpoint != nil and is transport.HostBoundEndpoint type.
|
||||
func (d *directfsDentry) bindAt(ctx context.Context, name string, creds *auth.Credentials, opts *vfs.MknodOptions) (*dentry, error) {
|
||||
if !d.fs.opts.directfs.hostUDSBind {
|
||||
return nil, unix.EPERM
|
||||
// There are no filesystems mounted in the sandbox process's mount namespace.
|
||||
// So we can't perform absolute path traversals. So fallback to using lisafs.
|
||||
if err := d.ensureLisafsControlFD(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// This mknod(2) is coming from unix bind(2), as opts.Endpoint is set.
|
||||
sockType := opts.Endpoint.(transport.Endpoint).Type()
|
||||
if !isSocketTypeSupported(sockType) {
|
||||
return nil, unix.ENXIO
|
||||
}
|
||||
// Create the socket.
|
||||
sockFD, err := unix.Socket(unix.AF_UNIX, int(sockType), 0)
|
||||
childInode, boundSocketFD, err := d.controlFDLisa.BindAt(ctx, sockType, name, opts.Mode, lisafs.UID(creds.EffectiveKUID), lisafs.GID(creds.EffectiveKGID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bsFD := &boundSocketFD{sockFD}
|
||||
d.fs.client.CloseFD(ctx, childInode.ControlFD, true /* flush */)
|
||||
// Update opts.Endpoint that it is bound.
|
||||
hbep := opts.Endpoint.(transport.HostBoundEndpoint)
|
||||
if err := hbep.SetBoundSocketFD(ctx, bsFD); err != nil {
|
||||
if err := hbep.SetBoundSocketFD(ctx, boundSocketFD); err != nil {
|
||||
if err := unix.Unlinkat(d.controlFD, name, 0); err != nil {
|
||||
log.Warningf("error unlinking newly created socket %q after failure: %v", filepath.Join(genericDebugPathname(&d.dentry), name), err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// fchmod(2) has to happen *before* the bind(2). sockFD's file mode will
|
||||
// be used in creating the filesystem-object in bind(2).
|
||||
if err := unix.Fchmod(sockFD, uint32(opts.Mode&^unix.S_IFMT)); err != nil {
|
||||
hbep.ResetBoundSocketFD(ctx)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// There are no filesystems mounted in the sandbox process's mount namespace.
|
||||
// So we can't perform absolute path traversals. So fchdir(2) to this
|
||||
// directory and bind at name (relative path traversal).
|
||||
if err := chdir.DoInDir(d.controlFD, func() error {
|
||||
return unix.Bind(sockFD, &unix.SockaddrUnix{Name: name})
|
||||
}); err != nil {
|
||||
hbep.ResetBoundSocketFD(ctx)
|
||||
return nil, err
|
||||
}
|
||||
child, err := d.getCreatedChild(name, int(creds.EffectiveKUID), int(creds.EffectiveKGID), false /* isDir */)
|
||||
// Socket already has the right UID/GID set, so use uid = gid = -1.
|
||||
child, err := d.getCreatedChild(name, -1 /* uid */, -1 /* gid */, false /* isDir */)
|
||||
if err != nil {
|
||||
hbep.ResetBoundSocketFD(ctx)
|
||||
return nil, err
|
||||
@@ -590,41 +596,12 @@ func (d *directfsDentry) getDirentsLocked(count int, recordDirent func(name stri
|
||||
|
||||
// Precondition: fs.renameMu is locked.
|
||||
func (d *directfsDentry) connect(ctx context.Context, sockType linux.SockType) (int, error) {
|
||||
if !d.fs.opts.directfs.hostUDSConnect {
|
||||
return -1, unix.EPERM
|
||||
}
|
||||
|
||||
if d.parent == nil {
|
||||
// This is a mount point socket. Fall back to lisafs for connect since we
|
||||
// don't have parent.
|
||||
if !d.rootControlFDLisa.Ok() {
|
||||
panic("directfsDentry.rootControlFDLisa is not set for mount point socket")
|
||||
}
|
||||
return d.rootControlFDLisa.Connect(ctx, sockType)
|
||||
}
|
||||
|
||||
if !isSocketTypeSupported(sockType) {
|
||||
log.Warningf("unsupported socket type %d", sockType)
|
||||
return -1, unix.ENXIO
|
||||
}
|
||||
|
||||
sock, err := unix.Socket(unix.AF_UNIX, int(sockType), 0)
|
||||
if err != nil {
|
||||
log.Warningf("socket(2) failed: %v", err)
|
||||
return -1, err
|
||||
}
|
||||
|
||||
// There are no filesystems mounted in the sandbox process's mount namespace.
|
||||
// So we can't perform absolute path traversals. So fchdir(2) to parent
|
||||
// and connect to this socket at name (relative path traversal).
|
||||
if err := chdir.DoInDir(d.parent.impl.(*directfsDentry).controlFD, func() error {
|
||||
return unix.Connect(sock, &unix.SockaddrUnix{Name: d.name})
|
||||
}); err != nil {
|
||||
unix.Close(sock)
|
||||
log.Warningf("connect(2) failed: %v", err)
|
||||
// So we can't perform absolute path traversals. So fallback to using lisafs.
|
||||
if err := d.ensureLisafsControlFD(ctx); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
return sock, nil
|
||||
return d.controlFDLisa.Connect(ctx, sockType)
|
||||
}
|
||||
|
||||
func (d *directfsDentry) readlink() (string, error) {
|
||||
|
||||
@@ -1753,12 +1753,6 @@ func (fs *filesystem) MountOptions() string {
|
||||
}
|
||||
if fs.opts.directfs.enabled {
|
||||
optsKV = append(optsKV, mopt{moptDirectfs, nil})
|
||||
if fs.opts.directfs.hostUDSBind {
|
||||
optsKV = append(optsKV, mopt{moptHostUDSBind, nil})
|
||||
}
|
||||
if fs.opts.directfs.hostUDSConnect {
|
||||
optsKV = append(optsKV, mopt{moptHostUDSConnect, nil})
|
||||
}
|
||||
}
|
||||
|
||||
opts := make([]string, 0, len(optsKV))
|
||||
|
||||
@@ -85,9 +85,7 @@ const (
|
||||
moptOverlayfsStaleRead = "overlayfs_stale_read"
|
||||
|
||||
// Directfs options.
|
||||
moptDirectfs = "directfs"
|
||||
moptHostUDSConnect = "host_uds_connect"
|
||||
moptHostUDSBind = "host_uds_bind"
|
||||
moptDirectfs = "directfs"
|
||||
)
|
||||
|
||||
// Valid values for the "cache" mount option.
|
||||
@@ -287,14 +285,6 @@ type directfsOpts struct {
|
||||
// If directfs is enabled, the gofer client does not make RPCs to the gofer
|
||||
// process. Instead, it makes host syscalls to perform file operations.
|
||||
enabled bool
|
||||
|
||||
// hostUDSBind dictates whether this mount can create host unix domain
|
||||
// sockets.
|
||||
hostUDSBind bool
|
||||
|
||||
// hostUDSConnect dictates whether this mount can connect to host unix domain
|
||||
// sockets.
|
||||
hostUDSConnect bool
|
||||
}
|
||||
|
||||
// InteropMode controls the client's interaction with other remote filesystem
|
||||
@@ -485,14 +475,6 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
delete(mopts, moptDirectfs)
|
||||
fsopts.directfs.enabled = true
|
||||
}
|
||||
if _, ok := mopts[moptHostUDSBind]; ok {
|
||||
delete(mopts, moptHostUDSBind)
|
||||
fsopts.directfs.hostUDSBind = true
|
||||
}
|
||||
if _, ok := mopts[moptHostUDSConnect]; ok {
|
||||
delete(mopts, moptHostUDSConnect)
|
||||
fsopts.directfs.hostUDSConnect = true
|
||||
}
|
||||
// fsopts.regularFilesUseSpecialFileFD can only be enabled by specifying
|
||||
// "cache=none".
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
load("//tools:defs.bzl", "go_library")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
go_library(
|
||||
name = "chdir",
|
||||
srcs = ["chdir.go"],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/sync",
|
||||
"@org_golang_x_sys//unix:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,69 +0,0 @@
|
||||
// Copyright 2023 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package chdir provides utilities to control the sandbox process's current
|
||||
// working directory.
|
||||
package chdir
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
)
|
||||
|
||||
// chdirMu is the global mutex that synchronizes host chdir operations for the
|
||||
// sandbox process.
|
||||
var chdirMu sync.Mutex
|
||||
|
||||
// cwd is the current working directory for the sandbox process. The sandbox
|
||||
// process usually runs in an empty chroot so cwd should be pointing to '/'.
|
||||
// cwd is protected by chdirMu.
|
||||
var cwd *os.File
|
||||
|
||||
// InitCWD initializes the global cwd FD. InitCWD must be called after the
|
||||
// sandbox process has been configured with pivot_root(2)/chroot(2).
|
||||
func InitCWD() (err error) {
|
||||
chdirMu.Lock()
|
||||
defer chdirMu.Unlock()
|
||||
if cwd != nil {
|
||||
panic("InitCWD() called twice")
|
||||
}
|
||||
cwd, err = os.Open(".")
|
||||
return
|
||||
}
|
||||
|
||||
// DoInDir performs fn after chdir-ing to dirFD and then reverts back to the
|
||||
// original CWD.
|
||||
//
|
||||
// Precondition: InitCWD() must have been called.
|
||||
func DoInDir(dirFD int, fn func() error) error {
|
||||
chdirMu.Lock()
|
||||
defer chdirMu.Unlock()
|
||||
if cwd == nil {
|
||||
panic("DoInDir() called without calling InitCWD()")
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := unix.Fchdir(int(cwd.Fd())); err != nil {
|
||||
panic(fmt.Errorf("restoring orginial CWD failed: %v", err))
|
||||
}
|
||||
}()
|
||||
|
||||
if err := unix.Fchdir(dirFD); err != nil {
|
||||
return err
|
||||
}
|
||||
return fn()
|
||||
}
|
||||
@@ -457,11 +457,6 @@ func hostFilesystemFilters() seccomp.SyscallRules {
|
||||
seccomp.MatchAny{},
|
||||
},
|
||||
},
|
||||
unix.SYS_FCHDIR: []seccomp.Rule{
|
||||
{
|
||||
validFDCheck,
|
||||
},
|
||||
},
|
||||
unix.SYS_READLINKAT: []seccomp.Rule{
|
||||
{
|
||||
validFDCheck,
|
||||
@@ -496,70 +491,3 @@ func hostFilesystemFilters() seccomp.SyscallRules {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// hostSocketCommonFilters contains syscalls that are needed to create socket FDs.
|
||||
func hostSocketCommonFilters() seccomp.SyscallRules {
|
||||
return seccomp.SyscallRules{
|
||||
unix.SYS_SOCKET: []seccomp.Rule{
|
||||
{
|
||||
seccomp.EqualTo(unix.AF_UNIX),
|
||||
seccomp.EqualTo(unix.SOCK_STREAM),
|
||||
seccomp.EqualTo(0),
|
||||
},
|
||||
{
|
||||
seccomp.EqualTo(unix.AF_UNIX),
|
||||
seccomp.EqualTo(unix.SOCK_DGRAM),
|
||||
seccomp.EqualTo(0),
|
||||
},
|
||||
{
|
||||
seccomp.EqualTo(unix.AF_UNIX),
|
||||
seccomp.EqualTo(unix.SOCK_SEQPACKET),
|
||||
seccomp.EqualTo(0),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// hostSocketCreateFilters contains syscalls that are needed to create UDS on
|
||||
// the host filesystem and interact with it.
|
||||
func hostSocketCreateFilters() seccomp.SyscallRules {
|
||||
validFDCheck := nonNegativeFDCheck()
|
||||
return seccomp.SyscallRules{
|
||||
unix.SYS_BIND: []seccomp.Rule{
|
||||
{
|
||||
validFDCheck,
|
||||
seccomp.MatchAny{},
|
||||
seccomp.MatchAny{},
|
||||
},
|
||||
},
|
||||
unix.SYS_LISTEN: []seccomp.Rule{
|
||||
{
|
||||
validFDCheck,
|
||||
seccomp.MatchAny{},
|
||||
},
|
||||
},
|
||||
unix.SYS_ACCEPT4: []seccomp.Rule{
|
||||
{
|
||||
validFDCheck,
|
||||
seccomp.MatchAny{},
|
||||
seccomp.MatchAny{},
|
||||
seccomp.EqualTo(unix.SOCK_NONBLOCK | unix.SOCK_CLOEXEC),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// hostSocketOpenFilters contains syscalls that are needed to open UDS on the
|
||||
// host filesystem and interact with it.
|
||||
func hostSocketOpenFilters() seccomp.SyscallRules {
|
||||
validFDCheck := nonNegativeFDCheck()
|
||||
return seccomp.SyscallRules{
|
||||
unix.SYS_CONNECT: []seccomp.Rule{
|
||||
{
|
||||
validFDCheck,
|
||||
seccomp.MatchAny{},
|
||||
seccomp.MatchAny{},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,6 @@ type Options struct {
|
||||
HostNetwork bool
|
||||
HostNetworkRawSockets bool
|
||||
HostFilesystem bool
|
||||
HostSocketCreate bool
|
||||
HostSocketOpen bool
|
||||
ProfileEnable bool
|
||||
ControllerFD int
|
||||
}
|
||||
@@ -60,16 +58,6 @@ func Install(opt Options) error {
|
||||
Report("host filesystem enabled: syscall filters less restrictive!")
|
||||
s.Merge(hostFilesystemFilters())
|
||||
}
|
||||
if opt.HostSocketCreate || opt.HostSocketOpen {
|
||||
Report("host socket enabled: syscall filters less restrictive!")
|
||||
s.Merge(hostSocketCommonFilters())
|
||||
if opt.HostSocketCreate {
|
||||
s.Merge(hostSocketCreateFilters())
|
||||
}
|
||||
if opt.HostSocketOpen {
|
||||
s.Merge(hostSocketOpenFilters())
|
||||
}
|
||||
}
|
||||
|
||||
s.Merge(opt.Platform.SyscallFilters())
|
||||
|
||||
|
||||
@@ -601,15 +601,12 @@ func (l *Loader) installSeccompFilters() error {
|
||||
if l.root.conf.DisableSeccomp {
|
||||
filter.Report("syscall filter is DISABLED. Running in less secure mode.")
|
||||
} else {
|
||||
hostUDS := l.root.conf.GetHostUDS()
|
||||
hostnet := l.root.conf.Network == config.NetworkHost
|
||||
opts := filter.Options{
|
||||
Platform: l.k.Platform,
|
||||
HostNetwork: hostnet,
|
||||
HostNetworkRawSockets: hostnet && l.root.conf.EnableRaw,
|
||||
HostFilesystem: l.root.conf.DirectFS,
|
||||
HostSocketCreate: l.root.conf.DirectFS && hostUDS.AllowCreate(),
|
||||
HostSocketOpen: l.root.conf.DirectFS && hostUDS.AllowOpen(),
|
||||
ProfileEnable: l.root.conf.ProfileEnable,
|
||||
ControllerFD: l.ctrl.srv.FD(),
|
||||
}
|
||||
|
||||
@@ -282,13 +282,6 @@ func goferMountData(fd int, fa config.FileAccessType, conf *config.Config) []str
|
||||
}
|
||||
if conf.DirectFS {
|
||||
opts = append(opts, "directfs")
|
||||
hostUDS := conf.GetHostUDS()
|
||||
if hostUDS.AllowOpen() {
|
||||
opts = append(opts, "host_uds_connect")
|
||||
}
|
||||
if hostUDS.AllowCreate() {
|
||||
opts = append(opts, "host_uds_bind")
|
||||
}
|
||||
}
|
||||
return opts
|
||||
}
|
||||
|
||||
@@ -61,7 +61,6 @@ go_library(
|
||||
"//pkg/prometheus",
|
||||
"//pkg/ring0",
|
||||
"//pkg/sentry/control",
|
||||
"//pkg/sentry/fsutil/chdir",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/platform",
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/metric"
|
||||
"gvisor.dev/gvisor/pkg/ring0"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsutil/chdir"
|
||||
"gvisor.dev/gvisor/pkg/sentry/platform"
|
||||
"gvisor.dev/gvisor/runsc/boot"
|
||||
"gvisor.dev/gvisor/runsc/cmd/util"
|
||||
@@ -362,12 +361,6 @@ func (b *Boot) Execute(_ context.Context, f *flag.FlagSet, args ...any) subcomma
|
||||
// modes exactly as sent by the sentry, which would have already applied
|
||||
// the application umask.
|
||||
unix.Umask(0)
|
||||
|
||||
// Now that the sandbox process is running in an empty pivot_root(2)
|
||||
// environment, we can initialize the chdir package.
|
||||
if err := chdir.InitCWD(); err != nil {
|
||||
util.Fatalf("Failed to initialize CWD for directfs: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if conf.EnableCoreTags {
|
||||
|
||||
Reference in New Issue
Block a user