initial commit
This commit is contained in:
commit
93d66e8a25
12 changed files with 368 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
builddir/
|
BIN
a.out
Normal file
BIN
a.out
Normal file
Binary file not shown.
12
meson.build
Normal file
12
meson.build
Normal 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
1
myfile
Normal file
|
@ -0,0 +1 @@
|
||||||
|
hello
|
24
src/mach.c
Normal file
24
src/mach.c
Normal 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
44
src/mach.h
Normal 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
152
src/main.c
Normal 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
25
src/start.s
Normal 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
52
src/sys.h
Normal 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
28
src/syscall.c
Normal 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
3
src/syscall.h
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
int sys$open(char *path, int mode);
|
26
src/tos.h
Normal file
26
src/tos.h
Normal 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;
|
Loading…
Reference in a new issue