@samitouri / QOSamiQemu / commits / 8330da591e

include/user/guest-host.h: Provide g2h etc for both abi_ptr and vaddr

In commit 7804c84a ("include/user: Use vaddr in guest-host.h") we changed all the functions in guest-host.h that took or returned their guest address argument in type abi_ptr to instead use vaddr. This introduced regressions for the case of a 32-bit guest and an address above 2GB for the common situation where the address is a syscall argument stored in a variable of type 'abi_long'. With abi_ptr (which will be an unsigned 32-bit type for 32-bit guests), the address is cast to unsigned 32-bit, and then zero-extended to 64-bits in g2h_untagged_vaddr(). With the switch to vaddr (which is always a 64-bit unsigned type), the guest address will instead be sign-extended to 64 bits, which gives the wrong answer. Fix this by providing two versions of the affected functions: the standard names (g2h(), g2h_untagged(), guest_addr_valid_untagged(), guest_range_valid_untagged(), cpu_untagged_addr()) return to using the logically-correct abi_ptr type; new versions with a _vaddr() prefix use the vaddr type. accel/tcg/user-exec.c must change to use the _vaddr() versions; this is the only file that uses guest-host.h that we want to compile once. All the other uses are in linux-user and bsd-user code that inherently has to know the sizes of target-ABI types. Cc: qemu-stable@nongnu.org Fixes: 7804c84a ("include/user: Use vaddr in guest-host.h") Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3333 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260330143123.1685142-3-peter.maydell@linaro.org Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>

Peter Maydell committed Mar 30, 2026 at 15:31 UTC 8330da591ef62484b408e323d828566095a64929
2 files changed +69 -19
accel/tcg/user-exec.c
+13 -13
@@ -647,7 +647,7 @@ void tb_lock_page0(tb_page_addr_t address)
647
648 if (prot & PAGE_WRITE) {
649 pageflags_set_clear(start, last, 0, PAGE_WRITE);
650 - mprotect(g2h_untagged(start), last - start + 1,
650 + mprotect(g2h_untagged_vaddr(start), last - start + 1,
651 prot & (PAGE_READ | PAGE_EXEC) ? PROT_READ : PROT_NONE);
652 }
653 }
@@ -734,7 +734,7 @@ int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc)
734 if (prot & PAGE_EXEC) {
735 prot = (prot & ~PAGE_EXEC) | PAGE_READ;
736 }
737 - mprotect((void *)g2h_untagged(start), len, prot & PAGE_RWX);
737 + mprotect((void *)g2h_untagged_vaddr(start), len, prot & PAGE_RWX);
738 }
739 mmap_unlock();
740
@@ -763,7 +763,7 @@ static int probe_access_internal(CPUArchState *env, vaddr addr,
763 g_assert_not_reached();
764 }
765
766 - if (guest_addr_valid_untagged(addr)) {
766 + if (guest_addr_valid_untagged_vaddr(addr)) {
767 int page_flags = page_get_flags(addr);
768 if (page_flags & acc_flag) {
769 if (access_type != MMU_INST_FETCH
@@ -792,7 +792,7 @@ int probe_access_flags(CPUArchState *env, vaddr addr, int size,
792
793 g_assert(-(addr | TARGET_PAGE_MASK) >= size);
794 flags = probe_access_internal(env, addr, size, access_type, nonfault, ra);
795 - *phost = (flags & TLB_INVALID_MASK) ? NULL : g2h(env_cpu(env), addr);
795 + *phost = (flags & TLB_INVALID_MASK) ? NULL : g2h_vaddr(env_cpu(env), addr);
796 return flags;
797 }
798
@@ -805,13 +805,13 @@ void *probe_access(CPUArchState *env, vaddr addr, int size,
805 flags = probe_access_internal(env, addr, size, access_type, false, ra);
806 g_assert((flags & ~TLB_MMIO) == 0);
807
808 - return size ? g2h(env_cpu(env), addr) : NULL;
808 + return size ? g2h_vaddr(env_cpu(env), addr) : NULL;
809 }
810
811 void *tlb_vaddr_to_host(CPUArchState *env, vaddr addr,
812 MMUAccessType access_type, int mmu_idx)
813 {
814 - return g2h(env_cpu(env), addr);
814 + return g2h_vaddr(env_cpu(env), addr);
815 }
816
817 tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr,
@@ -822,7 +822,7 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr,
822 flags = probe_access_internal(env, addr, 1, MMU_INST_FETCH, false, 0);
823 g_assert(flags == 0);
824
825 - *hostp = g2h_untagged(addr);
825 + *hostp = g2h_untagged_vaddr(addr);
826 return addr;
827 }
828
@@ -938,7 +938,7 @@ static void *cpu_mmu_lookup(CPUState *cpu, vaddr addr,
938 cpu_loop_exit_sigbus(cpu, addr, type, ra);
939 }
940
941 - ret = g2h(cpu, addr);
941 + ret = g2h_vaddr(cpu, addr);
942 set_helper_retaddr(ra);
943 return ret;
944 }
@@ -968,7 +968,7 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
968 }
969 if (is_write) {
970 if (flags & PAGE_WRITE) {
971 - memcpy(g2h(cpu, addr), buf, l);
971 + memcpy(g2h_vaddr(cpu, addr), buf, l);
972 } else {
973 /* Bypass the host page protection using ptrace. */
974 if (fd == -1) {
@@ -987,13 +987,13 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
987 */
988 tb_invalidate_phys_range(NULL, addr, addr + l - 1);
989 written = pwrite(fd, buf, l,
990 - (off_t)(uintptr_t)g2h_untagged(addr));
990 + (off_t)(uintptr_t)g2h_untagged_vaddr(addr));
991 if (written != l) {
992 goto out_close;
993 }
994 }
995 } else if (flags & PAGE_READ) {
996 - memcpy(buf, g2h(cpu, addr), l);
996 + memcpy(buf, g2h_vaddr(cpu, addr), l);
997 } else {
998 /* Bypass the host page protection using ptrace. */
999 if (fd == -1) {
@@ -1003,7 +1003,7 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
1003 }
1004 }
1005 if (pread(fd, buf, l,
1006 - (off_t)(uintptr_t)g2h_untagged(addr)) != l) {
1006 + (off_t)(uintptr_t)g2h_untagged_vaddr(addr)) != l) {
1007 goto out_close;
1008 }
1009 }
@@ -1231,7 +1231,7 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi,
1231 cpu_loop_exit_atomic(cpu, retaddr);
1232 }
1233
1234 - ret = g2h(cpu, addr);
1234 + ret = g2h_vaddr(cpu, addr);
1235 set_helper_retaddr(retaddr);
1236 return ret;
1237 }
include/user/guest-host.h
+56 -6
@@ -29,7 +29,12 @@ extern unsigned long reserved_va;
29 */
30 extern unsigned long guest_addr_max;
31
32 -static inline vaddr cpu_untagged_addr(CPUState *cs, vaddr x)
32 +/*
33 + * These functions take the guest virtual address as a vaddr,
34 + * and are suitable for use from target-independent code.
35 + */
36 +
37 +static inline vaddr cpu_untagged_addr_vaddr(CPUState *cs, vaddr x)
38 {
39 const TCGCPUOps *tcg_ops = cs->cc->tcg_ops;
40 if (tcg_ops->untagged_addr) {
@@ -39,22 +44,22 @@ static inline vaddr cpu_untagged_addr(CPUState *cs, vaddr x)
44 }
45
46 /* All direct uses of g2h and h2g need to go away for usermode softmmu. */
42 -static inline void *g2h_untagged(vaddr x)
47 +static inline void *g2h_untagged_vaddr(vaddr x)
48 {
49 return (void *)((uintptr_t)(x) + guest_base);
50 }
51
47 -static inline void *g2h(CPUState *cs, vaddr x)
52 +static inline void *g2h_vaddr(CPUState *cs, vaddr x)
53 {
49 - return g2h_untagged(cpu_untagged_addr(cs, x));
54 + return g2h_untagged_vaddr(cpu_untagged_addr_vaddr(cs, x));
55 }
56
52 -static inline bool guest_addr_valid_untagged(vaddr x)
57 +static inline bool guest_addr_valid_untagged_vaddr(vaddr x)
58 {
59 return x <= guest_addr_max;
60 }
61
57 -static inline bool guest_range_valid_untagged(vaddr start, vaddr len)
62 +static inline bool guest_range_valid_untagged_vaddr(vaddr start, vaddr len)
63 {
64 return len - 1 <= guest_addr_max && start <= guest_addr_max - len + 1;
65 }
@@ -73,4 +78,49 @@ static inline bool guest_range_valid_untagged(vaddr start, vaddr len)
78 h2g_nocheck(x); \
79 })
80
81 +#ifdef COMPILING_PER_TARGET
82 +
83 +/*
84 + * These functions take the guest virtual address as an abi_ptr. This
85 + * is an important difference from a vaddr for the common case where
86 + * the address is a syscall argument in a variable of type abi_long,
87 + * which may be smaller than the vaddr type. If you pass an address in
88 + * an abi_long to these functions then the value will be converted to
89 + * an unsigned type and then zero extended to give the vaddr. If you
90 + * use the g2h_vaddr() and similar functions which take an argument of
91 + * type vaddr, then the value will be sign-extended, giving the wrong
92 + * answer for addresses above the 2GB mark on 32-bit guests.
93 + *
94 + * Providing these functions with their traditional QEMU semantics is
95 + * less bug-prone than requiring many callsites to remember to cast
96 + * their abi_long variable to an abi_ptr before calling.
97 + */
98 +
99 +static inline void *g2h(CPUState *cs, abi_ptr x)
100 +{
101 + return g2h_vaddr(cs, x);
102 +}
103 +
104 +static inline void *g2h_untagged(abi_ptr x)
105 +{
106 + return g2h_untagged_vaddr(x);
107 +}
108 +
109 +static inline bool guest_addr_valid_untagged(abi_ptr x)
110 +{
111 + return guest_addr_valid_untagged_vaddr(x);
112 +}
113 +
114 +static inline bool guest_range_valid_untagged(abi_ptr start, abi_ptr len)
115 +{
116 + return guest_range_valid_untagged_vaddr(start, len);
117 +}
118 +
119 +static inline abi_ptr cpu_untagged_addr(CPUState *cs, abi_ptr x)
120 +{
121 + return cpu_untagged_addr_vaddr(cs, x);
122 +}
123 +
124 +#endif
125 +
126 #endif