linux-user: Fix guest signal remapping after adjusting SIGABRT

linux-user: Implement VDSOs
 -----BEGIN PGP SIGNATURE-----
 
 iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmVAHMsdHHJpY2hhcmQu
 aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV/GSgf/SiaCzl7FV2NsxA2h
 zHrgSYEf/4dyqjbgNhE9XSrIJ/cPEY47JrpMqJ0cK4BGc/d2IppUU0Zz3qZltXck
 CkTIPPXEWDvex+PSe5NXarxQtOazi21C+EySGFtFcCQ32C/LsdJBtNzrB+G/Tl/t
 QvPJBztXvS6FAdVci2TGBNk62nFq3NS/Uz477SD6Q/uSlczQQ5b1fu3YgZcCqM9D
 ncncHbuExUu+NMK02h8vyWwpxaTvUBSdRxx/6jnyctwVpWyMaIOfsrMooz0gBfoD
 Z7MqXhvtBYOnm4OjcQs4Nj1JBOdYoQS/y6dJ7ZP0kg10VSEwr48pduXZSvIypxbw
 hsaa8w==
 =wcWF
 -----END PGP SIGNATURE-----

Merge tag 'pull-lu-20231030' of https://gitlab.com/rth7680/qemu into 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>
This commit is contained in:
Stefan Hajnoczi 2023-10-31 07:12:40 +09:00
commit 516fffc993
76 changed files with 3286 additions and 219 deletions

View file

@ -37,6 +37,19 @@
#undef ELF_ARCH
#endif
#ifndef TARGET_ARCH_HAS_SIGTRAMP_PAGE
#define TARGET_ARCH_HAS_SIGTRAMP_PAGE 0
#endif
typedef struct {
const uint8_t *image;
const uint32_t *relocs;
unsigned image_size;
unsigned reloc_count;
unsigned sigreturn_ofs;
unsigned rt_sigreturn_ofs;
} VdsoImageInfo;
#define ELF_OSABI ELFOSABI_SYSV
/* from personality.h */
@ -296,12 +309,27 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUX86State *en
(*regs)[15] = tswapreg(env->regs[R_ESP]);
(*regs)[16] = tswapreg(env->segs[R_SS].selector & 0xffff);
}
#endif
/*
* i386 is the only target which supplies AT_SYSINFO for the vdso.
* All others only supply AT_SYSINFO_EHDR.
*/
#define DLINFO_ARCH_ITEMS (vdso_info != NULL)
#define ARCH_DLINFO \
do { \
if (vdso_info) { \
NEW_AUX_ENT(AT_SYSINFO, vdso_info->entry); \
} \
} while (0)
#endif /* TARGET_X86_64 */
#define VDSO_HEADER "vdso.c.inc"
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
#endif /* TARGET_I386 */
#ifdef TARGET_ARM
@ -921,6 +949,13 @@ 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 /* TARGET_ARM */
#ifdef TARGET_SPARC
@ -1156,6 +1191,14 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#ifndef TARGET_PPC64
# define VDSO_HEADER "vdso-32.c.inc"
#elif TARGET_BIG_ENDIAN
# define VDSO_HEADER "vdso-64.c.inc"
#else
# define VDSO_HEADER "vdso-64le.c.inc"
#endif
#endif
#ifdef TARGET_LOONGARCH64
@ -1166,6 +1209,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en
#define elf_check_arch(x) ((x) == EM_LOONGARCH)
#define VDSO_HEADER "vdso.c.inc"
static inline void init_thread(struct target_pt_regs *regs,
struct image_info *infop)
{
@ -1853,6 +1898,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#define VDSO_HEADER "vdso.c.inc"
#endif /* TARGET_S390X */
#ifdef TARGET_RISCV
@ -1861,8 +1908,10 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
#ifdef TARGET_RISCV32
#define ELF_CLASS ELFCLASS32
#define VDSO_HEADER "vdso-32.c.inc"
#else
#define ELF_CLASS ELFCLASS64
#define VDSO_HEADER "vdso-64.c.inc"
#endif
#define ELF_HWCAP get_elf_hwcap()
@ -1898,6 +1947,8 @@ static inline void init_thread(struct target_pt_regs *regs,
#define STACK_GROWS_DOWN 0
#define STACK_ALIGNMENT 64
#define VDSO_HEADER "vdso.c.inc"
static inline void init_thread(struct target_pt_regs *regs,
struct image_info *infop)
{
@ -2205,7 +2256,8 @@ static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { }
#ifdef USE_ELF_CORE_DUMP
static int elf_core_dump(int, const CPUArchState *);
#endif /* USE_ELF_CORE_DUMP */
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias);
static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
abi_ulong load_bias);
/* Verify the portions of EHDR within E_IDENT for the target.
This can be performed before bswapping the entire header. */
@ -2474,7 +2526,8 @@ static abi_ulong loader_build_fdpic_loadmap(struct image_info *info, abi_ulong s
static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct elfhdr *exec,
struct image_info *info,
struct image_info *interp_info)
struct image_info *interp_info,
struct image_info *vdso_info)
{
abi_ulong sp;
abi_ulong u_argc, u_argv, u_envp, u_auxv;
@ -2562,10 +2615,15 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
}
size = (DLINFO_ITEMS + 1) * 2;
if (k_base_platform)
if (k_base_platform) {
size += 2;
if (k_platform)
}
if (k_platform) {
size += 2;
}
if (vdso_info) {
size += 2;
}
#ifdef DLINFO_ARCH_ITEMS
size += DLINFO_ARCH_ITEMS * 2;
#endif
@ -2647,6 +2705,9 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
if (u_platform) {
NEW_AUX_ENT(AT_PLATFORM, u_platform);
}
if (vdso_info) {
NEW_AUX_ENT(AT_SYSINFO_EHDR, vdso_info->load_addr);
}
NEW_AUX_ENT (AT_NULL, 0);
#undef NEW_AUX_ENT
@ -3106,10 +3167,9 @@ static bool parse_elf_property(const uint32_t *data, int *off, int datasz,
}
/* Process NT_GNU_PROPERTY_TYPE_0. */
static bool parse_elf_properties(int image_fd,
static bool parse_elf_properties(const ImageSource *src,
struct image_info *info,
const struct elf_phdr *phdr,
char bprm_buf[BPRM_BUF_SIZE],
Error **errp)
{
union {
@ -3137,14 +3197,8 @@ static bool parse_elf_properties(int image_fd,
return false;
}
if (phdr->p_offset + n <= BPRM_BUF_SIZE) {
memcpy(&note, bprm_buf + phdr->p_offset, n);
} else {
ssize_t len = pread(image_fd, &note, n, phdr->p_offset);
if (len != n) {
error_setg_errno(errp, errno, "Error reading file header");
return false;
}
if (!imgsrc_read(&note, phdr->p_offset, n, src, errp)) {
return false;
}
/*
@ -3190,29 +3244,34 @@ static bool parse_elf_properties(int image_fd,
}
}
/* Load an ELF image into the address space.
/**
* load_elf_image: Load an ELF image into the address space.
* @image_name: the filename of the image, to use in error messages.
* @src: the ImageSource from which to read.
* @info: info collected from the loaded image.
* @ehdr: the ELF header, not yet bswapped.
* @pinterp_name: record any PT_INTERP string found.
*
* On return: @info values will be filled in, as necessary or available.
*/
IMAGE_NAME is the filename of the image, to use in error messages.
IMAGE_FD is the open file descriptor for the image.
BPRM_BUF is a copy of the beginning of the file; this of course
contains the elf file header at offset 0. It is assumed that this
buffer is sufficiently aligned to present no problems to the host
in accessing data at aligned offsets within the buffer.
On return: INFO values will be filled in, as necessary or available. */
static void load_elf_image(const char *image_name, int image_fd,
struct image_info *info, char **pinterp_name,
char bprm_buf[BPRM_BUF_SIZE])
static void load_elf_image(const char *image_name, const ImageSource *src,
struct image_info *info, struct elfhdr *ehdr,
char **pinterp_name)
{
struct elfhdr *ehdr = (struct elfhdr *)bprm_buf;
struct elf_phdr *phdr;
g_autofree struct elf_phdr *phdr = NULL;
abi_ulong load_addr, load_bias, loaddr, hiaddr, error;
int i, retval, prot_exec;
int i, prot_exec;
Error *err = NULL;
/* First of all, some simple consistency checks */
/*
* First of all, some simple consistency checks.
* Note that we rely on the bswapped ehdr staying in bprm_buf,
* for later use by load_elf_binary and create_elf_tables.
*/
if (!imgsrc_read(ehdr, 0, sizeof(*ehdr), src, &err)) {
goto exit_errmsg;
}
if (!elf_check_ident(ehdr)) {
error_setg(&err, "Invalid ELF image for this architecture");
goto exit_errmsg;
@ -3223,15 +3282,11 @@ static void load_elf_image(const char *image_name, int image_fd,
goto exit_errmsg;
}
i = ehdr->e_phnum * sizeof(struct elf_phdr);
if (ehdr->e_phoff + i <= BPRM_BUF_SIZE) {
phdr = (struct elf_phdr *)(bprm_buf + ehdr->e_phoff);
} else {
phdr = (struct elf_phdr *) alloca(i);
retval = pread(image_fd, phdr, i, ehdr->e_phoff);
if (retval != i) {
goto exit_read;
}
phdr = imgsrc_read_alloc(ehdr->e_phoff,
ehdr->e_phnum * sizeof(struct elf_phdr),
src, &err);
if (phdr == NULL) {
goto exit_errmsg;
}
bswap_phdr(phdr, ehdr->e_phnum);
@ -3268,17 +3323,10 @@ static void load_elf_image(const char *image_name, int image_fd,
goto exit_errmsg;
}
interp_name = g_malloc(eppnt->p_filesz);
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
memcpy(interp_name, bprm_buf + eppnt->p_offset,
eppnt->p_filesz);
} else {
retval = pread(image_fd, interp_name, eppnt->p_filesz,
eppnt->p_offset);
if (retval != eppnt->p_filesz) {
goto exit_read;
}
interp_name = imgsrc_read_alloc(eppnt->p_offset, eppnt->p_filesz,
src, &err);
if (interp_name == NULL) {
goto exit_errmsg;
}
if (interp_name[eppnt->p_filesz - 1] != 0) {
error_setg(&err, "Invalid PT_INTERP entry");
@ -3286,7 +3334,7 @@ static void load_elf_image(const char *image_name, int image_fd,
}
*pinterp_name = g_steal_pointer(&interp_name);
} else if (eppnt->p_type == PT_GNU_PROPERTY) {
if (!parse_elf_properties(image_fd, info, eppnt, bprm_buf, &err)) {
if (!parse_elf_properties(src, info, eppnt, &err)) {
goto exit_errmsg;
}
} else if (eppnt->p_type == PT_GNU_STACK) {
@ -3439,9 +3487,9 @@ static void load_elf_image(const char *image_name, int image_fd,
* but no backing file segment.
*/
if (eppnt->p_filesz != 0) {
error = target_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
error = imgsrc_mmap(vaddr_ps, eppnt->p_filesz + vaddr_po,
elf_prot, MAP_PRIVATE | MAP_FIXED,
image_fd, eppnt->p_offset - vaddr_po);
src, eppnt->p_offset - vaddr_po);
if (error == -1) {
goto exit_mmap;
}
@ -3473,20 +3521,11 @@ static void load_elf_image(const char *image_name, int image_fd,
#ifdef TARGET_MIPS
} else if (eppnt->p_type == PT_MIPS_ABIFLAGS) {
Mips_elf_abiflags_v0 abiflags;
if (eppnt->p_filesz < sizeof(Mips_elf_abiflags_v0)) {
error_setg(&err, "Invalid PT_MIPS_ABIFLAGS entry");
if (!imgsrc_read(&abiflags, eppnt->p_offset, sizeof(abiflags),
src, &err)) {
goto exit_errmsg;
}
if (eppnt->p_offset + eppnt->p_filesz <= BPRM_BUF_SIZE) {
memcpy(&abiflags, bprm_buf + eppnt->p_offset,
sizeof(Mips_elf_abiflags_v0));
} else {
retval = pread(image_fd, &abiflags, sizeof(Mips_elf_abiflags_v0),
eppnt->p_offset);
if (retval != sizeof(Mips_elf_abiflags_v0)) {
goto exit_read;
}
}
bswap_mips_abiflags(&abiflags);
info->fp_abi = abiflags.fp_abi;
#endif
@ -3499,23 +3538,16 @@ static void load_elf_image(const char *image_name, int image_fd,
}
if (qemu_log_enabled()) {
load_symbols(ehdr, image_fd, load_bias);
load_symbols(ehdr, src, load_bias);
}
debuginfo_report_elf(image_name, image_fd, load_bias);
debuginfo_report_elf(image_name, src->fd, load_bias);
mmap_unlock();
close(image_fd);
close(src->fd);
return;
exit_read:
if (retval >= 0) {
error_setg(&err, "Incomplete read of file header");
} else {
error_setg_errno(&err, errno, "Error reading file header");
}
goto exit_errmsg;
exit_mmap:
error_setg_errno(&err, errno, "Error mapping file");
goto exit_errmsg;
@ -3527,6 +3559,8 @@ static void load_elf_image(const char *image_name, int image_fd,
static void load_elf_interp(const char *filename, struct image_info *info,
char bprm_buf[BPRM_BUF_SIZE])
{
struct elfhdr ehdr;
ImageSource src;
int fd, retval;
Error *err = NULL;
@ -3544,11 +3578,57 @@ static void load_elf_interp(const char *filename, struct image_info *info,
exit(-1);
}
if (retval < BPRM_BUF_SIZE) {
memset(bprm_buf + retval, 0, BPRM_BUF_SIZE - retval);
src.fd = fd;
src.cache = bprm_buf;
src.cache_size = retval;
load_elf_image(filename, &src, info, &ehdr, NULL);
}
#ifdef VDSO_HEADER
#include VDSO_HEADER
#define vdso_image_info() &vdso_image_info
#else
#define vdso_image_info() NULL
#endif
static void load_elf_vdso(struct image_info *info, const VdsoImageInfo *vdso)
{
ImageSource src;
struct elfhdr ehdr;
abi_ulong load_bias, load_addr;
src.fd = -1;
src.cache = vdso->image;
src.cache_size = vdso->image_size;
load_elf_image("<internal-vdso>", &src, info, &ehdr, NULL);
load_addr = info->load_addr;
load_bias = info->load_bias;
/*
* We need to relocate the VDSO image. The one built into the kernel
* is built for a fixed address. The one built for QEMU is not, since
* that requires close control of the guest address space.
* We pre-processed the image to locate all of the addresses that need
* to be updated.
*/
for (unsigned i = 0, n = vdso->reloc_count; i < n; i++) {
abi_ulong *addr = g2h_untagged(load_addr + vdso->relocs[i]);
*addr = tswapal(tswapal(*addr) + load_bias);
}
load_elf_image(filename, fd, info, NULL, bprm_buf);
/* Install signal trampolines, if present. */
if (vdso->sigreturn_ofs) {
default_sigreturn = load_addr + vdso->sigreturn_ofs;
}
if (vdso->rt_sigreturn_ofs) {
default_rt_sigreturn = load_addr + vdso->rt_sigreturn_ofs;
}
/* Remove write from VDSO segment. */
target_mprotect(info->start_data, info->end_data - info->start_data,
PROT_READ | PROT_EXEC);
}
static int symfind(const void *s0, const void *s1)
@ -3595,19 +3675,20 @@ static int symcmp(const void *s0, const void *s1)
}
/* Best attempt to load symbols from this ELF object. */
static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
static void load_symbols(struct elfhdr *hdr, const ImageSource *src,
abi_ulong load_bias)
{
int i, shnum, nsyms, sym_idx = 0, str_idx = 0;
uint64_t segsz;
struct elf_shdr *shdr;
g_autofree struct elf_shdr *shdr = NULL;
char *strings = NULL;
struct syminfo *s = NULL;
struct elf_sym *new_syms, *syms = NULL;
struct elf_sym *syms = NULL;
struct elf_sym *new_syms;
uint64_t segsz;
shnum = hdr->e_shnum;
i = shnum * sizeof(struct elf_shdr);
shdr = (struct elf_shdr *)alloca(i);
if (pread(fd, shdr, i, hdr->e_shoff) != i) {
shdr = imgsrc_read_alloc(hdr->e_shoff, shnum * sizeof(struct elf_shdr),
src, NULL);
if (shdr == NULL) {
return;
}
@ -3625,31 +3706,33 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
found:
/* Now know where the strtab and symtab are. Snarf them. */
s = g_try_new(struct syminfo, 1);
if (!s) {
goto give_up;
}
segsz = shdr[str_idx].sh_size;
s->disas_strtab = strings = g_try_malloc(segsz);
if (!strings ||
pread(fd, strings, segsz, shdr[str_idx].sh_offset) != segsz) {
strings = g_try_malloc(segsz);
if (!strings) {
goto give_up;
}
if (!imgsrc_read(strings, shdr[str_idx].sh_offset, segsz, src, NULL)) {
goto give_up;
}
segsz = shdr[sym_idx].sh_size;
syms = g_try_malloc(segsz);
if (!syms || pread(fd, syms, segsz, shdr[sym_idx].sh_offset) != segsz) {
goto give_up;
}
if (segsz / sizeof(struct elf_sym) > INT_MAX) {
/* Implausibly large symbol table: give up rather than ploughing
* on with the number of symbols calculation overflowing
/*
* Implausibly large symbol table: give up rather than ploughing
* on with the number of symbols calculation overflowing.
*/
goto give_up;
}
nsyms = segsz / sizeof(struct elf_sym);
syms = g_try_malloc(segsz);
if (!syms) {
goto give_up;
}
if (!imgsrc_read(syms, shdr[sym_idx].sh_offset, segsz, src, NULL)) {
goto give_up;
}
for (i = 0; i < nsyms; ) {
bswap_sym(syms + i);
/* Throw away entries which we do not need. */
@ -3674,10 +3757,12 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
goto give_up;
}
/* Attempt to free the storage associated with the local symbols
that we threw away. Whether or not this has any effect on the
memory allocation depends on the malloc implementation and how
many symbols we managed to discard. */
/*
* Attempt to free the storage associated with the local symbols
* that we threw away. Whether or not this has any effect on the
* memory allocation depends on the malloc implementation and how
* many symbols we managed to discard.
*/
new_syms = g_try_renew(struct elf_sym, syms, nsyms);
if (new_syms == NULL) {
goto give_up;
@ -3686,20 +3771,23 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
qsort(syms, nsyms, sizeof(*syms), symcmp);
s->disas_num_syms = nsyms;
#if ELF_CLASS == ELFCLASS32
s->disas_symtab.elf32 = syms;
#else
s->disas_symtab.elf64 = syms;
#endif
s->lookup_symbol = lookup_symbolxx;
s->next = syminfos;
syminfos = s;
{
struct syminfo *s = g_new(struct syminfo, 1);
s->disas_strtab = strings;
s->disas_num_syms = nsyms;
#if ELF_CLASS == ELFCLASS32
s->disas_symtab.elf32 = syms;
#else
s->disas_symtab.elf64 = syms;
#endif
s->lookup_symbol = lookup_symbolxx;
s->next = syminfos;
syminfos = s;
}
return;
give_up:
g_free(s);
give_up:
g_free(strings);
g_free(syms);
}
@ -3741,8 +3829,14 @@ uint32_t get_elf_eflags(int fd)
int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
{
struct image_info interp_info;
struct elfhdr elf_ex;
/*
* We need a copy of the elf header for passing to create_elf_tables.
* We will have overwritten the original when we re-use bprm->buf
* while loading the interpreter. Allocate the storage for this now
* and let elf_load_image do any swapping that may be required.
*/
struct elfhdr ehdr;
struct image_info interp_info, vdso_info;
char *elf_interpreter = NULL;
char *scratch;
@ -3751,13 +3845,7 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
interp_info.fp_abi = MIPS_ABI_FP_UNKNOWN;
#endif
load_elf_image(bprm->filename, bprm->fd, info,
&elf_interpreter, bprm->buf);
/* ??? We need a copy of the elf header for passing to create_elf_tables.
If we do nothing, we'll have overwritten this when we re-use bprm->buf
when we load the interpreter. */
elf_ex = *(struct elfhdr *)bprm->buf;
load_elf_image(bprm->filename, &bprm->src, info, &ehdr, &elf_interpreter);
/* Do this so that we can load the interpreter, if need be. We will
change some of these later */
@ -3829,10 +3917,14 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
}
/*
* TODO: load a vdso, which would also contain the signal trampolines.
* Otherwise, allocate a private page to hold them.
* Load a vdso if available, which will amongst other things contain the
* signal trampolines. Otherwise, allocate a separate page for them.
*/
if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
const VdsoImageInfo *vdso = vdso_image_info();
if (vdso) {
load_elf_vdso(&vdso_info, vdso);
info->vdso = vdso_info.load_bias;
} else if (TARGET_ARCH_HAS_SIGTRAMP_PAGE) {
abi_long tramp_page = target_mmap(0, TARGET_PAGE_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
@ -3844,8 +3936,9 @@ int load_elf_binary(struct linux_binprm *bprm, struct image_info *info)
target_mprotect(tramp_page, TARGET_PAGE_SIZE, PROT_READ | PROT_EXEC);
}
bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &elf_ex,
info, (elf_interpreter ? &interp_info : NULL));
bprm->p = create_elf_tables(bprm->p, bprm->argc, bprm->envc, &ehdr, info,
elf_interpreter ? &interp_info : NULL,
vdso ? &vdso_info : NULL);
info->start_stack = bprm->p;
/* If we have an interpreter, set that as the program's entry point.