From 3e8f1628e864201692aa28996f8f64f9761555af Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 12 Feb 2021 10:48:43 -0800 Subject: exec: Use cpu_untagged_addr in g2h; split out g2h_untagged Use g2h_untagged in contexts that have no cpu, e.g. the binary loaders that operate before the primary cpu is created. As a colollary, target_mmap and friends must use untagged addresses, since they are used by the loaders. Use g2h_untagged on values returned from target_mmap, as the kernel never applies a tag itself. Use g2h_untagged on all pc values. The only current user of tags, aarch64, removes tags from code addresses upon branch, so "pc" is always untagged. Use g2h with the cpu context on hand wherever possible. Use g2h_untagged in lock_user, which will be updated soon. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210212184902.1251044-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- linux-user/hppa/cpu_loop.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'linux-user/hppa/cpu_loop.c') diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c index d7e1ec7722..944511bbe4 100644 --- a/linux-user/hppa/cpu_loop.c +++ b/linux-user/hppa/cpu_loop.c @@ -23,6 +23,7 @@ static abi_ulong hppa_lws(CPUHPPAState *env) { + CPUState *cs = env_cpu(env); uint32_t which = env->gr[20]; abi_ulong addr = env->gr[26]; abi_ulong old = env->gr[25]; @@ -39,7 +40,7 @@ static abi_ulong hppa_lws(CPUHPPAState *env) } old = tswap32(old); new = tswap32(new); - ret = qatomic_cmpxchg((uint32_t *)g2h(addr), old, new); + ret = qatomic_cmpxchg((uint32_t *)g2h(cs, addr), old, new); ret = tswap32(ret); break; @@ -58,38 +59,38 @@ static abi_ulong hppa_lws(CPUHPPAState *env) can be host-endian as well. */ switch (size) { case 0: - old = *(uint8_t *)g2h(old); - new = *(uint8_t *)g2h(new); - ret = qatomic_cmpxchg((uint8_t *)g2h(addr), old, new); + old = *(uint8_t *)g2h(cs, old); + new = *(uint8_t *)g2h(cs, new); + ret = qatomic_cmpxchg((uint8_t *)g2h(cs, addr), old, new); ret = ret != old; break; case 1: - old = *(uint16_t *)g2h(old); - new = *(uint16_t *)g2h(new); - ret = qatomic_cmpxchg((uint16_t *)g2h(addr), old, new); + old = *(uint16_t *)g2h(cs, old); + new = *(uint16_t *)g2h(cs, new); + ret = qatomic_cmpxchg((uint16_t *)g2h(cs, addr), old, new); ret = ret != old; break; case 2: - old = *(uint32_t *)g2h(old); - new = *(uint32_t *)g2h(new); - ret = qatomic_cmpxchg((uint32_t *)g2h(addr), old, new); + old = *(uint32_t *)g2h(cs, old); + new = *(uint32_t *)g2h(cs, new); + ret = qatomic_cmpxchg((uint32_t *)g2h(cs, addr), old, new); ret = ret != old; break; case 3: { uint64_t o64, n64, r64; - o64 = *(uint64_t *)g2h(old); - n64 = *(uint64_t *)g2h(new); + o64 = *(uint64_t *)g2h(cs, old); + n64 = *(uint64_t *)g2h(cs, new); #ifdef CONFIG_ATOMIC64 - r64 = qatomic_cmpxchg__nocheck((uint64_t *)g2h(addr), + r64 = qatomic_cmpxchg__nocheck((uint64_t *)g2h(cs, addr), o64, n64); ret = r64 != o64; #else start_exclusive(); - r64 = *(uint64_t *)g2h(addr); + r64 = *(uint64_t *)g2h(cs, addr); ret = 1; if (r64 == o64) { - *(uint64_t *)g2h(addr) = n64; + *(uint64_t *)g2h(cs, addr) = n64; ret = 0; } end_exclusive(); -- cgit 1.4.1 From c7169b022b329a121d0c7acb550a08efa04d816a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 12 Feb 2021 10:48:47 -0800 Subject: linux-user: Use cpu_untagged_addr in access_ok; split out *_untagged Provide both tagged and untagged versions of access_ok. In a few places use thread_cpu, as the user is several callees removed from do_syscall1. Reviewed-by: Peter Maydell Signed-off-by: Richard Henderson Message-id: 20210212184902.1251044-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- linux-user/elfload.c | 2 +- linux-user/hppa/cpu_loop.c | 8 ++++---- linux-user/i386/cpu_loop.c | 2 +- linux-user/i386/signal.c | 5 +++-- linux-user/qemu.h | 11 +++++++++-- linux-user/syscall.c | 9 ++++++--- 6 files changed, 24 insertions(+), 13 deletions(-) (limited to 'linux-user/hppa/cpu_loop.c') diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 902be3ff11..73d750c809 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -3510,7 +3510,7 @@ static int vma_get_mapping_count(const struct mm_struct *mm) static abi_ulong vma_dump_size(const struct vm_area_struct *vma) { /* if we cannot even read the first page, skip it */ - if (!access_ok(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE)) + if (!access_ok_untagged(VERIFY_READ, vma->vma_start, TARGET_PAGE_SIZE)) return (0); /* diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c index 944511bbe4..3aaaf3337c 100644 --- a/linux-user/hppa/cpu_loop.c +++ b/linux-user/hppa/cpu_loop.c @@ -35,7 +35,7 @@ static abi_ulong hppa_lws(CPUHPPAState *env) return -TARGET_ENOSYS; case 0: /* elf32 atomic 32bit cmpxchg */ - if ((addr & 3) || !access_ok(VERIFY_WRITE, addr, 4)) { + if ((addr & 3) || !access_ok(cs, VERIFY_WRITE, addr, 4)) { return -TARGET_EFAULT; } old = tswap32(old); @@ -50,9 +50,9 @@ static abi_ulong hppa_lws(CPUHPPAState *env) return -TARGET_ENOSYS; } if (((addr | old | new) & ((1 << size) - 1)) - || !access_ok(VERIFY_WRITE, addr, 1 << size) - || !access_ok(VERIFY_READ, old, 1 << size) - || !access_ok(VERIFY_READ, new, 1 << size)) { + || !access_ok(cs, VERIFY_WRITE, addr, 1 << size) + || !access_ok(cs, VERIFY_READ, old, 1 << size) + || !access_ok(cs, VERIFY_READ, new, 1 << size)) { return -TARGET_EFAULT; } /* Note that below we use host-endian loads so that the cmpxchg diff --git a/linux-user/i386/cpu_loop.c b/linux-user/i386/cpu_loop.c index 19c8a18cd3..f813e87294 100644 --- a/linux-user/i386/cpu_loop.c +++ b/linux-user/i386/cpu_loop.c @@ -99,7 +99,7 @@ static bool write_ok_or_segv(CPUX86State *env, abi_ptr addr, size_t len) * For all the vsyscalls, NULL means "don't write anything" not * "write it at address 0". */ - if (addr == 0 || access_ok(VERIFY_WRITE, addr, len)) { + if (addr == 0 || access_ok(env_cpu(env), VERIFY_WRITE, addr, len)) { return true; } diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c index 97a39204cc..9320e1d472 100644 --- a/linux-user/i386/signal.c +++ b/linux-user/i386/signal.c @@ -513,9 +513,10 @@ restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc) fpstate_addr = tswapl(sc->fpstate); if (fpstate_addr != 0) { - if (!access_ok(VERIFY_READ, fpstate_addr, - sizeof(struct target_fpstate))) + if (!access_ok(env_cpu(env), VERIFY_READ, fpstate_addr, + sizeof(struct target_fpstate))) { goto badframe; + } #ifndef TARGET_X86_64 cpu_x86_frstor(env, fpstate_addr, 1); #else diff --git a/linux-user/qemu.h b/linux-user/qemu.h index b3ccffbf0f..82eabb73f8 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -491,7 +491,7 @@ extern unsigned long guest_stack_size; #define VERIFY_READ PAGE_READ #define VERIFY_WRITE (PAGE_READ | PAGE_WRITE) -static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) +static inline bool access_ok_untagged(int type, abi_ulong addr, abi_ulong size) { if (size == 0 ? !guest_addr_valid_untagged(addr) @@ -501,6 +501,12 @@ static inline bool access_ok(int type, abi_ulong addr, abi_ulong size) return page_check_range((target_ulong)addr, size, type) == 0; } +static inline bool access_ok(CPUState *cpu, int type, + abi_ulong addr, abi_ulong size) +{ + return access_ok_untagged(type, cpu_untagged_addr(cpu, addr), size); +} + /* NOTE __get_user and __put_user use host pointers and don't check access. These are usually used to access struct data members once the struct has been locked - usually with lock_user_struct. */ @@ -636,8 +642,9 @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len); host area will have the same contents as the guest. */ static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy) { - if (!access_ok(type, guest_addr, len)) + if (!access_ok_untagged(type, guest_addr, len)) { return NULL; + } #ifdef DEBUG_REMAP { void *addr; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 53529e4004..3d0411da57 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3526,8 +3526,9 @@ static abi_long do_accept4(int fd, abi_ulong target_addr, return -TARGET_EINVAL; } - if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) + if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) { return -TARGET_EFAULT; + } addr = alloca(addrlen); @@ -3557,8 +3558,9 @@ static abi_long do_getpeername(int fd, abi_ulong target_addr, return -TARGET_EINVAL; } - if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) + if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) { return -TARGET_EFAULT; + } addr = alloca(addrlen); @@ -3588,8 +3590,9 @@ static abi_long do_getsockname(int fd, abi_ulong target_addr, return -TARGET_EINVAL; } - if (!access_ok(VERIFY_WRITE, target_addr, addrlen)) + if (!access_ok(thread_cpu, VERIFY_WRITE, target_addr, addrlen)) { return -TARGET_EFAULT; + } addr = alloca(addrlen); -- cgit 1.4.1