diff --git a/pkg/abi/linux/mm.go b/pkg/abi/linux/mm.go index 2263653cc..b48e1d18a 100644 --- a/pkg/abi/linux/mm.go +++ b/pkg/abi/linux/mm.go @@ -31,6 +31,7 @@ const ( MAP_PRIVATE = 1 << 1 MAP_FIXED = 1 << 4 MAP_ANONYMOUS = 1 << 5 + MAP_32BIT = 1 << 6 // arch/x86/include/uapi/asm/mman.h MAP_GROWSDOWN = 1 << 8 MAP_DENYWRITE = 1 << 11 MAP_EXECUTABLE = 1 << 12 diff --git a/pkg/sentry/memmap/memmap.go b/pkg/sentry/memmap/memmap.go index 14fed55bc..72986cbb9 100644 --- a/pkg/sentry/memmap/memmap.go +++ b/pkg/sentry/memmap/memmap.go @@ -266,6 +266,12 @@ type MMapOpts struct { // be replaced. If Unmap is true, Fixed must be true. Unmap bool + // If Map32Bit is true, all addresses in the created mapping must fit in a + // 32-bit integer. (Note that the "end address" of the mapping, i.e. the + // address of the first byte *after* the mapping, need not fit in a 32-bit + // integer.) Map32Bit is ignored if Fixed is true. + Map32Bit bool + // Perms is the set of permissions to the applied to this mapping. Perms usermem.AccessType diff --git a/pkg/sentry/mm/vma.go b/pkg/sentry/mm/vma.go index 61aaa3195..b81e861f1 100644 --- a/pkg/sentry/mm/vma.go +++ b/pkg/sentry/mm/vma.go @@ -34,9 +34,10 @@ func (mm *MemoryManager) createVMALocked(ctx context.Context, opts memmap.MMapOp // Find a useable range. addr, err := mm.findAvailableLocked(opts.Length, findAvailableOpts{ - Addr: opts.Addr, - Fixed: opts.Fixed, - Unmap: opts.Unmap, + Addr: opts.Addr, + Fixed: opts.Fixed, + Unmap: opts.Unmap, + Map32Bit: opts.Map32Bit, }) if err != nil { return vmaIterator{}, usermem.AddrRange{}, err @@ -93,24 +94,40 @@ func (mm *MemoryManager) createVMALocked(ctx context.Context, opts memmap.MMapOp } type findAvailableOpts struct { - // Addr is a suggested address. Addr must be page-aligned. - Addr usermem.Addr + // These fields are equivalent to those in memmap.MMapOpts, except that: + // + // - Addr must be page-aligned. + // + // - Unmap allows existing guard pages in the returned range. - // Fixed is true if only the suggested address is acceptable. - Fixed bool - - // Unmap is true if existing vmas and guard pages may exist in the returned - // range. - Unmap bool + Addr usermem.Addr + Fixed bool + Unmap bool + Map32Bit bool } +// map32Start/End are the bounds to which MAP_32BIT mappings are constrained, +// and are equivalent to Linux's MAP32_BASE and MAP32_MAX respectively. +const ( + map32Start = 0x40000000 + map32End = 0x80000000 +) + // findAvailableLocked finds an allocatable range. // // Preconditions: mm.mappingMu must be locked. func (mm *MemoryManager) findAvailableLocked(length uint64, opts findAvailableOpts) (usermem.Addr, error) { + if opts.Fixed { + opts.Map32Bit = false + } + allowedAR := mm.applicationAddrRange() + if opts.Map32Bit { + allowedAR = allowedAR.Intersect(usermem.AddrRange{map32Start, map32End}) + } + // Does the provided suggestion work? if ar, ok := opts.Addr.ToRange(length); ok { - if mm.applicationAddrRange().IsSupersetOf(ar) { + if allowedAR.IsSupersetOf(ar) { if opts.Unmap { return ar.Start, nil } @@ -132,6 +149,9 @@ func (mm *MemoryManager) findAvailableLocked(length uint64, opts findAvailableOp alignment = usermem.HugePageSize } + if opts.Map32Bit { + return mm.findLowestAvailableLocked(length, alignment, allowedAR) + } if mm.layout.DefaultDirection == arch.MmapBottomUp { return mm.findLowestAvailableLocked(length, alignment, usermem.AddrRange{mm.layout.BottomUpBase, mm.layout.MaxAddr}) } diff --git a/pkg/sentry/syscalls/linux/sys_mmap.go b/pkg/sentry/syscalls/linux/sys_mmap.go index 2c7d41de0..bfa23f6a8 100644 --- a/pkg/sentry/syscalls/linux/sys_mmap.go +++ b/pkg/sentry/syscalls/linux/sys_mmap.go @@ -45,6 +45,7 @@ func Mmap(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallC private := flags&linux.MAP_PRIVATE != 0 shared := flags&linux.MAP_SHARED != 0 anon := flags&linux.MAP_ANONYMOUS != 0 + map32bit := flags&linux.MAP_32BIT != 0 // Require exactly one of MAP_PRIVATE and MAP_SHARED. if private == shared { @@ -52,12 +53,13 @@ func Mmap(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallC } opts := memmap.MMapOpts{ - Length: args[1].Uint64(), - Offset: args[5].Uint64(), - Addr: args[0].Pointer(), - Fixed: fixed, - Unmap: fixed, - Private: private, + Length: args[1].Uint64(), + Offset: args[5].Uint64(), + Addr: args[0].Pointer(), + Fixed: fixed, + Unmap: fixed, + Map32Bit: map32bit, + Private: private, Perms: usermem.AccessType{ Read: linux.PROT_READ&prot != 0, Write: linux.PROT_WRITE&prot != 0,