diff --git a/pkg/sentry/vfs/device.go b/pkg/sentry/vfs/device.go index 572d81afc..52b6640aa 100644 --- a/pkg/sentry/vfs/device.go +++ b/pkg/sentry/vfs/device.go @@ -105,6 +105,35 @@ func (vfs *VirtualFilesystem) OpenDeviceSpecialFile(ctx context.Context, mnt *Mo return rd.dev.Open(ctx, mnt, d, *opts) } +// GetDynamicCharDevMajor allocates and returns an unused major device number +// for a character device or set of character devices. +func (vfs *VirtualFilesystem) GetDynamicCharDevMajor() (uint32, error) { + vfs.dynCharDevMajorMu.Lock() + defer vfs.dynCharDevMajorMu.Unlock() + // Compare Linux's fs/char_dev.c:find_dynamic_major(). + for major := uint32(254); major >= 234; major-- { + if _, ok := vfs.dynCharDevMajorUsed[major]; !ok { + vfs.dynCharDevMajorUsed[major] = struct{}{} + return major, nil + } + } + for major := uint32(511); major >= 384; major-- { + if _, ok := vfs.dynCharDevMajorUsed[major]; !ok { + vfs.dynCharDevMajorUsed[major] = struct{}{} + return major, nil + } + } + return 0, linuxerr.EBUSY +} + +// PutDynamicCharDevMajor deallocates a major device number returned by a +// previous call to GetDynamicCharDevMajor. +func (vfs *VirtualFilesystem) PutDynamicCharDevMajor(major uint32) { + vfs.dynCharDevMajorMu.Lock() + defer vfs.dynCharDevMajorMu.Unlock() + delete(vfs.dynCharDevMajorUsed, major) +} + // GetAnonBlockDevMinor allocates and returns an unused minor device number for // an "anonymous" block device with major number UNNAMED_MAJOR. func (vfs *VirtualFilesystem) GetAnonBlockDevMinor() (uint32, error) { diff --git a/pkg/sentry/vfs/vfs.go b/pkg/sentry/vfs/vfs.go index 1949b30cc..09e7cd936 100644 --- a/pkg/sentry/vfs/vfs.go +++ b/pkg/sentry/vfs/vfs.go @@ -116,6 +116,11 @@ type VirtualFilesystem struct { devicesMu sync.RWMutex `state:"nosave"` devices map[devTuple]*registeredDevice + // dynCharDevMajorUsed contains all allocated dynamic character device + // major numbers. dynCharDevMajor is protected by dynCharDevMajorMu. + dynCharDevMajorMu sync.Mutex `state:"nosave"` + dynCharDevMajorUsed map[uint32]struct{} + // anonBlockDevMinor contains all allocated anonymous block device minor // numbers. anonBlockDevMinorNext is a lower bound for the smallest // unallocated anonymous block device number. anonBlockDevMinorNext and @@ -149,6 +154,7 @@ func (vfs *VirtualFilesystem) Init(ctx context.Context) error { } vfs.mountpoints = make(map[*Dentry]map[*Mount]struct{}) vfs.devices = make(map[devTuple]*registeredDevice) + vfs.dynCharDevMajorUsed = make(map[uint32]struct{}) vfs.anonBlockDevMinorNext = 1 vfs.anonBlockDevMinor = make(map[uint32]struct{}) vfs.fsTypes = make(map[string]*registeredFilesystemType)