linux-user: Use ImageSource in load_elf_image

Change parse_elf_properties as well, as the bprm_buf argument
ties the two functions closely.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2021-06-16 20:32:56 -07:00
parent 40d487eecf
commit 3bd0238638

View File

@ -3102,10 +3102,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 {
@ -3133,15 +3132,9 @@ 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");
if (!imgsrc_read(&note, phdr->p_offset, n, src, errp)) {
return false;
}
}
/*
* The contents of a valid PT_GNU_PROPERTY is a sequence
@ -3186,30 +3179,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,
static void load_elf_image(const char *image_name, const ImageSource *src,
struct image_info *info, struct elfhdr *ehdr,
char **pinterp_name,
char bprm_buf[BPRM_BUF_SIZE])
char **pinterp_name)
{
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 */
memcpy(ehdr, bprm_buf, sizeof(*ehdr));
/*
* 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;
@ -3220,15 +3217,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);
@ -3265,17 +3258,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");
@ -3283,7 +3269,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) {
@ -3436,9 +3422,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;
}
@ -3470,20 +3456,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
@ -3496,23 +3473,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->fd, 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;
@ -3525,6 +3495,7 @@ 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;
@ -3542,11 +3513,11 @@ 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, fd, info, &ehdr, NULL, bprm_buf);
load_elf_image(filename, &src, info, &ehdr, NULL);
}
static int symfind(const void *s0, const void *s1)
@ -3755,8 +3726,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,
&ehdr, &elf_interpreter, 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 */