The Pedigree Project 0.1
ptrace-contract-test/contract.h
1#ifndef PTRACE_CONTRACT_H
2#define PTRACE_CONTRACT_H
3
4#include <errno.h>
5#include <pthread.h>
6#include <signal.h>
7#include <stdatomic.h>
8#include <stddef.h>
9#include <stdint.h>
10#include <stdio.h>
11
12#include "entry-layout.h"
13#include "sentinel-layout.h"
14#include <sys/ptrace.h>
15#include <sys/syscall.h>
16#include <sys/types.h>
17#include <sys/user.h>
18#include <sys/wait.h>
19
20#if !defined(__x86_64__) || defined(__ILP32__)
21#error This draft requires the musl amd64 ABI.
22#endif
23
24#define TC_ARCH_GET_FS 0x1003
25#define TC_STOP_SIGNAL SIGUSR1
26#define TC_EXECUTABLE "/applications/ptrace-contract-test"
27#define TC_ENTRY_EXECUTABLE "/applications/ptrace-entry-test"
28#define TC_EXIT_CODE 17
29#define TC_IMAGE_TLS UINT64_C(0x1938574629183746)
30#define CHECK(condition) \
31 do { \
32 if (!(condition)) { \
33 fprintf(stderr, "%s:%d: %s (errno=%d)\n", __FILE__, __LINE__, #condition, errno); \
34 failed = 1; \
35 goto out; \
36 } \
37 } while (0)
38
39struct tc_setup {
40 uint64_t pid, tid, fs_base, stack, label, cs, ss, ds, es, fs, gs;
41};
42
43struct tc_capture {
44 struct tc_setup setup;
45 uint64_t entry_flags;
46 struct user_regs_struct resumed;
47};
48
50 uint64_t magic;
51 struct user_regs_struct registers;
52 int64_t fs_result;
53};
54
55#define TC_OFFSET(type, field, offset) \
56 _Static_assert(offsetof(type, field) == (offset), "assembly offset: " #field)
57TC_OFFSET(struct tc_setup, pid, TC_PID);
58TC_OFFSET(struct tc_setup, tid, TC_TID);
59TC_OFFSET(struct tc_setup, fs_base, TC_FS_BASE);
60TC_OFFSET(struct tc_setup, stack, TC_STACK);
61TC_OFFSET(struct tc_setup, label, TC_LABEL);
62TC_OFFSET(struct tc_setup, cs, TC_CS);
63TC_OFFSET(struct tc_setup, ss, TC_SS);
64TC_OFFSET(struct tc_setup, ds, TC_DS);
65TC_OFFSET(struct tc_setup, es, TC_ES);
66TC_OFFSET(struct tc_setup, fs, TC_FS);
67TC_OFFSET(struct tc_setup, gs, TC_GS);
68TC_OFFSET(struct tc_capture, entry_flags, TC_ENTRY_FLAGS);
69TC_OFFSET(struct tc_capture, resumed, TC_RESUMED);
70TC_OFFSET(struct tc_entry_record, magic, TC_ENTRY_MAGIC);
71TC_OFFSET(struct tc_entry_record, registers, TC_ENTRY_REGISTERS);
72TC_OFFSET(struct tc_entry_record, fs_result, TC_ENTRY_FS_RESULT);
73TC_OFFSET(struct user_regs_struct, r15, TC_R15);
74TC_OFFSET(struct user_regs_struct, r14, TC_R14);
75TC_OFFSET(struct user_regs_struct, r13, TC_R13);
76TC_OFFSET(struct user_regs_struct, r12, TC_R12);
77TC_OFFSET(struct user_regs_struct, rbp, TC_RBP);
78TC_OFFSET(struct user_regs_struct, rbx, TC_RBX);
79TC_OFFSET(struct user_regs_struct, r11, TC_R11);
80TC_OFFSET(struct user_regs_struct, r10, TC_R10);
81TC_OFFSET(struct user_regs_struct, r9, TC_R9);
82TC_OFFSET(struct user_regs_struct, r8, TC_R8);
83TC_OFFSET(struct user_regs_struct, rax, TC_RAX);
84TC_OFFSET(struct user_regs_struct, rcx, TC_RCX);
85TC_OFFSET(struct user_regs_struct, rdx, TC_RDX);
86TC_OFFSET(struct user_regs_struct, rsi, TC_RSI);
87TC_OFFSET(struct user_regs_struct, rdi, TC_RDI);
88TC_OFFSET(struct user_regs_struct, orig_rax, TC_ORIG_RAX);
89TC_OFFSET(struct user_regs_struct, rip, TC_RIP);
90TC_OFFSET(struct user_regs_struct, cs, TC_REG_CS);
91TC_OFFSET(struct user_regs_struct, eflags, TC_EFLAGS);
92TC_OFFSET(struct user_regs_struct, rsp, TC_RSP);
93TC_OFFSET(struct user_regs_struct, ss, TC_REG_SS);
94TC_OFFSET(struct user_regs_struct, fs_base, TC_REG_FS_BASE);
95TC_OFFSET(struct user_regs_struct, gs_base, TC_REG_GS_BASE);
96TC_OFFSET(struct user_regs_struct, ds, TC_REG_DS);
97TC_OFFSET(struct user_regs_struct, es, TC_REG_ES);
98TC_OFFSET(struct user_regs_struct, fs, TC_REG_FS);
99TC_OFFSET(struct user_regs_struct, gs, TC_REG_GS);
100#undef TC_OFFSET
101
102_Static_assert(sizeof(struct tc_setup) == TC_SETUP_SIZE, "setup size");
103_Static_assert(sizeof(struct user_regs_struct) == TC_REG_SIZE, "musl register ABI changed");
104_Static_assert(sizeof(siginfo_t) == 128, "musl siginfo ABI changed");
105_Static_assert(sizeof(struct tc_capture) == TC_CAPTURE_SIZE, "capture size");
106_Static_assert(sizeof(struct tc_entry_record) == TC_ENTRY_SIZE, "entry record size");
107_Static_assert(SYS_arch_prctl == 158 && SYS_exit == 60, "entry syscall ABI");
108_Static_assert(SYS_write == 1 && SYS_getpid == 39 && SYS_tgkill == 234, "asm syscall ABI");
109_Static_assert(TC_STOP_SIGNAL == 10, "asm signal ABI");
110
111int64_t tc_now(void);
112int tc_read(int fd, void* data, size_t size);
113int tc_write(int fd, const void* data, size_t size);
114int tc_wait(pid_t pid, int* status, int milliseconds);
115void tc_cleanup(pid_t* pid);
116int tc_probe(int report_fd, struct tc_capture* capture);
117int tc_registers(void);
118
119struct tc_child {
120 pid_t pid;
121 int command, report;
122};
123#define TC_CHILD_INIT {.pid = -1, .command = -1, .report = -1}
125 int operation, signal;
126};
128 int kind, signal, code, error;
129 pid_t pid;
130 uid_t uid;
131 int64_t result;
132 uint64_t value;
133};
134extern size_t tc_page;
135extern _Thread_local volatile uint64_t tc_image_tls;
136int tc_atomic_wait(atomic_uint* value, unsigned expected);
137int tc_spawn(struct tc_child* child, int traced);
138void tc_tracee(int command, int report, int traced);
139void tc_close(struct tc_child* child);
140int tc_send(const struct tc_child* child, int operation, int signal);
141int tc_receive(int fd, int kind, struct tc_message* message);
142int tc_stop(struct tc_child* child, int signal);
143int tc_wait_stop(struct tc_child* child, int signal);
144int tc_finish(struct tc_child* child);
145int tc_resume(pid_t child, int request, int signal);
146int tc_signal_info(const siginfo_t* info, int signal, int code, pid_t pid, uid_t uid);
147int tc_inspect(void);
148int tc_signals(void);
149int tc_ownership(void);
150int tc_lifecycle(void);
151int tc_errors(void);
152int tc_exec_child(int report);
153int tc_exec_tracer(pid_t child, int command, int report);
154
155#endif