Skip to content

Commit

Permalink
Allow sending and importing a host event fd.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 724046820
  • Loading branch information
nlacasse authored and gvisor-bot committed Feb 6, 2025
1 parent 213917f commit a4a0e84
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
19 changes: 19 additions & 0 deletions pkg/sentry/fsimpl/eventfd/eventfd.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,25 @@ func New(ctx context.Context, vfsObj *vfs.VirtualFilesystem, initVal uint64, sem
return &efd.vfsfd, nil
}

// NewFromHost creates a new event fd from the given host fd.
func NewFromHost(ctx context.Context, vfsObj *vfs.VirtualFilesystem, hostfd int, flags uint32) (*vfs.FileDescription, error) {
semMode := flags&linux.EFD_SEMAPHORE != 0
fileFlags := uint32(linux.O_RDWR)
if flags&linux.EFD_NONBLOCK != 0 {
fileFlags |= linux.O_NONBLOCK
}
fd, err := New(ctx, vfsObj, 0, semMode, flags)
if err != nil {
return nil, err
}
efd := fd.Impl().(*EventFileDescription)
efd.hostfd = hostfd
if err := fdnotifier.AddFD(int32(hostfd), &efd.queue); err != nil {
return nil, err
}
return fd, nil
}

// HostFD returns the host eventfd associated with this event.
func (efd *EventFileDescription) HostFD() (int, error) {
efd.mu.Lock()
Expand Down
1 change: 1 addition & 0 deletions pkg/sentry/fsimpl/host/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ go_library(
"//pkg/refs",
"//pkg/safemem",
"//pkg/sentry/arch",
"//pkg/sentry/fsimpl/eventfd",
"//pkg/sentry/fsimpl/kernfs",
"//pkg/sentry/fsimpl/lock",
"//pkg/sentry/fsutil",
Expand Down
31 changes: 31 additions & 0 deletions pkg/sentry/fsimpl/host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"gvisor.dev/gvisor/pkg/hostarch"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/eventfd"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
"gvisor.dev/gvisor/pkg/sentry/hostfd"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
Expand Down Expand Up @@ -281,6 +282,11 @@ func NewFD(ctx context.Context, mnt *vfs.Mount, hostFD int, opts *NewFDOptions)
}

fileType := linux.FileMode(stat.Mode).FileType()
if fileType == 0 && isHostEventFdDevice(stat.Dev) {
// This is an event fd. No inode needed.
vfsObj := mnt.Filesystem().VirtualFilesystem()
return eventfd.NewFromHost(ctx, vfsObj, hostFD, flags)
}
i, err := newInode(ctx, fs, hostFD, opts.Savable, opts.RestoreKey, fileType, opts.IsTTY, opts.Readonly)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1027,3 +1033,28 @@ func (f *fileDescription) Ioctl(ctx context.Context, uio usermem.IO, sysno uintp

return f.FileDescriptionDefaultImpl.Ioctl(ctx, uio, sysno, args)
}

// hostEventFdDevice is the host device that host event fds are associated
// with. It is calculated once lazily.
var hostEventFdDevice uint64
var hostEventFdDeviceOnce sync.Once

// isHostEventFdDevice initializes hostEventFdDevice and compares it to the
// given host device id.
func isHostEventFdDevice(dev uint64) bool {
hostEventFdDeviceOnce.Do(func() {
efd, _, err := unix.RawSyscall(unix.SYS_EVENTFD2, 0, 0, 0)
if err != 0 {
log.Warningf("failed to create dummy eventfd: %v. Importing eventfds will fail", error(err))
return
}
defer unix.Close(int(efd))
var stat unix.Stat_t
if err := unix.Fstat(int(efd), &stat); err != nil {
log.Warningf("failed to stat dummy eventfd: %v. Importing eventfds will fail", error(err))
return
}
hostEventFdDevice = stat.Dev
})
return dev == hostEventFdDevice
}

0 comments on commit a4a0e84

Please sign in to comment.