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:
Ayush Ranjan
2023-07-18 21:53:21 -07:00
committed by gVisor bot
parent a87aa73698
commit ea7cd71841
3 changed files with 67 additions and 19 deletions
+17 -19
View File
@@ -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:
+1
View File
@@ -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",
],
)
+49
View File
@@ -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)
}
}