added README
This commit is contained in:
73
README.md
Normal file
73
README.md
Normal file
@@ -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 <code>!`, where `<code>` 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.
|
||||||
Reference in New Issue
Block a user