mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-27 20:29:39 +02:00
[pitboss] phase 08: Track C.4 + C.5 — SinkCrash oracle + per-probe witness capture
This commit is contained in:
parent
4eccbd48b4
commit
93eb98edda
21 changed files with 1988 additions and 115 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
"#
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue