diff --git a/pkg/abi/linux/vfio.go b/pkg/abi/linux/vfio.go index 5943e4735..269a3ecf4 100644 --- a/pkg/abi/linux/vfio.go +++ b/pkg/abi/linux/vfio.go @@ -20,9 +20,15 @@ package linux const ( VFIO_TYPE = ';' VFIO_BASE = 100 + + // VFIO extensions. + VFIO_TYPE1_IOMMU = 1 + VFIO_SPAPR_TCE_IOMMU = 2 + VFIO_TYPE1v2_IOMMU = 3 ) // IOCTLs for VFIO file descriptor from include/uapi/linux/vfio.h. var ( + VFIO_CHECK_EXTENSION = IO(VFIO_TYPE, VFIO_BASE+1) VFIO_GROUP_SET_CONTAINER = IO(VFIO_TYPE, VFIO_BASE+4) ) diff --git a/pkg/sentry/devices/tpuproxy/seccomp_filter.go b/pkg/sentry/devices/tpuproxy/seccomp_filter.go index f989c9ebc..21d47c9f2 100644 --- a/pkg/sentry/devices/tpuproxy/seccomp_filter.go +++ b/pkg/sentry/devices/tpuproxy/seccomp_filter.go @@ -57,6 +57,10 @@ func Filters() seccomp.SyscallRules { seccomp.NonNegativeFD{}, seccomp.EqualTo(linux.VFIO_GROUP_SET_CONTAINER), }, + seccomp.PerArg{ + seccomp.NonNegativeFD{}, + seccomp.EqualTo(linux.VFIO_CHECK_EXTENSION), + }, }, }) } diff --git a/pkg/sentry/devices/tpuproxy/vfio.go b/pkg/sentry/devices/tpuproxy/vfio.go index 7dbf5ae1c..88268f92f 100644 --- a/pkg/sentry/devices/tpuproxy/vfio.go +++ b/pkg/sentry/devices/tpuproxy/vfio.go @@ -18,10 +18,13 @@ import ( "fmt" "golang.org/x/sys/unix" + "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/errors/linuxerr" "gvisor.dev/gvisor/pkg/fdnotifier" + "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/sentry/arch" + "gvisor.dev/gvisor/pkg/sentry/kernel" "gvisor.dev/gvisor/pkg/sentry/vfs" "gvisor.dev/gvisor/pkg/usermem" "gvisor.dev/gvisor/pkg/waiter" @@ -77,5 +80,45 @@ func (fd *vfioFd) Epollable() bool { // Ioctl implements vfs.FileDescriptionImpl.Ioctl. func (fd *vfioFd) Ioctl(ctx context.Context, uio usermem.IO, sysno uintptr, args arch.SyscallArguments) (uintptr, error) { + cmd := args[1].Uint() + t := kernel.TaskFromContext(ctx) + if t == nil { + panic("Ioctl should be called from a task context") + } + switch cmd { + case linux.VFIO_CHECK_EXTENSION: + return fd.checkExtension(extension(args[2].Int())) + } return 0, linuxerr.ENOSYS } + +// checkExtension returns a positive integer when the given VFIO extension +// is supported, otherwise, it returns 0. +func (fd *vfioFd) checkExtension(ext extension) (uintptr, error) { + switch ext { + case linux.VFIO_TYPE1_IOMMU, linux.VFIO_SPAPR_TCE_IOMMU, linux.VFIO_TYPE1v2_IOMMU: + ret, err := ioctlInvoke[int32](fd.hostFd, linux.VFIO_CHECK_EXTENSION, int32(ext)) + if err != nil { + log.Warningf("check VFIO extension %s: %v", ext, err) + return 0, err + } + return ret, nil + } + return 0, linuxerr.EINVAL +} + +// VFIO extension. +type extension int32 + +// String implements fmt.Stringer for VFIO extension string representation. +func (e extension) String() string { + switch e { + case linux.VFIO_TYPE1_IOMMU: + return "VFIO_TYPE1_IOMMU" + case linux.VFIO_SPAPR_TCE_IOMMU: + return "VFIO_SPAPR_TCE_IOMMU" + case linux.VFIO_TYPE1v2_IOMMU: + return "VFIO_TYPE1v2_IOMMU" + } + return "" +}