cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

task_size.c (3401B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <stdio.h>
      3#include <stdlib.h>
      4#include <signal.h>
      5#include <sys/mman.h>
      6#include <longjmp.h>
      7
      8#ifdef __i386__
      9
     10static jmp_buf buf;
     11
     12static void segfault(int sig)
     13{
     14	longjmp(buf, 1);
     15}
     16
     17static int page_ok(unsigned long page)
     18{
     19	unsigned long *address = (unsigned long *) (page << UM_KERN_PAGE_SHIFT);
     20	unsigned long n = ~0UL;
     21	void *mapped = NULL;
     22	int ok = 0;
     23
     24	/*
     25	 * First see if the page is readable.  If it is, it may still
     26	 * be a VDSO, so we go on to see if it's writable.  If not
     27	 * then try mapping memory there.  If that fails, then we're
     28	 * still in the kernel area.  As a sanity check, we'll fail if
     29	 * the mmap succeeds, but gives us an address different from
     30	 * what we wanted.
     31	 */
     32	if (setjmp(buf) == 0)
     33		n = *address;
     34	else {
     35		mapped = mmap(address, UM_KERN_PAGE_SIZE,
     36			      PROT_READ | PROT_WRITE,
     37			      MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     38		if (mapped == MAP_FAILED)
     39			return 0;
     40		if (mapped != address)
     41			goto out;
     42	}
     43
     44	/*
     45	 * Now, is it writeable?  If so, then we're in user address
     46	 * space.  If not, then try mprotecting it and try the write
     47	 * again.
     48	 */
     49	if (setjmp(buf) == 0) {
     50		*address = n;
     51		ok = 1;
     52		goto out;
     53	} else if (mprotect(address, UM_KERN_PAGE_SIZE,
     54			    PROT_READ | PROT_WRITE) != 0)
     55		goto out;
     56
     57	if (setjmp(buf) == 0) {
     58		*address = n;
     59		ok = 1;
     60	}
     61
     62 out:
     63	if (mapped != NULL)
     64		munmap(mapped, UM_KERN_PAGE_SIZE);
     65	return ok;
     66}
     67
     68unsigned long os_get_top_address(void)
     69{
     70	struct sigaction sa, old;
     71	unsigned long bottom = 0;
     72	/*
     73	 * A 32-bit UML on a 64-bit host gets confused about the VDSO at
     74	 * 0xffffe000.  It is mapped, is readable, can be reprotected writeable
     75	 * and written.  However, exec discovers later that it can't be
     76	 * unmapped.  So, just set the highest address to be checked to just
     77	 * below it.  This might waste some address space on 4G/4G 32-bit
     78	 * hosts, but shouldn't hurt otherwise.
     79	 */
     80	unsigned long top = 0xffffd000 >> UM_KERN_PAGE_SHIFT;
     81	unsigned long test, original;
     82
     83	printf("Locating the bottom of the address space ... ");
     84	fflush(stdout);
     85
     86	/*
     87	 * We're going to be longjmping out of the signal handler, so
     88	 * SA_DEFER needs to be set.
     89	 */
     90	sa.sa_handler = segfault;
     91	sigemptyset(&sa.sa_mask);
     92	sa.sa_flags = SA_NODEFER;
     93	if (sigaction(SIGSEGV, &sa, &old)) {
     94		perror("os_get_top_address");
     95		exit(1);
     96	}
     97
     98	/* Manually scan the address space, bottom-up, until we find
     99	 * the first valid page (or run out of them).
    100	 */
    101	for (bottom = 0; bottom < top; bottom++) {
    102		if (page_ok(bottom))
    103			break;
    104	}
    105
    106	/* If we've got this far, we ran out of pages. */
    107	if (bottom == top) {
    108		fprintf(stderr, "Unable to determine bottom of address "
    109			"space.\n");
    110		exit(1);
    111	}
    112
    113	printf("0x%lx\n", bottom << UM_KERN_PAGE_SHIFT);
    114	printf("Locating the top of the address space ... ");
    115	fflush(stdout);
    116
    117	original = bottom;
    118
    119	/* This could happen with a 4G/4G split */
    120	if (page_ok(top))
    121		goto out;
    122
    123	do {
    124		test = bottom + (top - bottom) / 2;
    125		if (page_ok(test))
    126			bottom = test;
    127		else
    128			top = test;
    129	} while (top - bottom > 1);
    130
    131out:
    132	/* Restore the old SIGSEGV handling */
    133	if (sigaction(SIGSEGV, &old, NULL)) {
    134		perror("os_get_top_address");
    135		exit(1);
    136	}
    137	top <<= UM_KERN_PAGE_SHIFT;
    138	printf("0x%lx\n", top);
    139
    140	return top;
    141}
    142
    143#else
    144
    145unsigned long os_get_top_address(void)
    146{
    147	/* The old value of CONFIG_TOP_ADDR */
    148	return 0x7fc0002000;
    149}
    150
    151#endif