mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Allow walking on FIFO and UDS in lisafs.
The flags --host-uds and --host-fifo only control whether the application can open/connect or create/bind these special files. Stat-ing a host FIFO or UDS should not be blocked. PiperOrigin-RevId: 549199286
This commit is contained in:
+17
-19
@@ -116,7 +116,7 @@ func (s *LisafsServer) Mount(c *lisafs.Connection, mountNode *lisafs.Node) (*lis
|
||||
return nil, linux.Statx{}, -1, err
|
||||
}
|
||||
|
||||
if err := checkSupportedFileType(uint32(stat.Mode), &s.config); err != nil {
|
||||
if err := checkSupportedFileType(uint32(stat.Mode)); err != nil {
|
||||
log.Warningf("Mount: checkSupportedFileType() failed for file %q with mode %o: %v", mountPath, stat.Mode, err)
|
||||
return nil, linux.Statx{}, -1, err
|
||||
}
|
||||
@@ -408,7 +408,7 @@ func (fd *controlFDLisa) Walk(name string) (*lisafs.ControlFD, linux.Statx, erro
|
||||
return nil, linux.Statx{}, err
|
||||
}
|
||||
|
||||
if err := checkSupportedFileType(uint32(stat.Mode), &fd.Conn().ServerImpl().(*LisafsServer).config); err != nil {
|
||||
if err := checkSupportedFileType(uint32(stat.Mode)); err != nil {
|
||||
_ = unix.Close(childHostFD)
|
||||
log.Warningf("Walk: checkSupportedFileType() failed for %q with mode %o: %v", name, stat.Mode, err)
|
||||
return nil, linux.Statx{}, err
|
||||
@@ -445,7 +445,6 @@ func (fd *controlFDLisa) WalkStat(path lisafs.StringArray, recordStat func(linux
|
||||
if fd.IsSymlink() {
|
||||
return nil
|
||||
}
|
||||
server := fd.Conn().ServerImpl().(*LisafsServer)
|
||||
for _, name := range path {
|
||||
curFD, err := unix.Openat(curDirFD, name, unix.O_PATH|openFlags, 0)
|
||||
if err == unix.ENOENT {
|
||||
@@ -463,7 +462,7 @@ func (fd *controlFDLisa) WalkStat(path lisafs.StringArray, recordStat func(linux
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkSupportedFileType(uint32(stat.Mode), &server.config); err != nil {
|
||||
if err := checkSupportedFileType(uint32(stat.Mode)); err != nil {
|
||||
log.Warningf("WalkStat: checkSupportedFileType() failed for file %q with mode %o while walking path %+v: %v", name, stat.Mode, path, err)
|
||||
return err
|
||||
}
|
||||
@@ -481,6 +480,18 @@ func (fd *controlFDLisa) WalkStat(path lisafs.StringArray, recordStat func(linux
|
||||
|
||||
// Open implements lisafs.ControlFDImpl.Open.
|
||||
func (fd *controlFDLisa) Open(flags uint32) (*lisafs.OpenFD, int, error) {
|
||||
ftype := fd.FileType()
|
||||
server := fd.Conn().ServerImpl().(*LisafsServer)
|
||||
switch ftype {
|
||||
case unix.S_IFIFO:
|
||||
if !server.config.HostFifo.AllowOpen() {
|
||||
return nil, -1, unix.EPERM
|
||||
}
|
||||
case unix.S_IFSOCK:
|
||||
if !server.config.HostUDS.AllowOpen() {
|
||||
return nil, -1, unix.EPERM
|
||||
}
|
||||
}
|
||||
flags |= openFlags
|
||||
openHostFD, err := unix.Openat(int(procSelfFD.FD()), strconv.Itoa(fd.hostFD), int(flags)&^unix.O_NOFOLLOW, 0)
|
||||
if err != nil {
|
||||
@@ -488,7 +499,6 @@ func (fd *controlFDLisa) Open(flags uint32) (*lisafs.OpenFD, int, error) {
|
||||
}
|
||||
|
||||
hostFDToDonate := -1
|
||||
ftype := fd.FileType()
|
||||
switch {
|
||||
case ftype == unix.S_IFREG:
|
||||
// Best effort to donate file to the Sentry (for performance only).
|
||||
@@ -1140,21 +1150,9 @@ func fstatTo(hostFD int) (linux.Statx, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func checkSupportedFileType(mode uint32, config *Config) error {
|
||||
func checkSupportedFileType(mode uint32) error {
|
||||
switch mode & unix.S_IFMT {
|
||||
case unix.S_IFREG, unix.S_IFDIR, unix.S_IFLNK, unix.S_IFCHR:
|
||||
return nil
|
||||
|
||||
case unix.S_IFSOCK:
|
||||
if !config.HostUDS.AllowOpen() {
|
||||
return unix.EPERM
|
||||
}
|
||||
return nil
|
||||
|
||||
case unix.S_IFIFO:
|
||||
if !config.HostFifo.AllowOpen() {
|
||||
return unix.EPERM
|
||||
}
|
||||
case unix.S_IFREG, unix.S_IFDIR, unix.S_IFLNK, unix.S_IFCHR, unix.S_IFSOCK, unix.S_IFIFO:
|
||||
return nil
|
||||
|
||||
default:
|
||||
|
||||
@@ -26,6 +26,7 @@ go_test(
|
||||
"//pkg/test/testutil",
|
||||
"//runsc/specutils",
|
||||
"@com_github_docker_docker//api/types/mount:go_default_library",
|
||||
"@org_golang_x_sys//unix:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/mount"
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/test/dockerutil"
|
||||
"gvisor.dev/gvisor/pkg/test/testutil"
|
||||
)
|
||||
@@ -997,3 +998,51 @@ func TestCharDevice(t *testing.T) {
|
||||
t.Errorf("Wrong bytes, want: [all zeros], got: %v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockHostUds(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
d := dockerutil.MakeContainer(ctx, t)
|
||||
defer d.CleanUp(ctx)
|
||||
|
||||
dir, err := os.MkdirTemp(testutil.TmpDir(), "tmp-mount")
|
||||
if err != nil {
|
||||
t.Fatalf("MkdirTemp() failed: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
dirFD, err := unix.Open(dir, unix.O_PATH, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open %s: %v", dir, err)
|
||||
}
|
||||
defer unix.Close(dirFD)
|
||||
// Use /proc/self/fd to generate path to avoid EINVAL on large path.
|
||||
l, err := net.Listen("unix", filepath.Join("/proc/self/fd", strconv.Itoa(dirFD), "test.sock"))
|
||||
if err != nil {
|
||||
t.Fatalf("listen error: %v", err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
opts := dockerutil.RunOpts{
|
||||
Image: "basic/integrationtest",
|
||||
WorkDir: "/root",
|
||||
Mounts: []mount.Mount{
|
||||
{
|
||||
Type: mount.TypeBind,
|
||||
Source: dir,
|
||||
Target: "/dir",
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := d.Spawn(ctx, opts, "sleep", "infinity"); err != nil {
|
||||
t.Fatalf("docker run failed: %v", err)
|
||||
}
|
||||
// Application should be able to walk/stat the UDS ...
|
||||
if got, err := d.Exec(ctx, dockerutil.ExecOpts{}, "stat", "/dir/test.sock"); err != nil {
|
||||
t.Fatalf("stat(2)-ing the UDS failed: output = %q, err = %v", got, err)
|
||||
}
|
||||
// ... but not connect to it.
|
||||
const want = "connect: Connection refused"
|
||||
if got, err := d.Exec(ctx, dockerutil.ExecOpts{}, "./host_connect", "/dir/test.sock"); err == nil || !strings.Contains(got, want) {
|
||||
t.Errorf("err should be non-nil and output should contain %q, but got err = %v and output = %q", want, err, got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user