aboutsummaryrefslogtreecommitdiff
path: root/linux-user/linuxload.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-06-16 18:59:57 -0700
committerRichard Henderson <richard.henderson@linaro.org>2023-10-30 13:41:55 -0700
commit7d2c5526ed85dcd7c81d91a3e2782db883366143 (patch)
tree8f6809b70acdbeffa81f2da8234129396f821fc9 /linux-user/linuxload.c
parent02d9f5b6acfa494e756ed8a5b373412e4240afaf (diff)
linux-user: Introduce imgsrc_read, imgsrc_read_alloc
Introduced and initialized, but not yet really used. These will tidy the current tests vs BPRM_BUF_SIZE. Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'linux-user/linuxload.c')
-rw-r--r--linux-user/linuxload.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 745cce70ab..3536dd8104 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -3,7 +3,9 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "user-internals.h"
+#include "user-mmap.h"
#include "loader.h"
+#include "qapi/error.h"
#define NGROUPS 32
@@ -76,6 +78,10 @@ static int prepare_binprm(struct linux_binprm *bprm)
/* Make sure the rest of the loader won't read garbage. */
memset(bprm->buf + retval, 0, BPRM_BUF_SIZE - retval);
}
+
+ bprm->src.cache = bprm->buf;
+ bprm->src.cache_size = retval;
+
return retval;
}
@@ -139,6 +145,7 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
int retval;
bprm->fd = fdexec;
+ bprm->src.fd = fdexec;
bprm->filename = (char *)filename;
bprm->argc = count(argv);
bprm->argv = argv;
@@ -173,3 +180,86 @@ int loader_exec(int fdexec, const char *filename, char **argv, char **envp,
return retval;
}
+
+bool imgsrc_read(void *dst, off_t offset, size_t len,
+ const ImageSource *img, Error **errp)
+{
+ ssize_t ret;
+
+ if (offset + len <= img->cache_size) {
+ memcpy(dst, img->cache + offset, len);
+ return true;
+ }
+
+ if (img->fd < 0) {
+ error_setg(errp, "read past end of buffer");
+ return false;
+ }
+
+ ret = pread(img->fd, dst, len, offset);
+ if (ret == len) {
+ return true;
+ }
+ if (ret < 0) {
+ error_setg_errno(errp, errno, "Error reading file header");
+ } else {
+ error_setg(errp, "Incomplete read of file header");
+ }
+ return false;
+}
+
+void *imgsrc_read_alloc(off_t offset, size_t len,
+ const ImageSource *img, Error **errp)
+{
+ void *alloc = g_malloc(len);
+ bool ok = imgsrc_read(alloc, offset, len, img, errp);
+
+ if (!ok) {
+ g_free(alloc);
+ alloc = NULL;
+ }
+ return alloc;
+}
+
+abi_long imgsrc_mmap(abi_ulong start, abi_ulong len, int prot,
+ int flags, const ImageSource *src, abi_ulong offset)
+{
+ const int prot_write = PROT_READ | PROT_WRITE;
+ abi_long ret;
+ void *haddr;
+
+ assert(flags == (MAP_PRIVATE | MAP_FIXED));
+
+ if (src->fd >= 0) {
+ return target_mmap(start, len, prot, flags, src->fd, offset);
+ }
+
+ /*
+ * This case is for the vdso; we don't expect bad images.
+ * The mmap may extend beyond the end of the image, especially
+ * to the end of the page. Zero fill.
+ */
+ assert(offset < src->cache_size);
+
+ ret = target_mmap(start, len, prot_write, flags | MAP_ANON, -1, 0);
+ if (ret == -1) {
+ return ret;
+ }
+
+ haddr = lock_user(VERIFY_WRITE, start, len, 0);
+ assert(haddr != NULL);
+ if (offset + len <= src->cache_size) {
+ memcpy(haddr, src->cache + offset, len);
+ } else {
+ size_t rest = src->cache_size - offset;
+ memcpy(haddr, src->cache + offset, rest);
+ memset(haddr + rest, 0, len - rest);
+ }
+ unlock_user(haddr, start, len);
+
+ if (prot != prot_write) {
+ target_mprotect(start, len, prot);
+ }
+
+ return ret;
+}