# Debug, Trace, and Profiling Authority: Prior-Art Survey

Survey of how existing systems scope and gate debug, trace, and profiling
access. Each section states the verified fact and the lesson it carries for a
capability OS.

---

## 1. GDB Remote Serial Protocol (gdbstub)

The GDB Remote Serial Protocol (RSP) is the wire protocol between a GDB client
and a *gdbstub* running on or alongside the target. A stub exposes the target's
entire register file and address space to the connected client via a small set
of packet types:

- **`g`/`G`** — read and write all general-purpose registers.
- **`p`/`P`** — read and write individual registers.
- **`m`/`M`/`X`** — read and write arbitrary memory ranges.
- **`Z`/`z`** — set and clear software breakpoints, hardware breakpoints, and
  hardware watchpoints (read, write, or access).
- **`s`/`c`** — single-step and continue execution.

Feature negotiation (`qSupported`) lets client and stub advertise extensions,
but the baseline packet set already provides full read/write authority over the
target's memory and execution state.

**Lesson for capOS.** A `DebugSession` capability is not a read-only observer
— it is a read/write authority over the target's registers, memory, and control
flow. Attaching the stub to a process is itself the high-privilege act; the
session object must be issued by an explicit grant (e.g., a `ProcessSpawner`
debug grant or a `ThreadControl`-derived debug capability) rather than derived
from any lesser handle. The gdbstub pattern shows that the session boundary is
the right chokepoint: once a client holds the session capability the protocol
can proceed without further kernel checks.

---

## 2. Linux `ptrace` and the Yama LSM

### Ambient-authority problem

Linux `ptrace` originally allowed any process to `PTRACE_ATTACH` to any other
process running under the same UID that was marked as dumpable. The kernel docs
summarize the risk: "a single user is able to examine the memory and running
state of any of their processes. For example, if one application (e.g. Pidgin)
was compromised, it would be possible for an attacker to attach to other running
processes (e.g. Firefox, SSH sessions, GPG agent, etc) to extract additional
credentials and continue to expand the scope of their attack."

### Yama `ptrace_scope` levels

The Yama Linux Security Module adds a sysctl `kernel.yama.ptrace_scope` with
four levels to progressively restrict this ambient authority:

| Level | Behaviour |
|-------|-----------|
| **0** | Classic: `PTRACE_ATTACH` to any same-UID dumpable process. |
| **1** | Restricted: only descendants (or processes that have called `prctl(PR_SET_TRACER, ...)`) may be attached. |
| **2** | Admin-only: only processes holding `CAP_SYS_PTRACE` may attach. |
| **3** | No attach: `PTRACE_ATTACH` and `PTRACE_TRACEME` are blocked system-wide; the setting is irreversible once applied. |

Most Linux distributions now ship with level 1 as the default, but level 0
remains the kernel default if Yama is not loaded.

**Lesson for capOS.** Yama exists solely because ambient-authority ptrace is a
privilege-escalation footgun. The correct model is the inverse: no process
should be able to attach to another without an explicit, pre-granted capability.
In capOS terms, `DebugSession` attach must require a pre-issued debug capability
(analogous to level 3 everywhere, not level 0 with an opt-out). The parent
process or init can hold a `ThreadControl`-derived debug grant; a
`RestrictedLauncher` can be configured to never issue one. There is no ambient
fallback.

---

## 3. Linux `perf_events` and eBPF gating

### `perf_event_paranoid`

`/proc/sys/kernel/perf_event_paranoid` is the sysctl controlling
what unprivileged processes may sample:

| Value | Effect |
|-------|--------|
| **-1** | No scope or access restrictions; most permissive. |
| **≥ 0** | Raw tracepoints blocked for unprivileged users. |
| **≥ 1** | CPU-level (system-wide) profiling blocked; per-process only. |
| **≥ 2** | Kernel profiling blocked; user-space events only. |

Debian-based distributions additionally define **4** (block all perf for
unprivileged users) and use it as the distro default.

### `CAP_PERFMON` and `CAP_BPF`

Linux 5.8 introduced `CAP_PERFMON` to separate performance-monitoring authority
from the broad `CAP_SYS_ADMIN`. Holding `CAP_PERFMON` lets a process bypass
`perf_event_paranoid` scope checks. Similarly, `CAP_BPF` gates loading BPF
programs that have performance or tracing implications (e.g., kprobes, uprobes,
perf maps); attaching BPF to a kprobe tracepoint requires `CAP_PERFMON` or
`CAP_SYS_ADMIN`.

The split reflects the principle of least privilege: a profiling daemon should
not require `CAP_SYS_ADMIN` merely to sample hardware counters.

**Lesson for capOS.** Read-only sampling (hardware counters, ring buffer) is a
distinct authority from read/write debugging. capOS should issue a
`Sampler` capability (read-only, non-interrupting, no memory write) separately
from a `DebugSession` (register/memory read-write, breakpoints). The sampler
does not stop the target and transfers no writable authority; the
`perf`/`CAP_PERFMON` split is the prior-art justification for keeping these two
surfaces apart.

---

## 4. Fuchsia / Zircon: handle-scoped debug authority

### `debug_agent` and `zxdb`

On Fuchsia the debugger is split into two components: `debug_agent`, a
component running on the target that holds process handles and communicates
with the kernel, and `zxdb`, the developer-facing client that connects to
`debug_agent` over a socket. The `fuchsia.debugger` FIDL library defines the
boundary:

- **`DebugAgent`** — core protocol; `AttachTo` accepts a name pattern and
  `FilterType` to select which processes to attach to.
- **`ProcessInfoIterator`**, **`AttachedProcessIterator`** — read access to
  thread and process state.
- **`Launcher`** — creates new `DebugAgent` instances.

The `debug_agent` acquires process handles from the kernel by being granted
them through the Zircon job/process handle tree. Zircon's handle model means
that process operations (reading memory, setting breakpoints, receiving
exceptions) all require the caller to hold a process handle with the
appropriate `ZX_RIGHT_*` bits. A process that does not hold a handle to another
process cannot inspect or modify it, regardless of UID. The `zxdb` UI can
inspect handle tables of attached processes and displays their
`ZX_RIGHT_READ`/`ZX_RIGHT_WRITE`/`ZX_RIGHT_INSPECT`/`ZX_RIGHT_SIGNAL` rights
to the developer.

Exception delivery in Zircon is also capability-scoped: `zx_task_create_exception_channel`
creates a channel on a task (thread, process, or job) object; the caller must
hold that task handle. The resulting channel is read-only and can only receive
exception messages, not issue commands, which means observing crashes requires
the task handle but does not by itself grant write authority.

**Lesson for capOS.** Fuchsia demonstrates that a production debugger can be
built entirely on object-handle authority without ambient attach. The `debug_agent`
component acts like a bounded debug authority domain: it holds process handles
for the processes it is authorized to debug, and `zxdb` interacts only through
the FIDL protocol that `debug_agent` exposes. The capOS equivalent is a
`DebugSession` capability issued per target process, scoped to a running
session, with a separate read-only `ExceptionChannel` cap for crash observation.

---

## 5. seL4: TCB capability and debug-build gate

### Hardware debug API

seL4 exposes hardware breakpoints, watchpoints, and single-stepping to userspace
via TCB object methods, but only when the kernel is built with
`KernelDebugBuild` (equivalently, `HardwareDebugAPI=1` in the CMake config).
The available TCB invocations are:

- **`seL4_TCB_SetBreakpoint`** — configure a breakpoint or watchpoint (virtual
  address, access type: read/write/exec, size).
- **`seL4_TCB_GetBreakpoint`** — read the current configuration.
- **`seL4_TCB_UnsetBreakpoint`** — disable a slot.
- **`seL4_TCB_ConfigureSingleStepping`** — break on every N-th instruction.

Each invocation takes a capability to the target TCB. Only a holder of that TCB
capability can manipulate the thread's debug registers.

### Debug-only kernel syscalls

`KernelDebugBuild` also enables:

- **`seL4_DebugSnapshot`** — outputs a CapDL dump of the current kernel
  capability state to the serial console.
- **`seL4_DebugDumpScheduler`** — dumps TCB addresses, thread names,
  instruction pointers, priorities, and scheduler states.

These syscalls expose global kernel state and are intentionally excluded from
verified (proof) builds where the information flow would violate the formal
security model.

**Lesson for capOS.** seL4 gates per-thread debug authority on possession of
the TCB capability, which is the right model. capOS's `DebugSession` should
similarly be derived from `ThreadControl` so that only the process or entity
that holds `ThreadControl` for a thread can open a debug session on it.
The `seL4_DebugSnapshot` pattern also shows that a system-wide cap-table
snapshot is a separate, higher-privilege operation from per-thread debug access;
in capOS a read-only `CapTableSnapshot` authority can be issued for audit
purposes without granting register/memory write access.

---

## 6. Genode: capability-session GDB monitor

### Architecture

Genode implements user-level debugging via a *GDB monitor* component that
interposes between a target application and its parent. The GDB monitor:

1. Intercepts session requests from the target before they reach the parent.
2. Provides local virtual implementations of the **CPU service**, **RM
   (region-map/address-space) service**, and **ROM service**, wrapping the real
   core implementations.
3. Exposes a gdbserver protocol endpoint over a terminal session (TCP or UART).

This gives the GDB monitor "full control over all threads and memory objects
(dataspace) and the address space of the target." The monitor holds real
capabilities to the target's CPU and address-space sessions; the target's own
session handles are virtualized stubs that forward to the monitor.

### Capability session scoping

Genode's `Cpu_session` interface allows retrieving and modifying thread register
and execution state. The API comment in the framework explicitly notes that
these operations are "primarily designated for realizing user-level debuggers."
Because the monitor interposes the CPU session, it holds the same authority the
parent would hold, but the target holds only stubs — the target cannot see or
touch its own debug registers directly.

**Lesson for capOS.** The Genode monitor pattern reinforces that debugging
authority flows from capability delegation, not from process identity. The
interposition model also clarifies the ring-trace design decision: `debug_tap`
in capOS captures SQE/CQE ring records passively and does not require
interposing a CPU session, which keeps ring-trace authority weaker and
non-interrupting by construction. A full `DebugSession` (register read/write,
breakpoints) requires explicit session acquisition from the parent or init,
matching the Genode monitor's explicit CPU-session grant.

---

## Applicability to capOS

The cross-system survey points to a consistent set of design invariants:

1. **`DebugSession` attach is an explicit, audited capability grant, not
   ambient.** The anti-pattern is Linux ptrace at level 0; Yama level 3 is the
   correct default posture. In capOS no process inherits the ability to debug
   another: a `DebugSession` is derived from `ThreadControl`, issued by the
   process's parent or init, and recorded in the audit log.

2. **Read-only cap-table snapshots transfer no authority.** seL4's
   `seL4_DebugSnapshot` is a separate, opt-in, debug-build-only facility. In
   capOS a `CapTableSnapshot` cap can be issued for audit visibility without
   granting any write access to the observed process.

3. **Ring-trace builds on `debug_tap` and does not stop the target.**
   `perf`/`CAP_PERFMON` shows that sampling is a distinct authority class from
   full debugging. capOS `debug_tap` ring records are append-only,
   non-interrupting, and do not feed back into the target's execution — matching
   the sampler authority class, not the `DebugSession` class.

4. **Sampler does not stop the target.** Hardware performance counter sampling
   (`CAP_PERFMON` semantics) and ring-record sampling (`debug_tap`) are passive
   read surfaces. A `DebugSession` that can set breakpoints, modify registers,
   or write memory is a distinct, higher-privilege capability and must not be
   conflated with passive tracing.

5. **Exception observation is weaker than debug write authority.** Zircon's
   `zx_task_create_exception_channel` returns a read-only channel. capOS should
   provide a similar `ExceptionObserver` capability (receive crash notifications,
   no write access) independent of `DebugSession`.

---

## Sources

- GDB Remote Serial Protocol (Embecosm application note): <https://www.embecosm.com/appnotes/ean4/embecosm-howto-rsp-server-ean4-issue-2.html>
- GDB remote protocol packet reference (Apple/GNU): <https://developer.apple.com/library/archive/documentation/DeveloperTools/gdb/gdb/gdb_33.html>
- Linux kernel Yama documentation: <https://docs.kernel.org/admin-guide/LSM/Yama.html>
- Linux perf events security (kernel docs): <https://docs.kernel.org/admin-guide/perf-security.html>
- `perf_event_open(2)` man page: <https://man7.org/linux/man-pages/man2/perf_event_open.2.html>
- LWN: Introducing `CAP_PERFMON`: <https://lwn.net/Articles/816647/>
- Fuchsia `fuchsia.debugger` FIDL reference: <https://fuchsia.dev/reference/fidl/fuchsia.debugger>
- Fuchsia debugger (zxdb) overview: <https://fuchsia.dev/fuchsia-src/development/debugger>
- Fuchsia Zircon handles and rights: <https://fuchsia.dev/fuchsia-src/concepts/kernel/handles>
- Fuchsia exception handling: <https://fuchsia.dev/fuchsia-src/concepts/kernel/exceptions>
- seL4 API reference (debug syscalls and TCB hardware debug): <https://docs.sel4.systems/projects/sel4/api-doc.html>
- seL4 hardware debug tutorial: <https://docs.sel4.systems/projects/sel4-tutorials/debugging-userspace.html>
- seL4 kernel configurations (`KernelDebugBuild`): <https://docs.sel4.systems/projects/sel4/configurations.html>
- Genode GDB developer resources: <https://genode.org/documentation/developer-resources/gdb>
- Genode session interfaces (CPU session): <https://genode.org/documentation/genode-foundations/20.05/functional_specification/Session_interfaces_of_the_base_API.html>
