[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES, allow dynamic gro
From: |
Stefan Brüns |
Subject: |
[Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES, allow dynamic growth of env/argv space |
Date: |
Sat, 15 Aug 2015 20:26:01 +0200 |
qemu currently limits the space for the evironment and arguments to
32 * PAGE_SIZE. Linux limits the argument space to 1/4 of the stack size.
A program trying to detect this with a getrlimit(RLIMIT_STACK) syscall
will typically get a much larger limit than qemus current 128kB.
The current limit causes "Argument list too long" errors.
Signed-off-by: Stefan Brüns <address@hidden>
---
linux-user/elfload.c | 29 ++++++++++++++++++-----------
linux-user/linuxload.c | 7 ++++---
linux-user/qemu.h | 11 ++---------
linux-user/syscall.c | 4 ++++
4 files changed, 28 insertions(+), 23 deletions(-)
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 1788368..be8f4d6 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1365,11 +1365,13 @@ static bool elf_check_ehdr(struct elfhdr *ehdr)
* to be put directly into the top of new user memory.
*
*/
-static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
- abi_ulong p)
+static abi_ulong copy_elf_strings(int argc,char ** argv,
+ struct linux_binprm *bprm)
{
char *tmp, *tmp1, *pag = NULL;
int len, offset = 0;
+ void **page = bprm->page;
+ abi_ulong p = bprm->p;
if (!p) {
return 0; /* bullet-proofing */
@@ -1383,8 +1385,13 @@ static abi_ulong copy_elf_strings(int argc,char ** argv,
void **page,
tmp1 = tmp;
while (*tmp++);
len = tmp - tmp1;
- if (p < len) { /* this shouldn't happen - 128kB */
- return 0;
+ if (p < len) {
+ bprm->page = (void**)calloc(bprm->n_arg_pages + 32, sizeof(void*));
+ memcpy(&bprm->page[32], page, sizeof(void*) * bprm->n_arg_pages);
+ free(page);
+ page = bprm->page;
+ bprm->n_arg_pages += 32;
+ p += 32 * TARGET_PAGE_SIZE;
}
while (len) {
--p; --tmp; --len;
@@ -1423,8 +1430,8 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct
linux_binprm *bprm,
/* Create enough stack to hold everything. If we don't use
it for args, we'll use it for something else. */
size = guest_stack_size;
- if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE) {
- size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+ if (size < bprm->n_arg_pages * TARGET_PAGE_SIZE) {
+ size = bprm->n_arg_pages * TARGET_PAGE_SIZE;
}
guard = TARGET_PAGE_SIZE;
if (guard < qemu_real_host_page_size) {
@@ -1442,10 +1449,10 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct
linux_binprm *bprm,
target_mprotect(error, guard, PROT_NONE);
info->stack_limit = error + guard;
- stack_base = info->stack_limit + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
+ stack_base = info->stack_limit + size - bprm->n_arg_pages *
TARGET_PAGE_SIZE;
p += stack_base;
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+ for (i = 0; i < bprm->n_arg_pages; i++) {
if (bprm->page[i]) {
info->rss++;
/* FIXME - check return value of memcpy_to_target() for failure */
@@ -2211,9 +2218,9 @@ int load_elf_binary(struct linux_binprm *bprm, struct
image_info *info)
when we load the interpreter. */
elf_ex = *(struct elfhdr *)bprm->buf;
- bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
- bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
- bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
+ bprm->p = copy_elf_strings(1, &bprm->filename, bprm);
+ bprm->p = copy_elf_strings(bprm->envc, bprm->envp, bprm);
+ bprm->p = copy_elf_strings(bprm->argc, bprm->argv, bprm);
if (!bprm->p) {
fprintf(stderr, "%s: %s\n", bprm->filename, strerror(E2BIG));
exit(-1);
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 506e837..59943ea 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -137,8 +137,9 @@ int loader_exec(int fdexec, const char *filename, char
**argv, char **envp,
int retval;
int i;
- bprm->p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
- memset(bprm->page, 0, sizeof(bprm->page));
+ bprm->n_arg_pages = 32;
+ bprm->p = bprm->n_arg_pages * TARGET_PAGE_SIZE - sizeof(unsigned int);
+ bprm->page = (void**)calloc(bprm->n_arg_pages, sizeof(void*));
bprm->fd = fdexec;
bprm->filename = (char *)filename;
bprm->argc = count(argv);
@@ -173,7 +174,7 @@ int loader_exec(int fdexec, const char *filename, char
**argv, char **envp,
}
/* Something went wrong, return the inode and free the argument pages*/
- for (i=0 ; i<MAX_ARG_PAGES ; i++) {
+ for (i = 0; i < bprm->n_arg_pages; i++) {
g_free(bprm->page[i]);
}
return(retval);
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 8012cc2..cf4aa73 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -144,14 +144,6 @@ void stop_all_tasks(void);
extern const char *qemu_uname_release;
extern unsigned long mmap_min_addr;
-/* ??? See if we can avoid exposing so much of the loader internals. */
-/*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB w/4KB pages!
- */
-#define MAX_ARG_PAGES 33
-
/* Read a good amount of data initially, to hopefully get all the
program headers loaded. */
#define BPRM_BUF_SIZE 1024
@@ -162,7 +154,8 @@ extern unsigned long mmap_min_addr;
*/
struct linux_binprm {
char buf[BPRM_BUF_SIZE] __attribute__((aligned));
- void *page[MAX_ARG_PAGES];
+ void **page;
+ int n_arg_pages;
abi_ulong p;
int fd;
int e_uid, e_gid;
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f62c698..6fa5fb4 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -5799,12 +5799,16 @@ abi_long do_syscall(void *cpu_env, int num, abi_long
arg1,
}
*q = NULL;
+/* This check is bogus. MAX_ARG_PAGES is a thing of the past. Trust the host
+execve to set errno appropriately */
+#if 0
/* This case will not be caught by the host's execve() if its
page size is bigger than the target's. */
if (total_size > MAX_ARG_PAGES * TARGET_PAGE_SIZE) {
ret = -TARGET_E2BIG;
goto execve_end;
}
+#endif
if (!(p = lock_user_string(arg1)))
goto execve_efault;
ret = get_errno(execve(p, argp, envp));
--
2.1.4
- [Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES, allow dynamic growth of env/argv space,
Stefan Brüns <=
- Re: [Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES, allow dynamic growth of env/argv space, Peter Maydell, 2015/08/19
- [Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES limit, Stefan Brüns, 2015/08/22
- Re: [Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES limit, Stefan Bruens, 2015/08/27
- Re: [Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES limit, Peter Maydell, 2015/08/27
- [Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES limit, Stefan Brüns, 2015/08/27
- Re: [Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES limit, Stefan Bruens, 2015/08/30
- Re: [Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES limit, Peter Maydell, 2015/08/30
Re: [Qemu-devel] [PATCH] linux-user: remove MAX_ARG_PAGES, allow dynamic growth of env/argv space, Stefan Bruens, 2015/08/22