diff --git a/pkg/hostarch/hostarch_arm64.go b/pkg/hostarch/hostarch_arm64.go index 8ec71eb6d4..c83b92d784 100644 --- a/pkg/hostarch/hostarch_arm64.go +++ b/pkg/hostarch/hostarch_arm64.go @@ -86,6 +86,12 @@ func ESRAccessType(code uint64) AccessType { } } +// UntaggedUserAddr clears the tag from the address pointer. Top-Byte-Ignore (TBI0) +// is enabled in Linux, so bits[63:56] of user space addresses are ignored. +func UntaggedUserAddr(addr Addr) Addr { + return Addr(int64(addr<<8) >> 8) +} + func init() { // Make sure the page size is 4K on arm64 platform. if size := unix.Getpagesize(); size != PageSize { diff --git a/pkg/hostarch/hostarch_x86.go b/pkg/hostarch/hostarch_x86.go index 25c8ff3a0c..f79a101efb 100644 --- a/pkg/hostarch/hostarch_x86.go +++ b/pkg/hostarch/hostarch_x86.go @@ -43,3 +43,8 @@ var ( // ByteOrder is the native byte order (little endian). ByteOrder = binary.LittleEndian ) + +// UntaggedUserAddr is no-op on x86. +func UntaggedUserAddr(addr Addr) Addr { + return addr +} diff --git a/pkg/sentry/kernel/futex/futex.go b/pkg/sentry/kernel/futex/futex.go index c30d30172b..b5e0431e02 100644 --- a/pkg/sentry/kernel/futex/futex.go +++ b/pkg/sentry/kernel/futex/futex.go @@ -328,6 +328,7 @@ const ( // getKey returns a Key representing address addr in c. func getKey(t Target, addr hostarch.Addr, private bool) (Key, error) { + addr = hostarch.UntaggedUserAddr(addr) // Ensure the address is aligned. // It must be a DWORD boundary. if addr&0x3 != 0 { diff --git a/pkg/sentry/mm/io.go b/pkg/sentry/mm/io.go index 601af1e290..8c2c233279 100644 --- a/pkg/sentry/mm/io.go +++ b/pkg/sentry/mm/io.go @@ -70,6 +70,7 @@ const ( // // Preconditions: length >= 0. func (mm *MemoryManager) CheckIORange(addr hostarch.Addr, length int64) (hostarch.AddrRange, bool) { + addr = hostarch.UntaggedUserAddr(addr) // Note that access_ok() constrains end even if length == 0. ar, ok := addr.ToRange(uint64(length)) return ar, (ok && ar.End <= mm.layout.MaxAddr) diff --git a/pkg/sentry/mm/syscalls.go b/pkg/sentry/mm/syscalls.go index ed30b1b69b..29b7616554 100644 --- a/pkg/sentry/mm/syscalls.go +++ b/pkg/sentry/mm/syscalls.go @@ -33,6 +33,7 @@ import ( // // Preconditions: mm.as != nil. func (mm *MemoryManager) HandleUserFault(ctx context.Context, addr hostarch.Addr, at hostarch.AccessType, sp hostarch.Addr) error { + addr = hostarch.UntaggedUserAddr(addr) ar, ok := addr.RoundDown().ToRange(hostarch.PageSize) if !ok { return linuxerr.EFAULT @@ -304,6 +305,7 @@ func (mm *MemoryManager) MapStack(ctx context.Context) (hostarch.AddrRange, erro // MUnmap implements the semantics of Linux's munmap(2). func (mm *MemoryManager) MUnmap(ctx context.Context, addr hostarch.Addr, length uint64) error { + addr = hostarch.UntaggedUserAddr(addr) if addr != addr.RoundDown() { return linuxerr.EINVAL } @@ -358,6 +360,8 @@ const ( // MRemap implements the semantics of Linux's mremap(2). func (mm *MemoryManager) MRemap(ctx context.Context, oldAddr hostarch.Addr, oldSize uint64, newSize uint64, opts MRemapOpts) (hostarch.Addr, error) { + oldAddr = hostarch.UntaggedUserAddr(oldAddr) + // "Note that old_address has to be page aligned." - mremap(2) if oldAddr.RoundDown() != oldAddr { return 0, linuxerr.EINVAL @@ -627,6 +631,7 @@ func (mm *MemoryManager) MRemap(ctx context.Context, oldAddr hostarch.Addr, oldS // MProtect implements the semantics of Linux's mprotect(2). func (mm *MemoryManager) MProtect(addr hostarch.Addr, length uint64, realPerms hostarch.AccessType, growsDown bool) error { + addr = hostarch.UntaggedUserAddr(addr) if addr.RoundDown() != addr { return linuxerr.EINVAL } @@ -831,6 +836,7 @@ func (mm *MemoryManager) Brk(ctx context.Context, addr hostarch.Addr) (hostarch. // MLock implements the semantics of Linux's mlock()/mlock2()/munlock(), // depending on mode. func (mm *MemoryManager) MLock(ctx context.Context, addr hostarch.Addr, length uint64, mode memmap.MLockMode) error { + addr = hostarch.UntaggedUserAddr(addr) // Linux allows this to overflow. la, _ := hostarch.Addr(length + addr.PageOffset()).RoundUp() ar, ok := addr.RoundDown().ToRange(uint64(la)) @@ -1101,6 +1107,7 @@ func madviseAddrRange(addr hostarch.Addr, length uint64) (hostarch.AddrRange, er // Decommit implements the semantics of Linux's madvise(MADV_DONTNEED). func (mm *MemoryManager) Decommit(addr hostarch.Addr, length uint64) error { + addr = hostarch.UntaggedUserAddr(addr) ar, err := madviseAddrRange(addr, length) if err != nil { return err @@ -1293,6 +1300,7 @@ func (mm *MemoryManager) madviseMutateVMAs(addr hostarch.Addr, length uint64, f // // Preconditions: addr and length are page-aligned. func (mm *MemoryManager) SetDontFork(addr hostarch.Addr, length uint64, dontfork bool) error { + addr = hostarch.UntaggedUserAddr(addr) return mm.madviseMutateVMAs(addr, length, func(vseg vmaIterator) error { vseg.ValuePtr().dontfork = dontfork return nil @@ -1344,6 +1352,7 @@ type MSyncOpts struct { // MSync implements the semantics of Linux's msync(). func (mm *MemoryManager) MSync(ctx context.Context, addr hostarch.Addr, length uint64, opts MSyncOpts) error { + addr = hostarch.UntaggedUserAddr(addr) if addr != addr.RoundDown() { return linuxerr.EINVAL } diff --git a/pkg/sentry/platform/kvm/machine_arm64_unsafe.go b/pkg/sentry/platform/kvm/machine_arm64_unsafe.go index e0c74bac31..1ed244cf65 100644 --- a/pkg/sentry/platform/kvm/machine_arm64_unsafe.go +++ b/pkg/sentry/platform/kvm/machine_arm64_unsafe.go @@ -83,7 +83,8 @@ func (c *vCPU) initArchState() error { } // tcr_el1 - data = _TCR_TXSZ_VA48 | _TCR_CACHE_FLAGS | _TCR_SHARED | _TCR_TG_FLAGS | _TCR_ASID16 | _TCR_IPS_40BITS + data = _TCR_TXSZ_VA48 | _TCR_CACHE_FLAGS | _TCR_SHARED | _TCR_TG_FLAGS | + _TCR_ASID16 | _TCR_IPS_40BITS | _TCR_TBI0 reg.id = _KVM_ARM64_REGS_TCR_EL1 if err := c.setOneRegister(®); err != nil { return err diff --git a/pkg/sentry/syscalls/linux/sys_mmap.go b/pkg/sentry/syscalls/linux/sys_mmap.go index 70e3a5f3f3..037f1ade38 100644 --- a/pkg/sentry/syscalls/linux/sys_mmap.go +++ b/pkg/sentry/syscalls/linux/sys_mmap.go @@ -214,6 +214,7 @@ func Mincore(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr length := args[1].SizeT() vec := args[2].Pointer() + addr = hostarch.UntaggedUserAddr(addr) if addr != addr.RoundDown() { return 0, nil, linuxerr.EINVAL } diff --git a/test/syscalls/linux/fault.cc b/test/syscalls/linux/fault.cc index bd87d5e60c..704ac0e894 100644 --- a/test/syscalls/linux/fault.cc +++ b/test/syscalls/linux/fault.cc @@ -14,6 +14,7 @@ #define _GNU_SOURCE 1 #include +#include #include #include @@ -63,6 +64,20 @@ void sigact_handler(int sig, siginfo_t* siginfo, void* context) { } } +#if defined(__aarch64__) +#define APPLY_ADDRESS_TAG(addr) ((void*)((uint64)addr | (1ULL << 57))) + +TEST(TaggedAddressesTest, MemoryFault) { + void* addr = mmap(0, kPageSize, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); + ASSERT_NE(addr, MAP_FAILED); + addr = APPLY_ADDRESS_TAG(addr); + ((uint64*)addr)[0] = + 5; // trigger a memory fault that is handled in the Sentry. + EXPECT_THAT(munmap(addr, kPageSize), SyscallSucceeds()); +} +#endif + TEST(FaultTest, InRange) { // Reset the signal handler to do nothing so that it doesn't freak out // the test runner when we fire an alarm.