@@ -48,7 +48,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;
@@ -330,7 +330,7 @@ extern int __ignore_sigio_fd(int fd);
extern int get_pty(void);
/* sys-$ARCH/task_size.c */
-extern unsigned long os_get_top_address(void);
+extern unsigned long os_get_top_address(char **envp);
long syscall(long number, ...);
@@ -302,7 +302,7 @@ static void parse_cache_line(char *line)
}
}
-int __init linux_main(int argc, char **argv)
+int __init linux_main(int argc, char **argv, char **envp)
{
unsigned long avail, diff;
unsigned long virtmem_size, max_physmem;
@@ -324,7 +324,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 = os_get_top_address(envp);
/* reserve a few pages for the stubs (taking care of data alignment) */
/* align the data portion */
BUILD_BUG_ON(!is_power_of_2(STUB_DATA_PAGES));
@@ -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
@@ -1,151 +1,19 @@
// SPDX-License-Identifier: GPL-2.0
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/mman.h>
-#include <longjmp.h>
-#ifdef __i386__
-
-static jmp_buf buf;
-
-static void segfault(int sig)
-{
- longjmp(buf, 1);
-}
-
-static int page_ok(unsigned long page)
-{
- unsigned long *address = (unsigned long *) (page << UM_KERN_PAGE_SHIFT);
- unsigned long n = ~0UL;
- void *mapped = NULL;
- int ok = 0;
-
- /*
- * First see if the page is readable. If it is, it may still
- * be a VDSO, so we go on to see if it's writable. If not
- * then try mapping memory there. If that fails, then we're
- * still in the kernel area. As a sanity check, we'll fail if
- * the mmap succeeds, but gives us an address different from
- * what we wanted.
- */
- if (setjmp(buf) == 0)
- n = *address;
- else {
- mapped = mmap(address, UM_KERN_PAGE_SIZE,
- PROT_READ | PROT_WRITE,
- MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (mapped == MAP_FAILED)
- return 0;
- if (mapped != address)
- goto out;
- }
-
- /*
- * Now, is it writeable? If so, then we're in user address
- * space. If not, then try mprotecting it and try the write
- * again.
- */
- if (setjmp(buf) == 0) {
- *address = n;
- ok = 1;
- goto out;
- } else if (mprotect(address, UM_KERN_PAGE_SIZE,
- PROT_READ | PROT_WRITE) != 0)
- goto out;
-
- if (setjmp(buf) == 0) {
- *address = n;
- ok = 1;
- }
-
- out:
- if (mapped != NULL)
- munmap(mapped, UM_KERN_PAGE_SIZE);
- return ok;
-}
-
-unsigned long os_get_top_address(void)
+unsigned long os_get_top_address(char **envp)
{
- struct sigaction sa, old;
- unsigned long bottom = 0;
- /*
- * A 32-bit UML on a 64-bit host gets confused about the VDSO at
- * 0xffffe000. It is mapped, is readable, can be reprotected writeable
- * and written. However, exec discovers later that it can't be
- * unmapped. So, just set the highest address to be checked to just
- * below it. This might waste some address space on 4G/4G 32-bit
- * hosts, but shouldn't hurt otherwise.
- */
- unsigned long top = 0xffffd000 >> UM_KERN_PAGE_SHIFT;
- unsigned long test, original;
+ unsigned long top_addr = (unsigned long) &top_addr;
+ int i;
- printf("Locating the bottom of the address space ... ");
- fflush(stdout);
-
- /*
- * We're going to be longjmping out of the signal handler, so
- * SA_DEFER needs to be set.
- */
- sa.sa_handler = segfault;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_NODEFER;
- if (sigaction(SIGSEGV, &sa, &old)) {
- perror("os_get_top_address");
- exit(1);
- }
-
- /* Manually scan the address space, bottom-up, until we find
- * the first valid page (or run out of them).
- */
- for (bottom = 0; bottom < top; bottom++) {
- if (page_ok(bottom))
- break;
- }
-
- /* If we've got this far, we ran out of pages. */
- if (bottom == top) {
- fprintf(stderr, "Unable to determine bottom of address "
- "space.\n");
- exit(1);
- }
-
- printf("0x%lx\n", bottom << UM_KERN_PAGE_SHIFT);
- printf("Locating the top of the address space ... ");
- fflush(stdout);
-
- original = bottom;
-
- /* This could happen with a 4G/4G split */
- if (page_ok(top))
- goto out;
-
- do {
- test = bottom + (top - bottom) / 2;
- if (page_ok(test))
- bottom = test;
- else
- top = test;
- } while (top - bottom > 1);
-
-out:
- /* Restore the old SIGSEGV handling */
- if (sigaction(SIGSEGV, &old, NULL)) {
- perror("os_get_top_address");
- exit(1);
+ /* 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 <<= UM_KERN_PAGE_SHIFT;
- printf("0x%lx\n", top);
- return top;
-}
-
-#else
+ top_addr &= ~(UM_KERN_PAGE_SIZE - 1);
+ top_addr += UM_KERN_PAGE_SIZE;
-unsigned long os_get_top_address(void)
-{
- /* The old value of CONFIG_TOP_ADDR */
- return 0x7fc0002000;
+ return top_addr;
}
-#endif