[pitboss] phase 08: Track C.4 + C.5 — SinkCrash oracle + per-probe witness capture

This commit is contained in:
pitboss 2026-05-14 13:10:22 -05:00
parent 4eccbd48b4
commit 93eb98edda
21 changed files with 1988 additions and 115 deletions

View file

@ -23,12 +23,101 @@ const SUPPORTED: &[EntryKind] = &[EntryKind::Function];
/// the only dep on libc / stdio.
pub fn probe_shim() -> &'static str {
r#"
/* ── __nyx_probe shim (Phase 06 — Track C.1) ─────────────────────────────── */
/* ── __nyx_probe shim (Phase 06 — Track C.1, Phase 08 — Track C.4 + C.5) ── */
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#ifndef __NYX_PAYLOAD_LIMIT
#define __NYX_PAYLOAD_LIMIT (16 * 1024)
#endif
#define __NYX_REDACTED "<redacted-by-nyx-policy>"
extern char **environ;
static const char *__nyx_deny[] = {
"TOKEN","SECRET","PASSWORD","PASSWD","API_KEY","APIKEY","PRIVATE_KEY",
"CREDENTIAL","SESSION","COOKIE","AUTH","BEARER","AWS_ACCESS","AWS_SESSION",
"GH_TOKEN","GITHUB_TOKEN","NPM_TOKEN","PYPI_TOKEN","DOCKER_PASS",
NULL,
};
static int __nyx_is_denied_upper(const char *k_upper) {
for (int i = 0; __nyx_deny[i]; ++i) {
if (strstr(k_upper, __nyx_deny[i])) return 1;
}
return 0;
}
static void __nyx_write_witness(FILE *f, const char *sink_callee, int nargs, const char **args) {
fputs("{\"env_snapshot\":{", f);
int first = 1;
for (char **e = environ; *e; ++e) {
const char *eq = strchr(*e, '=');
if (!eq) continue;
size_t klen = (size_t)(eq - *e);
char *kup = (char *)malloc(klen + 1);
if (!kup) continue;
for (size_t i = 0; i < klen; ++i) {
char c = (*e)[i];
if (c >= 'a' && c <= 'z') c -= 32;
kup[i] = c;
}
kup[klen] = '\0';
int denied = __nyx_is_denied_upper(kup);
if (!first) fputc(',', f);
first = 0;
fputc('"', f);
fwrite(*e, 1, klen, f);
fputs("\":\"", f);
if (denied) {
fputs(__NYX_REDACTED, f);
} else {
const char *v = eq + 1;
for (; *v; ++v) {
switch (*v) {
case '"': fputs("\\\"", f); break;
case '\\': fputs("\\\\", f); break;
case '\n': fputs("\\n", f); break;
case '\r': fputs("\\r", f); break;
case '\t': fputs("\\t", f); break;
default: fputc(*v, f);
}
}
}
fputc('"', f);
free(kup);
}
fputs("},\"cwd\":\"", f);
char cwdbuf[4096];
if (getcwd(cwdbuf, sizeof(cwdbuf))) {
fputs(cwdbuf, f);
}
fputs("\",\"payload_bytes\":[", f);
const char *payload = getenv("NYX_PAYLOAD");
if (payload) {
size_t plen = strlen(payload);
if (plen > __NYX_PAYLOAD_LIMIT) plen = __NYX_PAYLOAD_LIMIT;
for (size_t i = 0; i < plen; ++i) {
if (i > 0) fputc(',', f);
fprintf(f, "%d", (unsigned char)payload[i]);
}
}
fputs("],\"callee\":\"", f);
fputs(sink_callee, f);
fputs("\",\"args_repr\":[", f);
for (int i = 0; i < nargs; ++i) {
if (i > 0) fputc(',', f);
fputc('"', f);
if (args && args[i]) fputs(args[i], f);
fputc('"', f);
}
fputs("]}", f);
}
static void __nyx_probe(const char *sink_callee, int nargs, ...) {
const char *p = getenv("NYX_PROBE_PATH");
@ -44,16 +133,77 @@ static void __nyx_probe(const char *sink_callee, int nargs, ...) {
fprintf(f, "{\"sink_callee\":\"%s\",\"args\":[", sink_callee);
va_list ap;
va_start(ap, nargs);
const char *args_arr[32];
int captured = nargs > 32 ? 32 : nargs;
for (int i = 0; i < nargs; ++i) {
const char *arg = va_arg(ap, const char *);
if (!arg) arg = "";
if (i < captured) args_arr[i] = arg;
if (i > 0) fputc(',', f);
fprintf(f, "{\"kind\":\"String\",\"value\":\"%s\"}", arg);
}
va_end(ap);
fprintf(f, "],\"captured_at_ns\":%llu,\"payload_id\":\"%s\"}\n", ns, pid);
fprintf(f, "],\"captured_at_ns\":%llu,\"payload_id\":\"%s\",", ns, pid);
fputs("\"kind\":{\"kind\":\"Normal\"},\"witness\":", f);
__nyx_write_witness(f, sink_callee, captured, args_arr);
fputs("}\n", f);
fclose(f);
}
/* Phase 08: sink-site signal handler. __nyx_install_crash_guard sets a
* sigaction(2) handler over SIGSEGV / SIGABRT / SIGBUS / SIGFPE / SIGILL
* that writes a Crash probe with witness before restoring SIG_DFL and
* re-raising the signal the process still dies with the same exit
* code, but the probe channel now carries the forensic record. */
static const char *__nyx_crash_sink_callee = "";
static void __nyx_crash_handler(int sig) {
const char *p = getenv("NYX_PROBE_PATH");
if (p && *p) {
FILE *f = fopen(p, "a");
if (f) {
const char *name = "SIGABRT";
switch (sig) {
case SIGSEGV: name = "SIGSEGV"; break;
case SIGABRT: name = "SIGABRT"; break;
case SIGBUS: name = "SIGBUS"; break;
case SIGFPE: name = "SIGFPE"; break;
case SIGILL: name = "SIGILL"; break;
}
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
unsigned long long ns = (unsigned long long)ts.tv_sec * 1000000000ULL +
(unsigned long long)ts.tv_nsec;
const char *pid = getenv("NYX_PAYLOAD_ID");
if (!pid) pid = "";
fprintf(f,
"{\"sink_callee\":\"%s\",\"args\":[],\"captured_at_ns\":%llu,"
"\"payload_id\":\"%s\",\"kind\":{\"kind\":\"Crash\",\"signal\":\"%s\"},"
"\"witness\":",
__nyx_crash_sink_callee, ns, pid, name);
__nyx_write_witness(f, __nyx_crash_sink_callee, 0, NULL);
fputs("}\n", f);
fclose(f);
}
}
struct sigaction dfl;
memset(&dfl, 0, sizeof(dfl));
dfl.sa_handler = SIG_DFL;
sigaction(sig, &dfl, NULL);
raise(sig);
}
static void __nyx_install_crash_guard(const char *sink_callee) {
__nyx_crash_sink_callee = sink_callee;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = __nyx_crash_handler;
sigemptyset(&sa.sa_mask);
int sigs[] = { SIGSEGV, SIGABRT, SIGBUS, SIGFPE, SIGILL };
for (size_t i = 0; i < sizeof(sigs)/sizeof(sigs[0]); ++i) {
sigaction(sigs[i], &sa, NULL);
}
}
"#
}