diff --git a/README.md b/README.md new file mode 100644 index 0000000..651778a --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# CoPaaS — Compiler-oriented Programming as a Service + +A startup offers an emulation service with a JIT engine for a custom instruction +set. The ISA is small and has no jumps, branches, or function calls — so it is +really just a glorified pocket calculator. You hand it a program, it compiles +that program to native x86-64 at runtime, runs it, and tells you the result. + +In the free tier, every program runs inside a sandbox. Pay for the premium tier +and the sandbox comes off — the startup trusts its paying customers. + +## How it works + +On connect you may activate premium mode, then you enter a loop: submit a +program, the service JIT-compiles and runs it, and prints the result. Repeat as +often as you like. + +Each round: + +1. You are asked for a program length `n` (`1 ≤ n ≤ 0x1000`). +2. You send `n` instructions as raw fixed-size records (see format below). +3. The service validates the program, compiles it to x86-64, and executes it. +4. It prints `Your program exited with !`, where `` is the result. + +### The machine + +- **Registers (14):** named `A`–`N`. All registers are zeroed before your program runs. +- **Result:** the program's exit code is the low 8 bits of register `A`. +- **No control flow:** there are no jumps, branches, or calls. + +### Instructions + +Each instruction is a fixed-size record with the fields: + +``` +opcode | reg1 | (padding) | reg2_or_immediate +``` + +`reg2_or_immediate` is interpreted as a second register for register-form +instructions, or as a 32-bit immediate for immediate-form instructions. + +| Opcode | Form | Effect | +| ------- | ----------------- | ------------------------------- | +| `LOADI` | `reg1, imm` | `reg1 = imm` | +| `ADDI` | `reg1, imm` | `reg1 += imm` | +| `ADD` | `reg1, reg2` | `reg1 += reg2` | +| `SUB` | `reg1, reg2` | `reg1 -= reg2` | +| `COPY` | `reg1, reg2` | `reg1 = reg2` | + +Programs are validated before compilation: any out-of-range opcode or register +is rejected and the round is discarded. The compiler also applies small +optimizations — consecutive `ADDI`s to the same register are folded together, +redundant consecutive `LOADI`s collapse to one, and a `COPY` of a register onto +itself is dropped. + +### Execution model + +- **Free / demo tier:** the compiled code runs in a forked child under a + seccomp-BPF sandbox that permits only `read`, `write`, `execve`, and + `exit_group`. The child runs on a fresh stack at a randomized address, and + `stdin`, `stdout`, and `stderr` are all closed first — so the **only** + information that leaves the child is its exit code (the low byte of `A`). +- **Premium tier:** unlocked by supplying the correct activation key. Compiled + code then runs in-process with **no sandbox**. + +### Mitigations + +Full RELRO · Stack Canary · NX · PIE + +## Goal + +Break out of the calculator and run code of your choosing — capture the flag via +`/bin/get_flag` (or a shell). The interesting surface is the JIT: what the code +generator emits for your instructions is not always what you'd expect.