diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index aa8af52cc3..06016eb030 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -800,7 +800,7 @@ static int probe_access_internal(CPUArchState *env, vaddr addr, if (guest_addr_valid_untagged(addr)) { int page_flags = page_get_flags(addr); if (page_flags & acc_flag) { - if ((acc_flag == PAGE_READ || acc_flag == PAGE_WRITE) + if (access_type != MMU_INST_FETCH && cpu_plugin_mem_cbs_enabled(env_cpu(env))) { return TLB_MMIO; } diff --git a/cpu-common.c b/cpu-common.c index 6b262233a3..0d607bbe49 100644 --- a/cpu-common.c +++ b/cpu-common.c @@ -194,6 +194,9 @@ void start_exclusive(void) CPUState *other_cpu; int running_cpus; + /* Ensure we are not running, or start_exclusive will be blocked. */ + g_assert(!current_cpu->running); + if (current_cpu->exclusive_context_count) { current_cpu->exclusive_context_count++; return; diff --git a/linux-user/aarch64/Makefile.vdso b/linux-user/aarch64/Makefile.vdso index 599958116b..c33a679c0f 100644 --- a/linux-user/aarch64/Makefile.vdso +++ b/linux-user/aarch64/Makefile.vdso @@ -5,8 +5,9 @@ VPATH += $(SUBDIR) all: $(SUBDIR)/vdso-be.so $(SUBDIR)/vdso-le.so -LDFLAGS = -nostdlib -shared -Wl,-h,linux-vdso.so.1 -Wl,--build-id=sha1 \ - -Wl,--hash-style=both -Wl,-T,$(SUBDIR)/vdso.ld +LDFLAGS = -nostdlib -shared -Wl,-h,linux-vdso.so.1 \ + -Wl,--build-id=sha1 -Wl,--hash-style=both \ + -Wl,-z,max-page-size=4096 -Wl,-T,$(SUBDIR)/vdso.ld $(SUBDIR)/vdso-be.so: vdso.S vdso.ld $(CC) -o $@ $(LDFLAGS) -mbig-endian $< diff --git a/linux-user/aarch64/vdso-be.so b/linux-user/aarch64/vdso-be.so index 808206ade8..d43c3b19cd 100755 Binary files a/linux-user/aarch64/vdso-be.so and b/linux-user/aarch64/vdso-be.so differ diff --git a/linux-user/aarch64/vdso-le.so b/linux-user/aarch64/vdso-le.so index 941aaf2993..aaedc9d85e 100755 Binary files a/linux-user/aarch64/vdso-le.so and b/linux-user/aarch64/vdso-le.so differ diff --git a/linux-user/arm/Makefile.vdso b/linux-user/arm/Makefile.vdso index 2d098a5748..ede489e236 100644 --- a/linux-user/arm/Makefile.vdso +++ b/linux-user/arm/Makefile.vdso @@ -3,15 +3,18 @@ include $(BUILD_DIR)/tests/tcg/arm-linux-user/config-target.mak SUBDIR = $(SRC_PATH)/linux-user/arm VPATH += $(SUBDIR) -all: $(SUBDIR)/vdso-be.so $(SUBDIR)/vdso-le.so +all: $(SUBDIR)/vdso-be8.so $(SUBDIR)/vdso-be32.so $(SUBDIR)/vdso-le.so # Adding -use-blx disables unneeded interworking without actually using blx. -LDFLAGS = -nostdlib -shared -Wl,-use-blx \ +LDFLAGS = -nostdlib -shared -Wl,-use-blx -Wl,-z,max-page-size=4096 \ -Wl,-h,linux-vdso.so.1 -Wl,--build-id=sha1 \ -Wl,--hash-style=both -Wl,-T,$(SUBDIR)/vdso.ld -$(SUBDIR)/vdso-be.so: vdso.S vdso.ld vdso-asmoffset.h - $(CC) -o $@ $(LDFLAGS) -mbig-endian $< +$(SUBDIR)/vdso-be8.so: vdso.S vdso.ld vdso-asmoffset.h + $(CC) -o $@ $(LDFLAGS) -mbig-endian -mbe8 $< + +$(SUBDIR)/vdso-be32.so: vdso.S vdso.ld vdso-asmoffset.h + $(CC) -o $@ $(LDFLAGS) -mbig-endian -mbe32 $< $(SUBDIR)/vdso-le.so: vdso.S vdso.ld vdso-asmoffset.h $(CC) -o $@ $(LDFLAGS) -mlittle-endian $< diff --git a/linux-user/arm/meson.build b/linux-user/arm/meson.build index c4bb9af5b8..348ffb810d 100644 --- a/linux-user/arm/meson.build +++ b/linux-user/arm/meson.build @@ -10,10 +10,17 @@ syscall_nr_generators += { # is always true as far as source_set.apply() is concerned. Always build # both header files and include the right one via #if. -vdso_be_inc = gen_vdso.process('vdso-be.so', - extra_args: ['-s', 'sigreturn_codes']) +vdso_be8_inc = gen_vdso.process('vdso-be8.so', + extra_args: ['-s', 'sigreturn_codes', + '-p', 'vdso_be8']) + +vdso_be32_inc = gen_vdso.process('vdso-be32.so', + extra_args: ['-s', 'sigreturn_codes', + '-p', 'vdso_be32']) vdso_le_inc = gen_vdso.process('vdso-le.so', extra_args: ['-s', 'sigreturn_codes']) -linux_user_ss.add(when: 'TARGET_ARM', if_true: [vdso_be_inc, vdso_le_inc]) +linux_user_ss.add(when: 'TARGET_ARM', if_true: [ + vdso_be8_inc, vdso_be32_inc, vdso_le_inc +]) diff --git a/linux-user/arm/vdso-be32.so b/linux-user/arm/vdso-be32.so new file mode 100755 index 0000000000..b896d3d545 Binary files /dev/null and b/linux-user/arm/vdso-be32.so differ diff --git a/linux-user/arm/vdso-be.so b/linux-user/arm/vdso-be8.so similarity index 90% rename from linux-user/arm/vdso-be.so rename to linux-user/arm/vdso-be8.so index 69cafbb956..784b7bdb2a 100755 Binary files a/linux-user/arm/vdso-be.so and b/linux-user/arm/vdso-be8.so differ diff --git a/linux-user/arm/vdso-le.so b/linux-user/arm/vdso-le.so index ad05a12518..38d3d51047 100755 Binary files a/linux-user/arm/vdso-le.so and b/linux-user/arm/vdso-le.so differ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 6cef8db3b5..471a384b22 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -659,6 +659,23 @@ static const char *get_elf_platform(void) #undef END } +#if TARGET_BIG_ENDIAN +#include "elf.h" +#include "vdso-be8.c.inc" +#include "vdso-be32.c.inc" + +static const VdsoImageInfo *vdso_image_info(uint32_t elf_flags) +{ + return (EF_ARM_EABI_VERSION(elf_flags) >= EF_ARM_EABI_VER4 + && (elf_flags & EF_ARM_BE8) + ? &vdso_be8_image_info + : &vdso_be32_image_info); +} +#define vdso_image_info vdso_image_info +#else +# define VDSO_HEADER "vdso-le.c.inc" +#endif + #else /* 64 bit ARM definitions */ @@ -958,14 +975,14 @@ const char *elf_hwcap2_str(uint32_t bit) #undef GET_FEATURE_ID -#endif /* not TARGET_AARCH64 */ - #if TARGET_BIG_ENDIAN # define VDSO_HEADER "vdso-be.c.inc" #else # define VDSO_HEADER "vdso-le.c.inc" #endif +#endif /* not TARGET_AARCH64 */ + #endif /* TARGET_ARM */ #ifdef TARGET_SPARC @@ -2898,7 +2915,7 @@ static uintptr_t pgb_try_itree(const PGBAddrs *ga, uintptr_t base, static uintptr_t pgb_find_itree(const PGBAddrs *ga, IntervalTreeRoot *root, uintptr_t align, uintptr_t brk) { - uintptr_t last = mmap_min_addr; + uintptr_t last = sizeof(uintptr_t) == 4 ? MiB : GiB; uintptr_t base, skip; while (true) { @@ -3179,7 +3196,8 @@ static void load_elf_image(const char *image_name, const ImageSource *src, char **pinterp_name) { g_autofree struct elf_phdr *phdr = NULL; - abi_ulong load_addr, load_bias, loaddr, hiaddr, error; + abi_ulong load_addr, load_bias, loaddr, hiaddr, error, align; + size_t reserve_size, align_size; int i, prot_exec; Error *err = NULL; @@ -3219,7 +3237,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src, * amount of memory to handle that. Locate the interpreter, if any. */ loaddr = -1, hiaddr = 0; - info->alignment = 0; + align = 0; info->exec_stack = EXSTACK_DEFAULT; for (i = 0; i < ehdr->e_phnum; ++i) { struct elf_phdr *eppnt = phdr + i; @@ -3233,7 +3251,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src, hiaddr = a; } ++info->nsegs; - info->alignment |= eppnt->p_align; + align |= eppnt->p_align; } else if (eppnt->p_type == PT_INTERP && pinterp_name) { g_autofree char *interp_name = NULL; @@ -3263,6 +3281,8 @@ static void load_elf_image(const char *image_name, const ImageSource *src, load_addr = loaddr; + align = pow2ceil(align); + if (pinterp_name != NULL) { if (ehdr->e_type == ET_EXEC) { /* @@ -3271,8 +3291,6 @@ static void load_elf_image(const char *image_name, const ImageSource *src, */ probe_guest_base(image_name, loaddr, hiaddr); } else { - abi_ulong align; - /* * The binary is dynamic, but we still need to * select guest_base. In this case we pass a size. @@ -3290,10 +3308,7 @@ static void load_elf_image(const char *image_name, const ImageSource *src, * Since we do not have complete control over the guest * address space, we prefer the kernel to choose some address * rather than force the use of LOAD_ADDR via MAP_FIXED. - * But without MAP_FIXED we cannot guarantee alignment, - * only suggest it. */ - align = pow2ceil(info->alignment); if (align) { load_addr &= -align; } @@ -3317,13 +3332,35 @@ static void load_elf_image(const char *image_name, const ImageSource *src, * In both cases, we will overwrite pages in this range with mappings * from the executable. */ - load_addr = target_mmap(load_addr, (size_t)hiaddr - loaddr + 1, PROT_NONE, + reserve_size = (size_t)hiaddr - loaddr + 1; + align_size = reserve_size; + + if (ehdr->e_type != ET_EXEC && align > qemu_real_host_page_size()) { + align_size += align - 1; + } + + load_addr = target_mmap(load_addr, align_size, PROT_NONE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE | (ehdr->e_type == ET_EXEC ? MAP_FIXED_NOREPLACE : 0), -1, 0); if (load_addr == -1) { goto exit_mmap; } + + if (align_size != reserve_size) { + abi_ulong align_addr = ROUND_UP(load_addr, align); + abi_ulong align_end = align_addr + reserve_size; + abi_ulong load_end = load_addr + align_size; + + if (align_addr != load_addr) { + target_munmap(load_addr, align_addr - load_addr); + } + if (align_end != load_end) { + target_munmap(align_end, load_end - align_end); + } + load_addr = align_addr; + } + load_bias = load_addr - loaddr; if (elf_is_fdpic(ehdr)) { @@ -3504,12 +3541,14 @@ static void load_elf_interp(const char *filename, struct image_info *info, load_elf_image(filename, &src, info, &ehdr, NULL); } +#ifndef vdso_image_info #ifdef VDSO_HEADER #include VDSO_HEADER -#define vdso_image_info() &vdso_image_info +#define vdso_image_info(flags) &vdso_image_info #else -#define vdso_image_info() NULL -#endif +#define vdso_image_info(flags) NULL +#endif /* VDSO_HEADER */ +#endif /* vdso_image_info */ static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso) { @@ -3840,7 +3879,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info) * Load a vdso if available, which will amongst other things contain the * signal trampolines. Otherwise, allocate a separate page for them. */ - const VdsoImageInfo *vdso = vdso_image_info(); + const VdsoImageInfo *vdso = vdso_image_info(info->elf_flags); if (vdso) { load_elf_vdso(&vdso_info, vdso); info->vdso = vdso_info.load_bias; diff --git a/linux-user/loongarch64/Makefile.vdso b/linux-user/loongarch64/Makefile.vdso index 369de13344..1d760b1e47 100644 --- a/linux-user/loongarch64/Makefile.vdso +++ b/linux-user/loongarch64/Makefile.vdso @@ -8,4 +8,5 @@ all: $(SUBDIR)/vdso.so $(SUBDIR)/vdso.so: vdso.S vdso.ld vdso-asmoffset.h $(CC) -o $@ -nostdlib -shared -fpic -Wl,-h,linux-vdso.so.1 \ -Wl,--build-id=sha1 -Wl,--hash-style=both \ - -Wl,--no-warn-rwx-segments -Wl,-T,$(SUBDIR)/vdso.ld $< + -Wl,--no-warn-rwx-segments -Wl,-z,max-page-size=4096 \ + -Wl,-T,$(SUBDIR)/vdso.ld $< diff --git a/linux-user/loongarch64/vdso.so b/linux-user/loongarch64/vdso.so index bfaa26f2bf..7c2de6c50e 100755 Binary files a/linux-user/loongarch64/vdso.so and b/linux-user/loongarch64/vdso.so differ diff --git a/linux-user/ppc/Makefile.vdso b/linux-user/ppc/Makefile.vdso index 3ca3c6b83e..e2b8facbb5 100644 --- a/linux-user/ppc/Makefile.vdso +++ b/linux-user/ppc/Makefile.vdso @@ -6,9 +6,11 @@ VPATH += $(SUBDIR) all: $(SUBDIR)/vdso-32.so $(SUBDIR)/vdso-64.so $(SUBDIR)/vdso-64le.so LDFLAGS32 = -nostdlib -shared -Wl,-T,$(SUBDIR)/vdso-32.ld \ - -Wl,-h,linux-vdso32.so.1 -Wl,--hash-style=both -Wl,--build-id=sha1 + -Wl,-h,linux-vdso32.so.1 -Wl,--hash-style=both \ + -Wl,--build-id=sha1 -Wl,-z,max-page-size=4096 LDFLAGS64 = -nostdlib -shared -Wl,-T,$(SUBDIR)/vdso-64.ld \ - -Wl,-h,linux-vdso64.so.1 -Wl,--hash-style=both -Wl,--build-id=sha1 + -Wl,-h,linux-vdso64.so.1 -Wl,--hash-style=both \ + -Wl,--build-id=sha1 -Wl,-z,max-page-size=4096 $(SUBDIR)/vdso-32.so: vdso.S vdso-32.ld vdso-asmoffset.h $(CC) -o $@ $(LDFLAGS32) -m32 $< diff --git a/linux-user/ppc/vdso-32.so b/linux-user/ppc/vdso-32.so index b19baafb0d..0dc55e0ddd 100755 Binary files a/linux-user/ppc/vdso-32.so and b/linux-user/ppc/vdso-32.so differ diff --git a/linux-user/ppc/vdso-64.so b/linux-user/ppc/vdso-64.so index 913c831b38..ac1ab2582e 100755 Binary files a/linux-user/ppc/vdso-64.so and b/linux-user/ppc/vdso-64.so differ diff --git a/linux-user/ppc/vdso-64le.so b/linux-user/ppc/vdso-64le.so index 258a03b807..424abb4290 100755 Binary files a/linux-user/ppc/vdso-64le.so and b/linux-user/ppc/vdso-64le.so differ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 895bdd722a..67bc81b149 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -44,7 +44,6 @@ struct image_info { abi_ulong file_string; uint32_t elf_flags; int personality; - abi_ulong alignment; bool exec_stack; /* Generic semihosting knows about these pointers. */ diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 59b2080b98..0279f23576 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -7233,12 +7233,24 @@ static inline int tswapid(int id) #else #define __NR_sys_setgroups __NR_setgroups #endif +#ifdef __NR_sys_setreuid32 +#define __NR_sys_setreuid __NR_setreuid32 +#else +#define __NR_sys_setreuid __NR_setreuid +#endif +#ifdef __NR_sys_setregid32 +#define __NR_sys_setregid __NR_setregid32 +#else +#define __NR_sys_setregid __NR_setregid +#endif _syscall1(int, sys_setuid, uid_t, uid) _syscall1(int, sys_setgid, gid_t, gid) _syscall3(int, sys_setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) _syscall3(int, sys_setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) _syscall2(int, sys_setgroups, int, size, gid_t *, grouplist) +_syscall2(int, sys_setreuid, uid_t, ruid, uid_t, euid); +_syscall2(int, sys_setregid, gid_t, rgid, gid_t, egid); void syscall_init(void) { @@ -11932,9 +11944,9 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, return get_errno(high2lowgid(getegid())); #endif case TARGET_NR_setreuid: - return get_errno(setreuid(low2highuid(arg1), low2highuid(arg2))); + return get_errno(sys_setreuid(low2highuid(arg1), low2highuid(arg2))); case TARGET_NR_setregid: - return get_errno(setregid(low2highgid(arg1), low2highgid(arg2))); + return get_errno(sys_setregid(low2highgid(arg1), low2highgid(arg2))); case TARGET_NR_getgroups: { /* the same code as for TARGET_NR_getgroups32 */ int gidsetsize = arg1; @@ -12264,11 +12276,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_setreuid32 case TARGET_NR_setreuid32: - return get_errno(setreuid(arg1, arg2)); + return get_errno(sys_setreuid(arg1, arg2)); #endif #ifdef TARGET_NR_setregid32 case TARGET_NR_setregid32: - return get_errno(setregid(arg1, arg2)); + return get_errno(sys_setregid(arg1, arg2)); #endif #ifdef TARGET_NR_getgroups32 case TARGET_NR_getgroups32: diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index f1ee0e060f..904296705c 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -6317,9 +6317,6 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, flags = info.page[0].flags | info.page[1].flags; if (unlikely(flags != 0)) { -#ifdef CONFIG_USER_ONLY - g_assert_not_reached(); -#else /* * At least one page includes MMIO. * Any bus operation can fail with cpu_transaction_failed, @@ -6350,7 +6347,6 @@ void sve_stN_r(CPUARMState *env, uint64_t *vg, target_ulong addr, } while (reg_off & 63); } while (reg_off <= reg_last); return; -#endif } mem_off = info.mem_off_first[0]; diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c index 02d3486421..b1f40040f8 100644 --- a/target/i386/tcg/sysemu/excp_helper.c +++ b/target/i386/tcg/sysemu/excp_helper.c @@ -107,6 +107,10 @@ static bool ptw_setl_slow(const PTETranslate *in, uint32_t old, uint32_t new) { uint32_t cmp; + CPUState *cpu = env_cpu(in->env); + /* We are in cpu_exec, and start_exclusive can't be called directly.*/ + g_assert(cpu->running); + cpu_exec_end(cpu); /* Does x86 really perform a rmw cycle on mmio for ptw? */ start_exclusive(); cmp = cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0); @@ -114,6 +118,7 @@ static bool ptw_setl_slow(const PTETranslate *in, uint32_t old, uint32_t new) cpu_stl_mmuidx_ra(in->env, in->gaddr, new, in->ptw_idx, 0); } end_exclusive(); + cpu_exec_start(cpu); return cmp == old; } diff --git a/tcg/tcg-op-gvec.c b/tcg/tcg-op-gvec.c index 78ee1ced80..97e4df221a 100644 --- a/tcg/tcg-op-gvec.c +++ b/tcg/tcg-op-gvec.c @@ -88,7 +88,20 @@ uint32_t simd_desc(uint32_t oprsz, uint32_t maxsz, int32_t data) uint32_t desc = 0; check_size_align(oprsz, maxsz, 0); - tcg_debug_assert(data == sextract32(data, 0, SIMD_DATA_BITS)); + + /* + * We want to check that 'data' will fit into SIMD_DATA_BITS. + * However, some callers want to treat the data as a signed + * value (which they can later get back with simd_data()) + * and some want to treat it as an unsigned value. + * So here we assert only that the data will fit into the + * field in at least one way. This means that some invalid + * values from the caller will not be detected, e.g. if the + * caller wants to handle the value as a signed integer but + * incorrectly passes us 1 << (SIMD_DATA_BITS - 1). + */ + tcg_debug_assert(data == sextract32(data, 0, SIMD_DATA_BITS) || + data == extract32(data, 0, SIMD_DATA_BITS)); oprsz = (oprsz / 8) - 1; maxsz = (maxsz / 8) - 1; diff --git a/tests/tcg/multiarch/Makefile.target b/tests/tcg/multiarch/Makefile.target index 78b83d5575..18d3cf4ae0 100644 --- a/tests/tcg/multiarch/Makefile.target +++ b/tests/tcg/multiarch/Makefile.target @@ -42,6 +42,9 @@ munmap-pthread: LDFLAGS+=-pthread vma-pthread: CFLAGS+=-pthread vma-pthread: LDFLAGS+=-pthread +sigreturn-sigmask: CFLAGS+=-pthread +sigreturn-sigmask: LDFLAGS+=-pthread + # The vma-pthread seems very sensitive on gitlab and we currently # don't know if its exposing a real bug or the test is flaky. ifneq ($(GITLAB_CI),) diff --git a/tests/tcg/multiarch/sigreturn-sigmask.c b/tests/tcg/multiarch/sigreturn-sigmask.c new file mode 100644 index 0000000000..e6cc904898 --- /dev/null +++ b/tests/tcg/multiarch/sigreturn-sigmask.c @@ -0,0 +1,51 @@ +/* + * Test that sigreturn() does not corrupt the signal mask. + * Block SIGUSR2 and handle SIGUSR1. + * Then sigwait() SIGUSR2, which relies on it remaining blocked. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include +#include +#include +#include +#include + +int seen_sig = -1; + +static void signal_func(int sig) +{ + seen_sig = sig; +} + +static void *thread_func(void *arg) +{ + kill(getpid(), SIGUSR2); + return NULL; +} + +int main(void) +{ + struct sigaction act = { + .sa_handler = signal_func, + }; + pthread_t thread; + sigset_t set; + int sig; + + assert(sigaction(SIGUSR1, &act, NULL) == 0); + + assert(sigemptyset(&set) == 0); + assert(sigaddset(&set, SIGUSR2) == 0); + assert(sigprocmask(SIG_BLOCK, &set, NULL) == 0); + + kill(getpid(), SIGUSR1); + assert(seen_sig == SIGUSR1); + + assert(pthread_create(&thread, NULL, thread_func, NULL) == 0); + assert(sigwait(&set, &sig) == 0); + assert(sig == SIGUSR2); + assert(pthread_join(thread, NULL) == 0); + + return EXIT_SUCCESS; +}