ladybird/Tests/Kernel/elf-execve-mmap-race.cpp
Andrew Kaster 1cd3826ad6 Userland+Tests: Don't use MAP_FILE when mmap-ing
MAP_FILE is not in POSIX, and is simply in most LibCs as a "default"
mode. Our own LibC defines it as 0, meaning "no flags". It is also not
defined in some OS's, such as Haiku. Let's be more portable and not use
the unnecessary flag.
2023-09-01 19:50:35 +02:00

142 lines
3.3 KiB
C++

/*
* Copyright (c) 2018-2020, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Types.h>
#include <elf.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
bool volatile hax = false;
int main()
{
char buffer[16384];
auto& header = *(Elf32_Ehdr*)buffer;
header.e_ident[EI_MAG0] = ELFMAG0;
header.e_ident[EI_MAG1] = ELFMAG1;
header.e_ident[EI_MAG2] = ELFMAG2;
header.e_ident[EI_MAG3] = ELFMAG3;
header.e_ident[EI_CLASS] = ELFCLASS32;
header.e_ident[EI_DATA] = ELFDATA2LSB;
header.e_ident[EI_VERSION] = EV_CURRENT;
header.e_ident[EI_OSABI] = ELFOSABI_SYSV;
header.e_ident[EI_ABIVERSION] = 0;
header.e_type = ET_EXEC;
header.e_version = EV_CURRENT;
header.e_ehsize = sizeof(Elf32_Ehdr);
header.e_machine = EM_386;
header.e_shentsize = sizeof(Elf32_Shdr);
header.e_phnum = 1;
header.e_phoff = 52;
header.e_phentsize = sizeof(Elf32_Phdr);
auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]);
ph[0].p_vaddr = 0x20000000;
ph[0].p_type = PT_LOAD;
ph[0].p_filesz = sizeof(buffer);
ph[0].p_memsz = sizeof(buffer);
ph[0].p_flags = PF_R | PF_W;
ph[0].p_align = PAGE_SIZE;
header.e_shnum = 3;
header.e_shoff = 1024;
u32 secret_address = 0x00184658;
auto* sh = (Elf32_Shdr*)(&buffer[header.e_shoff]);
sh[0].sh_type = SHT_SYMTAB;
sh[0].sh_offset = 2048;
sh[0].sh_entsize = sizeof(Elf32_Sym);
sh[0].sh_size = 1 * sizeof(Elf32_Sym);
sh[1].sh_type = SHT_STRTAB;
sh[1].sh_offset = secret_address - 0x01001000;
sh[1].sh_entsize = 0;
sh[1].sh_size = 1024;
sh[2].sh_type = SHT_STRTAB;
sh[2].sh_offset = 4096;
sh[2].sh_entsize = 0;
sh[2].sh_size = 1024;
header.e_shstrndx = 2;
auto* sym = (Elf32_Sym*)(&buffer[2048]);
sym[0].st_value = 0;
sym[0].st_name = 0;
header.e_entry = 0;
char path[] = "/tmp/x.XXXXXX";
auto fd = mkstemp(path);
if (fd < 0) {
perror("mkstemp");
return 1;
}
if (fchmod(fd, 0777) < 0) {
perror("chmod");
return 1;
}
int nwritten = write(fd, buffer, sizeof(buffer));
if (nwritten < 0) {
perror("write");
return 1;
}
sync();
auto* mapped = (u8*)mmap(nullptr, sizeof(buffer), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (mapped == MAP_FAILED) {
perror("mmap");
return 1;
}
auto* writable_program_headers = (Elf32_Phdr*)(&mapped[header.e_phoff]);
pthread_attr_t attrs;
pthread_attr_init(&attrs);
sched_param high_prio { 99 };
pthread_attr_setschedparam(&attrs, &high_prio);
pthread_t t;
pthread_create(
&t, &attrs, [](void* ctx) -> void* {
auto& ph = *(volatile Elf32_Phdr*)ctx;
for (;;) {
if (!hax)
ph.p_offset = 0x60000000;
else
ph.p_offset = 0;
hax = !hax;
usleep(1);
}
},
&writable_program_headers[0]);
for (;;) {
if (!fork()) {
try_again:
printf("exec\n");
execl(path, "x", nullptr);
goto try_again;
}
printf("waitpid\n");
waitpid(-1, nullptr, 0);
}
}