[PATCH v8 5/7] um: Discover host_task_size from envp
Tiwei Bie
tiwei.btw at antgroup.com
Thu Sep 19 05:15:43 PDT 2024
On 2024/7/5 03:05, Benjamin Berg wrote:
[...]
> diff --git a/arch/x86/um/os-Linux/task_size.c b/arch/x86/um/os-Linux/task_size.c
> index 1dc9adc20b1c..a91599799b1a 100644
> --- a/arch/x86/um/os-Linux/task_size.c
> +++ b/arch/x86/um/os-Linux/task_size.c
> @@ -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>
>
Tiny nit: we need to include os.h to avoid below warning:
arch/x86/um/os-Linux/task_size.c:3:15: warning: no previous prototype for
‘os_get_top_address’ [-Wmissing-prototypes]
3 | unsigned long os_get_top_address(char **envp)
| ^~~~~~~~~~~~~~~~~~
Regards,
Tiwei
> -#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
More information about the linux-um
mailing list