aboutsummaryrefslogtreecommitdiff
path: root/linux-user/elfload.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-06-16 20:32:56 -0700
committerRichard Henderson <richard.henderson@linaro.org>2023-10-30 13:41:55 -0700
commit3bd0238638070274b9ce3464f0456cdf6ca0884d (patch)
tree5517727778b0fa651ab49393517a1b4b134a4954 /linux-user/elfload.c
parent40d487eecfac331234cf7a5bfd26ff6f667b2b82 (diff)
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>
Diffstat (limited to 'linux-user/elfload.c')
-rw-r--r--linux-user/elfload.c128
1 files changed, 49 insertions, 79 deletions
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index d5af354a78..d763cb855a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -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,14 +3132,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;
}
/*
@@ -3186,30 +3179,34 @@ static bool parse_elf_properties(int image_fd,
}
}
-/* Load an ELF image into the address space.
-
- 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. */
+/**
+ * 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.
+ */
-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 */