/* * exechello.c -- stage 20: "hello" built with the stock recipe, * `musl-gcc -static` and no other flags. That makes a classic ET_EXEC * file linked at 0x400000 (4 MiB), the address every Linux linker uses. * Until stage 20 the kernel itself lived down there; now it doesn't. * * Checks: we really are at 0x400000, and the heap (brk) and mmap memory * land outside our image. Exit code = number of failed checks. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include static int fails; #define CHECK(cond, what) \ do { \ if (!(cond)) { \ fails++; \ printf("exechello: FAIL %s\n", what); \ } \ } while (0) extern const Elf64_Ehdr __ehdr_start; /* first byte of the image */ extern char _end[]; /* one past the last byte (.bss end) */ extern char _start[]; /* Does [p, p + len) overlap our image? */ static int in_image(const void *p, unsigned long len) { unsigned long a = (unsigned long)p, lo = (unsigned long)&__ehdr_start; return a < (unsigned long)_end && a + len > lo; } int main(void) { puts("hello from a plain static executable"); CHECK((unsigned long)&__ehdr_start == 0x400000, "image starts at 0x400000"); CHECK(__ehdr_start.e_type == ET_EXEC, "ET_EXEC file"); CHECK(getauxval(AT_ENTRY) == (unsigned long)_start, "AT_ENTRY is _start"); CHECK(getauxval(AT_PHDR) == 0x400000 + __ehdr_start.e_phoff, "AT_PHDR"); /* brk: starts at or after the image's end and grows from there. * (musl's sbrk() only takes 0, so grow it with the raw syscall.) */ char *brk0 = sbrk(0); CHECK(brk0 != (char *)-1 && brk0 >= _end, "brk starts after the image"); char *more = brk0; CHECK((char *)syscall(SYS_brk, brk0 + 64 * 1024) == brk0 + 64 * 1024, "brk grows by 64 KiB"); { memset(more, 0x5a, 64 * 1024); /* writable, no fault */ CHECK(!in_image(more, 64 * 1024), "brk memory outside the image"); } /* mmap and malloc (small: musl's heap; big: its own mmap). */ void *m = mmap(NULL, 1 << 20, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); CHECK(m != MAP_FAILED && !in_image(m, 1 << 20), "mmap outside the image"); CHECK(m == MAP_FAILED || (char *)m > brk0 + 64 * 1024, "mmap above the heap"); for (int i = 0; i < 64; i++) { size_t n = i % 2 ? 40 : 300 * 1024; char *p = malloc(n); CHECK(p && !in_image(p, n), "malloc outside the image"); if (p) memset(p, i, n); free(p); } printf("image %p..%p, brk %p, mmap %p\n", (void *)&__ehdr_start, (void *)_end, (void *)brk0, m); printf("exechello: %d failed\n", fails); return fails; }