initial commit

This commit is contained in:
hippoz 2023-07-11 20:49:24 +03:00
commit 93d66e8a25
Signed by: hippoz
GPG key ID: 56C4E02A85F2FBED
12 changed files with 368 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
builddir/

BIN
a.out Normal file

Binary file not shown.

12
meson.build Normal file
View file

@ -0,0 +1,12 @@
project('layer9', 'c')
add_global_arguments('-pie', language : 'c')
executable(
'layer9',
'./src/mach.c',
'./src/start.s',
'./src/syscall.c',
'./src/main.c',
dependencies : []
)

1
myfile Normal file
View file

@ -0,0 +1 @@
hello

24
src/mach.c Normal file
View file

@ -0,0 +1,24 @@
#include "mach.h"
const char *exec_magic_str(Exec *exec) {
switch (exec->magic) {
case A_MAGIC: return "68020";
case I_MAGIC: return "intel 386";
case J_MAGIC: return "intel 960 (retired)";
case K_MAGIC: return "sparc";
case V_MAGIC: return "mips 3000 BE";
case X_MAGIC: return "att dsp 3210 (retired)";
case M_MAGIC: return "mips 4000 BE";
case D_MAGIC: return "amd 29000 (retired)";
case E_MAGIC: return "arm";
case Q_MAGIC: return "powerpc";
case N_MAGIC: return "mips 4000 LE";
case L_MAGIC: return "dec alpha (retired)";
case P_MAGIC: return "mips 3000 LE";
case U_MAGIC: return "sparc64";
case S_MAGIC: return "amd64";
case T_MAGIC: return "powerpc64";
case R_MAGIC: return "arm64";
default: return "[unsupported]";
}
}

44
src/mach.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef _MACH_H
#define _MACH_H
#include <stdint.h>
typedef struct Exec {
int32_t magic; /* magic number */
int32_t text; /* size of text segment */
int32_t data; /* size of initialized data */
int32_t bss; /* size of uninitialized data */
int32_t syms; /* size of symbol table */
int32_t entry32; /* entry point */
int32_t spsz; /* size of pc/sp offset table */
int32_t pcsz; /* size of pc/line number table */
int64_t entry; /* entry point for HDR_MAGIC */
} __attribute__((__packed__)) Exec;
const static int exec_field_count = sizeof(Exec) / sizeof(int32_t);
#define HDR_MAGIC 0x00008000 /* header expansion */
#define _MAGIC(f, b) ((f)|((((4*(b))+0)*(b))+7))
#define A_MAGIC _MAGIC(0, 8) /* 68020 */
#define I_MAGIC _MAGIC(0, 11) /* intel 386 */
#define J_MAGIC _MAGIC(0, 12) /* intel 960 (retired) */
#define K_MAGIC _MAGIC(0, 13) /* sparc */
#define V_MAGIC _MAGIC(0, 16) /* mips 3000 BE */
#define X_MAGIC _MAGIC(0, 17) /* att dsp 3210 (retired) */
#define M_MAGIC _MAGIC(0, 18) /* mips 4000 BE */
#define D_MAGIC _MAGIC(0, 19) /* amd 29000 (retired) */
#define E_MAGIC _MAGIC(0, 20) /* arm */
#define Q_MAGIC _MAGIC(0, 21) /* powerpc */
#define N_MAGIC _MAGIC(0, 22) /* mips 4000 LE */
#define L_MAGIC _MAGIC(0, 23) /* dec alpha (retired) */
#define P_MAGIC _MAGIC(0, 24) /* mips 3000 LE */
#define U_MAGIC _MAGIC(0, 25) /* sparc64 */
#define S_MAGIC _MAGIC(HDR_MAGIC, 26) /* amd64 */
#define T_MAGIC _MAGIC(HDR_MAGIC, 27) /* powerpc64 */
#define R_MAGIC _MAGIC(HDR_MAGIC, 28) /* arm64 */
const char *exec_magic_str(Exec *exec);
#endif

152
src/main.c Normal file
View file

@ -0,0 +1,152 @@
#include "syscall.h"
#define _GNU_SOURCE
#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>
#include <inttypes.h>
#include <stdint.h>
#include <elf.h>
#include <link.h>
#include <sys/prctl.h>
#include <linux/prctl.h>
#include <sys/signal.h>
#include <fcntl.h>
#include "mach.h"
#include "tos.h"
#include "sys.h"
#define ALIGN(v, a) (((v) + (a) - 1) & ~((a) - 1))
#define DONE_ERR(M_err, M_ret) do { fprintf(stderr, (M_err)); defer_status = (M_ret); goto done; } while(0)
static char sud_intercept = SYSCALL_DISPATCH_FILTER_ALLOW;
extern void start(uintptr_t entry, Tos* tos, int argc, char **argv);
void enter(uintptr_t entry, int argc, char **argv)
{
Tos tos;
tos.pid = getpid();
printf("jump to entry 0x%"PRIxPTR"\n", entry);
sud_intercept = SYSCALL_DISPATCH_FILTER_BLOCK;
start(entry, &tos, argc, argv);
}
void handle_sigsys(int sig, siginfo_t *info, void *ptr)
{
ucontext_t *uc = ptr;
mcontext_t *mc = &uc->uc_mcontext;
greg_t *gregs = mc->gregs;
int64_t ret = -1;
int64_t *sp = (int64_t *)gregs[REG_RSP];
int64_t syscall = gregs[REG_RBP];
printf("syscall %ld\n", syscall);
switch (syscall) {
case OPEN:
ret = sys$open((char *)sp[1], (int)sp[2]);
break;
}
gregs[REG_RAX] = ret;
}
int findlibc(struct dl_phdr_info *info, size_t size, void *ptr)
{
const Elf64_Phdr *p;
uintptr_t offset, length, libc;
libc = (uintptr_t)read; /* arbitrary function used to identify libc text segment */
for (p = info->dlpi_phdr; p < info->dlpi_phdr + info->dlpi_phnum; ++p) {
if (p->p_type != PT_LOAD || !(p->p_flags & PF_X))
continue;
offset = info->dlpi_addr + p->p_vaddr;
length = p->p_memsz;
if (offset < libc && libc - offset < length) {
if (prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, offset, length, &sud_intercept) != 0) {
perror("prctl PR_SET_SYSCALL_USER_DISPATCH");
exit(1);
}
return 1;
}
}
return 0;
}
static char *program_argv[] = {
"out",
"../myfile",
NULL
};
int main()
{
int defer_status = 0;
void *file_segments = NULL;
FILE *f = NULL;
Exec header = {0};
size_t text_addr = 0x200000;
size_t data_addr;
f = fopen("../a.out", "rb");
if (fread(&header, 1, sizeof(header), f) != sizeof(header)) {
DONE_ERR("failed to read file header\n", 1);
}
// header fields are big-endian
int32_t *buf = (int32_t*)&header;
for (int i = 0; i < exec_field_count; i++) {
buf[i] = ntohl(buf[i]);
}
printf("load %s binary with entry 0x%"PRIxPTR"\n", exec_magic_str(&header), (uintptr_t)header.entry);
data_addr = ALIGN(text_addr + header.text, 0x200000);
size_t segments_size = sizeof(Exec) + header.text + header.data;
file_segments = malloc(segments_size);
if (!file_segments) {
defer_status = 1;
goto done;
}
if (fread(file_segments, 1, segments_size, f) != segments_size) {
DONE_ERR("failed to read file header and segments\n", 1);
}
void *text_segment = mmap((void*)text_addr, header.text, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (!text_segment) {
DONE_ERR("failed to map text segment into memory\n", 1);
}
printf("mapped text segment at 0x%"PRIxPTR"\n", (uintptr_t)text_segment);
void *data_segment = mmap((void*)data_addr, header.data + header.bss, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (!text_segment) {
DONE_ERR("failed to map data segment into memory\n", 1);
}
printf("mapped data segment at 0x%"PRIxPTR"\n", (uintptr_t)data_segment);
memcpy(text_segment, file_segments, header.text);
memcpy(data_segment, file_segments + sizeof(Exec) + header.text, header.data);
if (dl_iterate_phdr(findlibc, NULL) != 1) {
DONE_ERR("failed to find libc and enable SUD\n", 1);
}
struct sigaction sa = {
.sa_sigaction = handle_sigsys,
.sa_flags = SA_SIGINFO
};
sigaction(SIGSYS, &sa, NULL);
enter(header.entry32, 2, program_argv);
done:
free(file_segments);
fclose(f);
return defer_status;
}

25
src/start.s Normal file
View file

@ -0,0 +1,25 @@
/* Thanks: https://git.sr.ht/~mcf/nine/tree/main/item/start.s */
/* SPDX-License-Identifier: Unlicense */
.text
.globl start
start:
mov %rdi, %rbp /* entry */
mov %rsi, %rax /* _tos */
mov %rdx, %rbx /* argc */
mov %rcx, %rsi /* argv */
/* push argv onto stack */
mov %rbx, %rcx
add $1, %rcx
sal $3, %rcx
sub %rcx, %rsp
mov %rsp, %rdi
rep movsb
/* push argc onto stack */
push %rbx
jmp *%rbp
.section .note.GNU-stack,"",@progbits

52
src/sys.h Normal file
View file

@ -0,0 +1,52 @@
#define SYSR1 0
#define _ERRSTR 1
#define BIND 2
#define CHDIR 3
#define CLOSE 4
#define DUP 5
#define ALARM 6
#define EXEC 7
#define EXITS 8
#define _FSESSION 9
#define FAUTH 10
#define _FSTAT 11
#define SEGBRK 12
#define _MOUNT 13
#define OPEN 14
#define _READ 15
#define OSEEK 16
#define SLEEP 17
#define _STAT 18
#define RFORK 19
#define _WRITE 20
#define PIPE 21
#define CREATE 22
#define FD2PATH 23
#define BRK_ 24
#define REMOVE 25
#define _WSTAT 26
#define _FWSTAT 27
#define NOTIFY 28
#define NOTED 29
#define SEGATTACH 30
#define SEGDETACH 31
#define SEGFREE 32
#define SEGFLUSH 33
#define RENDEZVOUS 34
#define UNMOUNT 35
#define _WAIT 36
#define SEMACQUIRE 37
#define SEMRELEASE 38
#define SEEK 39
#define FVERSION 40
#define ERRSTR 41
#define STAT 42
#define FSTAT 43
#define WSTAT 44
#define FWSTAT 45
#define MOUNT 46
#define AWAIT 47
#define PREAD 50
#define PWRITE 51
#define TSEMACQUIRE 52
#define _NSEC 53

28
src/syscall.c Normal file
View file

@ -0,0 +1,28 @@
#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <inttypes.h>
#include "syscall.h"
static int mode_open(char *name, int mode, int perm, int flag)
{
switch (mode & 3) {
case 0: flag |= O_RDONLY; break;
case 1: flag |= O_WRONLY; break;
case 2: flag |= O_RDWR; break;
case 3: flag |= O_PATH; break;
}
if (mode & 16)
flag |= O_TRUNC;
if (mode & 32)
flag |= O_CLOEXEC;
return open(name, flag, perm);
}
int sys$open(char *path, int mode)
{
printf("sys$open(0x%"PRIxPTR", %d)\n", (uintptr_t)path, mode);
return mode_open(path, mode, 0, 0);
}

3
src/syscall.h Normal file
View file

@ -0,0 +1,3 @@
#pragma once
int sys$open(char *path, int mode);

26
src/tos.h Normal file
View file

@ -0,0 +1,26 @@
/* Thanks: https://git.sr.ht/~mcf/nine/tree/main/item/tos.h */
#include <stdint.h>
typedef struct Tos Tos;
typedef struct Plink Plink;
struct Tos {
struct /* Per process profiling */
{
Plink *pp; /* known to be 0(ptr) */
Plink *next; /* known to be 4(ptr) */
Plink *last;
Plink *first;
uint32_t pid;
uint32_t what;
} prof;
uint64_t cyclefreq; /* cycle clock frequency if there is one, 0 otherwise */
int64_t kcycles; /* cycles spent in kernel */
int64_t pcycles; /* cycles spent in process (kernel + user) */
uint32_t pid; /* might as well put the pid here */
uint32_t clock;
/* top of stack is here */
};
extern Tos *_tos;