Skip to content

Commit

Permalink
Merge tag 'pull-lu-20231030' of https://gitlab.com/rth7680/qemu into …
Browse files Browse the repository at this point in the history
…staging

linux-user: Fix guest signal remapping after adjusting SIGABRT
linux-user: Implement VDSOs

* tag 'pull-lu-20231030' of https://gitlab.com/rth7680/qemu: (21 commits)
  build: Add update-linux-vdso makefile rule
  linux-user: Show vdso address in /proc/pid/maps
  linux-user/s390x: Add vdso
  linux-user/s390x: Rename __SIGNAL_FRAMESIZE to STACK_FRAME_OVERHEAD
  linux-user/ppc: Add vdso
  linux-user/loongarch64: Add vdso
  linux-user/riscv: Add vdso
  linux-user/hppa: Add vdso
  linux-user/arm: Add vdso
  linux-user/aarch64: Add vdso
  linux-user/x86_64: Add vdso
  linux-user/i386: Add vdso
  linux-user: Add gen-vdso tool
  linux-user: Load vdso image if available
  linux-user: Replace bprm->fd with bprm->src.fd
  linux-user: Use ImageSource in load_symbols
  linux-user: Use ImageSource in load_elf_image
  linux-user: Do not clobber bprm_buf swapping ehdr
  linux-user: Tidy loader_exec
  linux-user: Introduce imgsrc_read, imgsrc_read_alloc
  ...

Conflicts:
  linux-user/arm/signal.c
  Fix an #include context conflict.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
  • Loading branch information
stefanhaRH committed Oct 30, 2023
2 parents 235fe6d + 335b8f7 commit 516fffc
Show file tree
Hide file tree
Showing 76 changed files with 3,278 additions and 211 deletions.
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,13 @@ include $(SRC_PATH)/tests/vm/Makefile.include
print-help-run = printf " %-30s - %s\\n" "$1" "$2"
print-help = @$(call print-help-run,$1,$2)

.PHONY: update-linux-vdso
update-linux-vdso:
@for m in $(SRC_PATH)/linux-user/*/Makefile.vdso; do \
$(MAKE) $(SUBDIR_MAKEFLAGS) -C $$(dirname $$m) -f Makefile.vdso \
SRC_PATH=$(SRC_PATH) BUILD_DIR=$(BUILD_DIR); \
done

.PHONY: help
help:
@echo 'Generic targets:'
Expand All @@ -303,6 +310,9 @@ endif
$(call print-help,distclean,Remove all generated files)
$(call print-help,dist,Build a distributable tarball)
@echo ''
@echo 'Linux-user targets:'
$(call print-help,update-linux-vdso,Build linux-user vdso images)
@echo ''
@echo 'Test targets:'
$(call print-help,check,Run all tests (check-help for details))
$(call print-help,bench,Run all benchmarks)
Expand Down
15 changes: 15 additions & 0 deletions linux-user/aarch64/Makefile.vdso
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
include $(BUILD_DIR)/tests/tcg/aarch64-linux-user/config-target.mak

SUBDIR = $(SRC_PATH)/linux-user/aarch64
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

$(SUBDIR)/vdso-be.so: vdso.S vdso.ld
$(CC) -o $@ $(LDFLAGS) -mbig-endian $<

$(SUBDIR)/vdso-le.so: vdso.S vdso.ld
$(CC) -o $@ $(LDFLAGS) -mlittle-endian $<
11 changes: 11 additions & 0 deletions linux-user/aarch64/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# TARGET_BIG_ENDIAN is defined to 'n' for little-endian; which means it
# 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: ['-r', '__kernel_rt_sigreturn'])

vdso_le_inc = gen_vdso.process('vdso-le.so',
extra_args: ['-r', '__kernel_rt_sigreturn'])

linux_user_ss.add(when: 'TARGET_AARCH64', if_true: [vdso_be_inc, vdso_le_inc])
Binary file added linux-user/aarch64/vdso-be.so
Binary file not shown.
Binary file added linux-user/aarch64/vdso-le.so
Binary file not shown.
71 changes: 71 additions & 0 deletions linux-user/aarch64/vdso.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* aarch64 linux replacement vdso.
*
* Copyright 2023 Linaro, Ltd.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/

#include <asm/unistd.h>

/* ??? These are in include/elf.h, which is not ready for inclusion in asm. */
#define NT_GNU_PROPERTY_TYPE_0 5
#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI (1U << 0)
#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC (1U << 1)

#define GNU_PROPERTY_AARCH64_FEATURE_1_DEFAULT \
(GNU_PROPERTY_AARCH64_FEATURE_1_BTI | GNU_PROPERTY_AARCH64_FEATURE_1_PAC)

.section .note.gnu.property
.align 3
.long 2f - 1f
.long 6f - 3f
.long NT_GNU_PROPERTY_TYPE_0
1: .string "GNU"
2: .align 3
3: .long GNU_PROPERTY_AARCH64_FEATURE_1_AND
.long 5f - 4f
4: .long GNU_PROPERTY_AARCH64_FEATURE_1_DEFAULT
5: .align 3
6:

.text

.macro endf name
.globl \name
.type \name, @function
.size \name, . - \name
.endm

.macro vdso_syscall name, nr
\name:
bti c
mov x8, #\nr
svc #0
ret
endf \name
.endm

.cfi_startproc

vdso_syscall __kernel_gettimeofday, __NR_gettimeofday
vdso_syscall __kernel_clock_gettime, __NR_clock_gettime
vdso_syscall __kernel_clock_getres, __NR_clock_getres

.cfi_endproc


/*
* TODO: The kernel makes a big deal of turning off the .cfi directives,
* because they cause libgcc to crash, but that's because they're wrong.
*
* For now, elide the unwind info for __kernel_rt_sigreturn and rely on
* the libgcc fallback routine as we have always done. This requires
* that the code sequence used be exact.
*/
__kernel_rt_sigreturn:
/* No BTI C insn here -- we arrive via RET. */
mov x8, #__NR_rt_sigreturn
svc #0
endf __kernel_rt_sigreturn
72 changes: 72 additions & 0 deletions linux-user/aarch64/vdso.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Linker script for linux aarch64 replacement vdso.
*
* Copyright 2021 Linaro, Ltd.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/

VERSION {
LINUX_2.6.39 {
global:
__kernel_rt_sigreturn;
__kernel_gettimeofday;
__kernel_clock_gettime;
__kernel_clock_getres;

local: *;
};
}


PHDRS {
phdr PT_PHDR FLAGS(4) PHDRS;
load PT_LOAD FLAGS(7) FILEHDR PHDRS;
dynamic PT_DYNAMIC FLAGS(4);
eh_frame_hdr PT_GNU_EH_FRAME;
note PT_NOTE FLAGS(4);
}

SECTIONS {
/*
* We can't prelink to any address without knowing something about
* the virtual memory space of the host, since that leaks over into
* the available memory space of the guest.
*/
. = SIZEOF_HEADERS;

/*
* The following, including the FILEHDRS and PHDRS, are modified
* when we relocate the binary. We want them to be initially
* writable for the relocation; we'll force them read-only after.
*/
.note : { *(.note*) } :load :note
.dynamic : { *(.dynamic) } :load :dynamic
.dynsym : { *(.dynsym) } :load
/*
* There ought not be any real read-write data.
* But since we manipulated the segment layout,
* we have to put these sections somewhere.
*/
.data : {
*(.data*)
*(.sdata*)
*(.got.plt) *(.got)
*(.gnu.linkonce.d.*)
*(.bss*)
*(.dynbss*)
*(.gnu.linkonce.b.*)
}

.rodata : { *(.rodata*) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.eh_frame_hdr : { *(.eh_frame_hdr) } :load :eh_frame_hdr
.eh_frame : { *(.eh_frame) } :load

.text : { *(.text*) } :load =0xd503201f
}
17 changes: 17 additions & 0 deletions linux-user/arm/Makefile.vdso
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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

# Adding -use-blx disables unneeded interworking without actually using blx.
LDFLAGS = -nostdlib -shared -Wl,-use-blx \
-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-le.so: vdso.S vdso.ld vdso-asmoffset.h
$(CC) -o $@ $(LDFLAGS) -mlittle-endian $<
12 changes: 12 additions & 0 deletions linux-user/arm/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,15 @@ syscall_nr_generators += {
arguments: [ meson.current_source_dir() / 'syscallhdr.sh', '@INPUT@', '@OUTPUT@', '@EXTRA_ARGS@' ],
output: '@BASENAME@_nr.h')
}

# TARGET_BIG_ENDIAN is defined to 'n' for little-endian; which means it
# 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_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])
49 changes: 32 additions & 17 deletions linux-user/arm/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "signal-common.h"
#include "linux-user/trace.h"
#include "target/arm/cpu-features.h"
#include "vdso-asmoffset.h"

struct target_sigcontext {
abi_ulong trap_no;
Expand Down Expand Up @@ -103,6 +104,11 @@ struct rt_sigframe
struct sigframe sig;
};

QEMU_BUILD_BUG_ON(offsetof(struct sigframe, retcode[3])
!= SIGFRAME_RC3_OFFSET);
QEMU_BUILD_BUG_ON(offsetof(struct rt_sigframe, sig.retcode[3])
!= RT_SIGFRAME_RC3_OFFSET);

static abi_ptr sigreturn_fdpic_tramp;

/*
Expand Down Expand Up @@ -161,16 +167,19 @@ get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
return (sp - framesize) & ~7;
}

static void write_arm_sigreturn(uint32_t *rc, int syscall);
static void write_arm_fdpic_sigreturn(uint32_t *rc, int ofs);

static int
setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
struct sigframe *frame, abi_ulong sp_addr)
{
abi_ulong handler = 0;
abi_ulong handler_fdpic_GOT = 0;
abi_ulong retcode;
int thumb, retcode_idx;
int is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
bool copy_retcode;
bool is_fdpic = info_is_fdpic(((TaskState *)thread_cpu->opaque)->info);
bool is_rt = ka->sa_flags & TARGET_SA_SIGINFO;
bool thumb;

if (is_fdpic) {
/* In FDPIC mode, ka->_sa_handler points to a function
Expand All @@ -185,9 +194,7 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
} else {
handler = ka->_sa_handler;
}

thumb = handler & 1;
retcode_idx = thumb + (ka->sa_flags & TARGET_SA_SIGINFO ? 2 : 0);

uint32_t cpsr = cpsr_read(env);

Expand All @@ -203,24 +210,32 @@ setup_return(CPUARMState *env, struct target_sigaction *ka, int usig,
cpsr &= ~CPSR_E;
}

/* Our vdso default_sigreturn label is a table of entry points. */
retcode = default_sigreturn + (is_fdpic * 2 + is_rt) * 8;

/*
* Put the sigreturn code on the stack no matter which return
* mechanism we use in order to remain ABI compliant.
* Because this is about ABI, always use the A32 instructions,
* despite the fact that our actual vdso trampoline is T16.
*/
if (is_fdpic) {
write_arm_fdpic_sigreturn(frame->retcode,
is_rt ? RT_SIGFRAME_RC3_OFFSET
: SIGFRAME_RC3_OFFSET);
} else {
write_arm_sigreturn(frame->retcode,
is_rt ? TARGET_NR_rt_sigreturn
: TARGET_NR_sigreturn);
}

if (ka->sa_flags & TARGET_SA_RESTORER) {
if (is_fdpic) {
/* Place the function descriptor in slot 3. */
__put_user((abi_ulong)ka->sa_restorer, &frame->retcode[3]);
retcode = (sigreturn_fdpic_tramp +
retcode_idx * RETCODE_BYTES + thumb);
copy_retcode = true;
} else {
retcode = ka->sa_restorer;
copy_retcode = false;
}
} else {
retcode = default_sigreturn + retcode_idx * RETCODE_BYTES + thumb;
copy_retcode = true;
}

/* Copy the code to the stack slot for ABI compatibility. */
if (copy_retcode) {
memcpy(frame->retcode, g2h_untagged(retcode & ~1), RETCODE_BYTES);
}

env->regs[0] = usig;
Expand Down
3 changes: 3 additions & 0 deletions linux-user/arm/vdso-asmoffset.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* offsetof(struct sigframe, retcode[3]) */
#define SIGFRAME_RC3_OFFSET 756
#define RT_SIGFRAME_RC3_OFFSET 884
Binary file added linux-user/arm/vdso-be.so
Binary file not shown.
Binary file added linux-user/arm/vdso-le.so
Binary file not shown.

0 comments on commit 516fffc

Please sign in to comment.