diff options
| author | Benjamin Berg <benjamin.berg@intel.com> | 2024-09-19 15:45:09 +0300 |
|---|---|---|
| committer | Johannes Berg <johannes.berg@intel.com> | 2024-10-10 14:37:22 +0300 |
| commit | 68b9883cc16ec2ce699d832ef60241b1a4e47d33 (patch) | |
| tree | 643472cca34b474083cf41dd9859840648c2e8f8 /arch/um | |
| parent | 830003c73d190259e45d0a99a0e3d14cb73e0af0 (diff) | |
| download | linux-68b9883cc16ec2ce699d832ef60241b1a4e47d33.tar.xz | |
um: Discover host_task_size from envp
When loading the UML binary, the host kernel will place the stack at the
highest possible address. It will then map the program name and
environment variables onto the start of the stack.
As such, an easy way to figure out the host_task_size is to use the
highest pointer to an environment variable as a reference.
Ensure that this works by disabling address layout randomization and
re-executing UML in case it was enabled.
This increases the available TASK_SIZE for 64 bit UML considerably.
Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
Link: https://patch.msgid.link/20240919124511.282088-9-benjamin@sipsolutions.net
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'arch/um')
| -rw-r--r-- | arch/um/include/shared/as-layout.h | 2 | ||||
| -rw-r--r-- | arch/um/include/shared/os.h | 3 | ||||
| -rw-r--r-- | arch/um/kernel/um_arch.c | 21 | ||||
| -rw-r--r-- | arch/um/os-Linux/main.c | 9 |
4 files changed, 28 insertions, 7 deletions
diff --git a/arch/um/include/shared/as-layout.h b/arch/um/include/shared/as-layout.h index 283226c34ca4..d9679c911e54 100644 --- a/arch/um/include/shared/as-layout.h +++ b/arch/um/include/shared/as-layout.h @@ -49,7 +49,7 @@ extern unsigned long brk_start; extern unsigned long host_task_size; extern unsigned long stub_start; -extern int linux_main(int argc, char **argv); +extern int linux_main(int argc, char **argv, char **envp); extern void uml_finishsetup(void); struct siginfo; diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h index b511637e1f76..bf539fee7831 100644 --- a/arch/um/include/shared/os.h +++ b/arch/um/include/shared/os.h @@ -325,9 +325,6 @@ extern int __ignore_sigio_fd(int fd); /* tty.c */ extern int get_pty(void); -/* sys-$ARCH/task_size.c */ -extern unsigned long os_get_top_address(void); - long syscall(long number, ...); /* irqflags tracing */ diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 4452df4f2c4b..38cbb41a64bc 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -302,7 +302,24 @@ static void parse_cache_line(char *line) } } -int __init linux_main(int argc, char **argv) +static unsigned long get_top_address(char **envp) +{ + unsigned long top_addr = (unsigned long) &top_addr; + int i; + + /* The earliest variable should be after the program name in ELF */ + for (i = 0; envp[i]; i++) { + if ((unsigned long) envp[i] > top_addr) + top_addr = (unsigned long) envp[i]; + } + + top_addr &= ~(UM_KERN_PAGE_SIZE - 1); + top_addr += UM_KERN_PAGE_SIZE; + + return top_addr; +} + +int __init linux_main(int argc, char **argv, char **envp) { unsigned long avail, diff; unsigned long virtmem_size, max_physmem; @@ -324,7 +341,7 @@ int __init linux_main(int argc, char **argv) if (have_console == 0) add_arg(DEFAULT_COMMAND_LINE_CONSOLE); - host_task_size = os_get_top_address(); + host_task_size = get_top_address(envp); /* reserve a few pages for the stubs */ stub_start = host_task_size - STUB_DATA_PAGES * PAGE_SIZE; /* another page for the code portion */ diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index cf1179ed1aec..8a52c49c5361 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -11,6 +11,7 @@ #include <signal.h> #include <string.h> #include <sys/resource.h> +#include <sys/personality.h> #include <as-layout.h> #include <init.h> #include <kern_util.h> @@ -108,6 +109,12 @@ int __init main(int argc, char **argv, char **envp) char **new_argv; int ret, i, err; + /* Disable randomization and re-exec if it was changed successfully */ + ret = personality(PER_LINUX | ADDR_NO_RANDOMIZE); + if (ret >= 0 && (ret & (PER_LINUX | ADDR_NO_RANDOMIZE)) != + (PER_LINUX | ADDR_NO_RANDOMIZE)) + execve("/proc/self/exe", argv, envp); + set_stklim(); setup_env_path(); @@ -140,7 +147,7 @@ int __init main(int argc, char **argv, char **envp) #endif change_sig(SIGPIPE, 0); - ret = linux_main(argc, argv); + ret = linux_main(argc, argv, envp); /* * Disable SIGPROF - I have no idea why libc doesn't do this or turn |
