From 71194033590006223e4afe1fec95b01443fdb3c6 Mon Sep 17 00:00:00 2001 From: Ayush Ranjan Date: Thu, 17 Oct 2024 21:53:10 -0700 Subject: [PATCH] goferfs: Use lgetxattr(2) to get xattr for sockets and symlinks. In goferfs, the control FD (in gofer client in directfs mode) and host FD in fsgofer server is an O_PATH FD for socket and symlink files. fgetxattr(2) fails with EBADF for O_PATH fds. So use lgetxattr(2) instead. This is a path-based syscall, so it should work for symlinks and sockets. Since the gofer client can not make path-based syscalls, it falls back to lisafs. Fixes #11049 Updates #10385 PiperOrigin-RevId: 687160973 --- pkg/sentry/fsimpl/gofer/dentry_impl.go | 2 +- pkg/sentry/fsimpl/gofer/directfs_dentry.go | 10 +++++++++- runsc/fsgofer/filter/config.go | 1 + runsc/fsgofer/lisafs.go | 6 ++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/pkg/sentry/fsimpl/gofer/dentry_impl.go b/pkg/sentry/fsimpl/gofer/dentry_impl.go index 8ebb4bb2c..8bace5dce 100644 --- a/pkg/sentry/fsimpl/gofer/dentry_impl.go +++ b/pkg/sentry/fsimpl/gofer/dentry_impl.go @@ -307,7 +307,7 @@ func (d *dentry) getXattrImpl(ctx context.Context, opts *vfs.GetXattrOptions) (s case *lisafsDentry: return dt.controlFD.GetXattr(ctx, opts.Name, opts.Size) case *directfsDentry: - return dt.getXattr(opts.Name, opts.Size) + return dt.getXattr(ctx, opts.Name, opts.Size) default: panic("unknown dentry implementation") } diff --git a/pkg/sentry/fsimpl/gofer/directfs_dentry.go b/pkg/sentry/fsimpl/gofer/directfs_dentry.go index 6d01ccbb1..5c54d0d56 100644 --- a/pkg/sentry/fsimpl/gofer/directfs_dentry.go +++ b/pkg/sentry/fsimpl/gofer/directfs_dentry.go @@ -423,7 +423,15 @@ func (d *directfsDentry) getHostChild(name string) (*dentry, error) { return d.fs.newDirectfsDentry(childFD) } -func (d *directfsDentry) getXattr(name string, size uint64) (string, error) { +func (d *directfsDentry) getXattr(ctx context.Context, name string, size uint64) (string, error) { + if ftype := d.fileType(); ftype == linux.S_IFSOCK || ftype == linux.S_IFLNK { + // Sockets and symlinks use O_PATH control FDs. However, fgetxattr(2) fails + // with EBADF for O_PATH FDs. Fallback to lisafs. + if err := d.ensureLisafsControlFD(ctx); err != nil { + return "", err + } + return d.controlFDLisa.GetXattr(ctx, name, size) + } data := make([]byte, size) if _, err := unix.Fgetxattr(d.controlFD, name, data); err != nil { return "", err diff --git a/runsc/fsgofer/filter/config.go b/runsc/fsgofer/filter/config.go index bd718a2cc..8f96bf584 100644 --- a/runsc/fsgofer/filter/config.go +++ b/runsc/fsgofer/filter/config.go @@ -105,6 +105,7 @@ var allowedSyscalls = seccomp.MakeSyscallRules(map[uintptr]seccomp.SyscallRule{ unix.SYS_GETRANDOM: seccomp.MatchAll{}, unix.SYS_GETTID: seccomp.MatchAll{}, unix.SYS_GETTIMEOFDAY: seccomp.MatchAll{}, + unix.SYS_LGETXATTR: seccomp.MatchAll{}, unix.SYS_LSEEK: seccomp.MatchAll{}, unix.SYS_MADVISE: seccomp.MatchAll{}, unix.SYS_MEMFD_CREATE: seccomp.MatchAll{}, // Used by flipcall.PacketWindowAllocator.Init(). diff --git a/runsc/fsgofer/lisafs.go b/runsc/fsgofer/lisafs.go index d7ada02fb..d28dfc047 100644 --- a/runsc/fsgofer/lisafs.go +++ b/runsc/fsgofer/lisafs.go @@ -923,6 +923,12 @@ func (fd *controlFDLisa) Renamed() { // GetXattr implements lisafs.ControlFDImpl.GetXattr. func (fd *controlFDLisa) GetXattr(name string, size uint32, getValueBuf func(uint32) []byte) (uint16, error) { data := getValueBuf(size) + if fd.IsSocket() || fd.IsSymlink() { + // Sockets and symlinks use O_PATH host FDs. However, fgetxattr(2) fails + // with EBADF for O_PATH FDs. Use lgetxattr(2) instead. + xattrSize, err := unix.Lgetxattr(fd.Node().FilePath(), name, data) + return uint16(xattrSize), err + } xattrSize, err := unix.Fgetxattr(fd.hostFD, name, data) return uint16(xattrSize), err }