commit 056b9939639819c1a2e85f0e73fc02dda5b27b78 from: Isaac Meerleo date: Wed Jul 15 14:35:35 2026 UTC centralize imsg payload views commit - 70b68b95fb01cb2b260ca9a92849088b4ee34fb2 commit + 056b9939639819c1a2e85f0e73fc02dda5b27b78 blob - 004de43f19fb128200743738afea48b0a2631923 blob + 2d9b5159b468ad7de6156909a7d880704f13c4ca --- regress/Makefile +++ regress/Makefile @@ -1,4 +1,4 @@ -SUBDIR= agentcfg anthropic buf conf deploy diff editor http journal json log markdown \ +SUBDIR= agentcfg anthropic buf conf deploy diff editor http imsgev journal json log markdown \ model_window openai output print sandbox skills sse term tools turn web xmalloc .include blob - d397b20feb0f182630b200d95785c71f75775960 blob + 5d18e65afa8d09013140fc89fe12daa92eeb6006 --- regress/README +++ regress/README @@ -43,8 +43,9 @@ I9 privileges only narrow sandbox (each role reaches steady pledge before untrusted input; forbidden syscalls trip PLDG violations) -I10 mutual distrust across roles imsg length/type validation in - worker.c/coord.c; hub-and-spoke +I10 mutual distrust across roles imsgev (partially consumed payloads + fail closed); imsg length/type + validation in worker.c/coord.c; hub-and-spoke authority map in proto.h; turn (a hostile second terminal cannot flip a committed turn; a tool @@ -60,7 +61,8 @@ I12 no ambient privilege no setuid, no daemon, no soc (coord.c); tools proves anchored process-group cleanup even after forced executor death -I13 length-aware strings buf, json (NUL round-trip), +I13 length-aware strings buf, json (NUL round-trip), imsgev + (empty and embedded-NUL payload views), sse (NUL transparency), anthropic, openai, http, web, output (NUL-bearing framing, headers, bodies, @@ -171,7 +173,9 @@ src/fugu/agentcfg.c agentcfg; turn (live schema/rout src/fugu/priv.c, coord.c sandbox (spawn/handshake/teardown), turn (lead and subagent turn loops) src/fugu/journal.c journal, turn -src/common/imsgev.c, worker.c sandbox (worker runtime) +src/common/imsgev.c imsgev (whole-payload views); sandbox + (event runtime) +src/common/worker.c sandbox (worker runtime) src/fugu-api (request/stream) turn (correlated concurrent lead/agent requests), print (deadline/retry/long-key reflection), openai (real requests + SSE) blob - /dev/null blob + 93314c1cf5366d4e2cbfa834d399e80834883a5f (mode 644) --- /dev/null +++ regress/imsgev/Makefile @@ -0,0 +1,7 @@ +PROG= imsgev_test +SRCS= imsgev_test.c imsgev.c log.c + +LDADD= -levent -lutil +DPADD= ${LIBEVENT} ${LIBUTIL} + +.include blob - /dev/null blob + f2fdf7f0d1295eab089010d5678c8daf04235d2d (mode 644) --- /dev/null +++ regress/imsgev/imsgev_test.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2026 Isaac + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "imsgev.h" + +#include "regress.h" + +static void +make_imsg(const void *data, size_t len, struct imsgbuf *receiver, + struct imsg *imsg) +{ + struct imsgbuf sender; + int fds[2]; + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, fds) == -1) + err(1, "socketpair"); + if (imsgbuf_init(&sender, fds[0]) == -1) + err(1, "imsgbuf_init sender"); + if (imsgbuf_init(receiver, fds[1]) == -1) + err(1, "imsgbuf_init receiver"); + if (imsg_compose(&sender, 1, 0, -1, -1, data, len) == -1) + err(1, "imsg_compose"); + if (imsgbuf_flush(&sender) == -1) + err(1, "imsgbuf_flush"); + if (imsgbuf_read(receiver) != 1) + errx(1, "imsgbuf_read"); + if (imsgbuf_get(receiver, imsg) != 1) + errx(1, "imsgbuf_get"); + imsgbuf_clear(&sender); + close(fds[0]); + close(fds[1]); +} + +int +main(void) +{ + static const u_char binary[] = { 'a', '\0', 'b' }; + struct imsgev_payload payload; + struct imsgbuf receiver; + struct imsg imsg; + u_char byte; + + make_imsg(NULL, 0, &receiver, &imsg); + payload.data = (const u_char *)1; + payload.len = 1; + CHECK(imsgev_get_payload(&imsg, &payload) == 0); + CHECK(payload.data == NULL); + CHECK(payload.len == 0); + imsg_free(&imsg); + imsgbuf_clear(&receiver); + + make_imsg(binary, sizeof(binary), &receiver, &imsg); + CHECK(imsgev_get_payload(&imsg, &payload) == 0); + CHECK(payload.len == sizeof(binary)); + CHECK(payload.data != NULL && + memcmp(payload.data, binary, sizeof(binary)) == 0); + imsg_free(&imsg); + imsgbuf_clear(&receiver); + + make_imsg(binary, sizeof(binary), &receiver, &imsg); + CHECK(imsg_get_buf(&imsg, &byte, sizeof(byte)) == 0); + CHECK(byte == 'a'); + payload.data = (const u_char *)1; + payload.len = SIZE_MAX; + errno = 0; + CHECK(imsgev_get_payload(&imsg, &payload) == -1); + CHECK(errno == EBADMSG); + CHECK(payload.data == NULL); + CHECK(payload.len == 0); + imsg_free(&imsg); + imsgbuf_clear(&receiver); + + REGRESS_END(); +} blob - 2cee5e52e25388738c7402a78e90bdad830f7263 blob + eae76c222a9645b9bd3757daa9fcf0204a9b45c7 --- src/common/imsgev.c +++ src/common/imsgev.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -67,6 +68,34 @@ imsgev_compose(struct imsgev *iev, uint32_t type, uint return (ret); } +int +imsgev_get_payload(struct imsg *imsg, struct imsgev_payload *payload) +{ + struct ibuf ib; + size_t len; + + payload->data = NULL; + payload->len = 0; + if (imsg->hdr.len < IMSG_HEADER_SIZE) { + errno = EBADMSG; + return (-1); + } + len = imsg_get_len(imsg); + if (len != imsg->hdr.len - IMSG_HEADER_SIZE) { + errno = EBADMSG; + return (-1); + } + if (len == 0) + return (0); + if (imsg_get_ibuf(imsg, &ib) == -1 || ibuf_size(&ib) != len) { + errno = EBADMSG; + return (-1); + } + payload->data = ibuf_data(&ib); + payload->len = ibuf_size(&ib); + return (0); +} + void imsgev_clear(struct imsgev *iev) { blob - 912e02e97f21c2bd74e1163842b466f0df041b0e blob + c19e3d504553e550f77a3268b8d2a63617840730 --- src/common/imsgev.h +++ src/common/imsgev.h @@ -33,11 +33,22 @@ struct imsgev { short events; }; +/* + * A whole, unconsumed imsg payload. The bytes are borrowed until + * imsg_free(). An empty payload is a successful { NULL, 0 } view; + * malformed or previously consumed payloads fail with EBADMSG. + */ +struct imsgev_payload { + const u_char *data; + size_t len; +}; + void imsgev_init(struct imsgev *, int, void (*)(int, short, void *), void *); void imsgev_add(struct imsgev *); int imsgev_compose(struct imsgev *, uint32_t, uint32_t, pid_t, int, const void *, size_t); +int imsgev_get_payload(struct imsg *, struct imsgev_payload *); void imsgev_clear(struct imsgev *); #endif /* IMSGEV_H */ blob - 5b7aab176b5f31d13771bcc71ec0e14336c9c592 blob + 6a041592b8100a7964a10178d9a337589172090f --- src/fugu/coord.c +++ src/fugu/coord.c @@ -469,19 +469,6 @@ msg_count(const struct msglist *l) return (n); } -static const u_char * -imsg_bytes(struct imsg *imsg, size_t *lenp) -{ - struct ibuf ib; - - if (imsg_get_len(imsg) == 0 || imsg_get_ibuf(imsg, &ib) == -1) { - *lenp = 0; - return (NULL); - } - *lenp = ibuf_size(&ib); - return (ibuf_data(&ib)); -} - static int protect_has(const struct buf *b, const char *path) { @@ -1134,6 +1121,7 @@ send_ui_config(struct coord *c) static void stream_event(struct coord *c, struct imsg *imsg) { + struct imsgev_payload payload; const u_char *p; size_t len; uint32_t type = imsg_get_type(imsg); @@ -1150,7 +1138,10 @@ stream_event(struct coord *c, struct imsg *imsg) if (imsg_get_id(imsg) != c->lead_api_id) fatalx("lead provider correlation mismatch"); - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get provider stream payload"); + p = payload.data; + len = payload.len; switch (type) { case FUGU_IMSG_A_TEXT: @@ -1301,12 +1292,16 @@ stream_event(struct coord *c, struct imsg *imsg) static void tool_event(struct coord *c, struct imsg *imsg) { + struct imsgev_payload payload; const u_char *p; size_t len; if (c->wait != WAIT_TOOL) return; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get tool result payload"); + p = payload.data; + len = payload.len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_TOOL_OUT: @@ -1349,10 +1344,14 @@ static void tool_ctl_event(struct coord *c, struct imsg *imsg) { struct tool_turn_ack ack; + struct imsgev_payload payload; const u_char *p; size_t len; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get tool Turn ACK payload"); + p = payload.data; + len = payload.len; if (c->tool_ctl_expected == 0 || p == NULL || len != sizeof(ack)) fatalx("unexpected tool Turn ACK"); memcpy(&ack, p, sizeof(ack)); @@ -1367,6 +1366,7 @@ tool_ctl_event(struct coord *c, struct imsg *imsg) static void web_event(struct coord *c, struct imsg *imsg) { + struct imsgev_payload payload; const u_char *p; size_t len; @@ -1374,7 +1374,10 @@ web_event(struct coord *c, struct imsg *imsg) return; if (imsg_get_id(imsg) != c->web_id) fatalx("web result correlation mismatch"); - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get web result payload"); + p = payload.data; + len = payload.len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_WEB_OUT: @@ -1418,12 +1421,16 @@ web_event(struct coord *c, struct imsg *imsg) static void ctx_event(struct coord *c, struct imsg *imsg) { + struct imsgev_payload payload; const u_char *p; size_t len; if (c->wait != WAIT_CTX) return; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get project context payload"); + p = payload.data; + len = payload.len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_CTX_DATA: @@ -1492,10 +1499,14 @@ configured_provider_name(const struct coord *c, int sl static void ui_event(struct coord *c, struct imsg *imsg) { + struct imsgev_payload payload; const u_char *p; size_t len; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get UI input payload"); + p = payload.data; + len = payload.len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_UI_SUBMIT: /* A submit only lands while idle: mid-turn, the tty queues @@ -1629,12 +1640,16 @@ ui_event(struct coord *c, struct imsg *imsg) static void model_event(struct coord *c, struct imsg *imsg) { + struct imsgev_payload payload; const u_char *p; size_t len; if (!c->ui) return; /* line mode never asks (2.2) */ - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get model listing payload"); + p = payload.data; + len = payload.len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_MODEL: { @@ -1710,10 +1725,14 @@ model_event(struct coord *c, struct imsg *imsg) static void compose_event(struct coord *c, struct imsg *imsg) { + struct imsgev_payload payload; const u_char *p; size_t len; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get compose payload"); + p = payload.data; + len = payload.len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_UI_COMPOSE: if (len == 0) @@ -1873,13 +1892,17 @@ agent_web_start_next(struct coord *c) static void agent_provider_event(struct subagent *a, struct imsg *imsg) { + struct imsgev_payload payload; const u_char *p; size_t len; uint32_t type = imsg_get_type(imsg); if (!a->api_inflight) fatalx("provider event for idle subagent"); - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get relayed provider payload"); + p = payload.data; + len = payload.len; if (!a->done && imsgev_compose(&a->iev, type, 0, -1, -1, p, len) == -1) fatal("relay provider event to subagent"); if (type == FUGU_IMSG_A_DONE || type == FUGU_IMSG_A_ERROR) @@ -1892,6 +1915,7 @@ static void agent_web_event(struct subagent *a, struct imsg *imsg) { struct coord *c = a->coord; + struct imsgev_payload payload; const u_char *p; size_t len; uint32_t outtype; @@ -1899,7 +1923,10 @@ agent_web_event(struct subagent *a, struct imsg *imsg) if (!a->web_inflight || c->agent_web_active != a || c->web_busy_id != a->web_id || imsg_get_id(imsg) != a->web_id) fatalx("web event for idle subagent"); - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get relayed web payload"); + p = payload.data; + len = payload.len; if (imsg_get_type(imsg) == FUGU_IMSG_WEB_OUT) outtype = FUGU_IMSG_AGENT_WEB_OUT; else if (imsg_get_type(imsg) == FUGU_IMSG_WEB_RESULT) @@ -2244,6 +2271,7 @@ agent_dispatch(int fd, short event, void *arg) struct coord *c = a->coord; struct imsgbuf *ibuf = &a->iev.ibuf; struct imsg imsg; + struct imsgev_payload payload; const u_char *p; struct tool_req req; ssize_t n; @@ -2293,7 +2321,10 @@ agent_dispatch(int fd, short event, void *arg) if (n == 0) break; type = imsg_get_type(&imsg); - p = imsg_bytes(&imsg, &len); + if (imsgev_get_payload(&imsg, &payload) == -1) + fatal("get subagent broker payload"); + p = payload.data; + len = payload.len; switch (type) { case FUGU_IMSG_READY: if (len != 0 || a->ready) blob - 0d4591c227b88282ec35a94f224dd3819ac44845 blob + 2935e1ff82c36ffc61949854b34bf9e6fe29eda1 --- src/fugu-api/main.c +++ src/fugu-api/main.c @@ -221,20 +221,6 @@ ca_path(void) return (tls_default_ca_cert_file()); } -/* A read-only view of an imsg's payload; valid until imsg_free. */ -static const u_char * -imsg_bytes(struct imsg *imsg, size_t *lenp) -{ - struct ibuf ib; - - if (imsg_get_len(imsg) == 0 || imsg_get_ibuf(imsg, &ib) == -1) { - *lenp = 0; - return (NULL); - } - *lenp = ibuf_size(&ib); - return (ibuf_data(&ib)); -} - /* A key crosses the wire as trailing bytes; it feeds an HTTP header, * so it must be NUL-free (I13). */ static char * @@ -276,11 +262,15 @@ api_lockdown(struct worker *w, struct imsg *imsg) { struct api *a = w->ctx; struct hello_api h; + struct imsgev_payload payload; struct prov *v; const u_char *p; size_t len; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get API HELLO payload"); + p = payload.data; + len = payload.len; if (p == NULL || len < sizeof(h)) fatalx("fugu-api: short HELLO"); memcpy(&h, p, sizeof(h)); @@ -321,11 +311,15 @@ static void prov_add(struct api *a, struct imsg *imsg) { struct hello_prov hp; + struct imsgev_payload payload; struct prov *v; const u_char *p; size_t len; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get PROV payload"); + p = payload.data; + len = payload.len; if (p == NULL || len < sizeof(hp)) fatalx("fugu-api: short PROV"); memcpy(&hp, p, sizeof(hp)); @@ -1817,14 +1811,19 @@ api_dispatch(struct worker *w, struct imsg *imsg) { struct api *a = w->ctx; struct api_request *r; + struct imsgev_payload payload; size_t len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_REQUEST: { - const u_char *p = imsg_bytes(imsg, &len); + const u_char *p; uint32_t id = imsg_get_id(imsg); size_t cap, growth; + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get REQUEST payload"); + p = payload.data; + len = payload.len; if ((r = request_find(a, id)) == NULL) r = request_new(w, id); if (r->phase != REQ_ASSEMBLY && r->phase != REQ_REJECTED) blob - fb3c99fc91d2262de753a404e38cb12639ff8994 blob + 7840fd7766fb54edcb5b70b8462764f98d184973 --- src/fugu-editor/main.c +++ src/fugu-editor/main.c @@ -53,20 +53,6 @@ static struct buf seed; /* accumulated EDIT_SEED chu static volatile sig_atomic_t edit_child; /* running editor pgid */ static char edit_path[64]; /* the live temp file, for SIGTERM cleanup */ -/* Borrow an imsg's payload bytes (length-checked by the caller). */ -static const u_char * -imsg_bytes(struct imsg *imsg, size_t *lenp) -{ - struct ibuf ib; - - if (imsg_get_len(imsg) == 0 || imsg_get_ibuf(imsg, &ib) == -1) { - *lenp = 0; - return (NULL); - } - *lenp = ibuf_size(&ib); - return (ibuf_data(&ib)); -} - /* A coordinator death mid-compose must not orphan the user's editor or * leave the seeded temp file behind ("the temp file never survives"). */ static void @@ -311,12 +297,16 @@ compose(struct worker *w) static int edit_dispatch(struct worker *w, struct imsg *imsg) { + struct imsgev_payload payload; const u_char *p; size_t len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_EDIT_SEED: - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get EDIT_SEED payload"); + p = payload.data; + len = payload.len; if (p == NULL || seed.len + len > FUGU_EDIT_MAX) fatalx("compose seed overrun"); /* I10, fail closed */ buf_add(&seed, p, len); blob - d37bcaf8fb50b8ec2b9e2ed1e60476b21a7b9895 blob + 83c5b7c960279f612572e5e849cb4f2e3152ad0b --- src/fugu-tool/agent.c +++ src/fugu-tool/agent.c @@ -229,19 +229,6 @@ agent_boot_prompt(struct agent_boot *b, const void *da return (0); } -static const u_char * -frame_bytes(struct imsg *imsg, size_t *lenp) -{ - struct ibuf ib; - - if (imsg_get_len(imsg) == 0 || imsg_get_ibuf(imsg, &ib) == -1) { - *lenp = 0; - return (NULL); - } - *lenp = ibuf_size(&ib); - return (ibuf_data(&ib)); -} - static void agent_send(struct agent_state *a, uint32_t type, const void *data, size_t len) { @@ -416,6 +403,7 @@ agent_generation(struct agent_state *a, const struct t { struct buf body; struct imsg imsg; + struct imsgev_payload payload; const u_char *p; size_t len; uint32_t type; @@ -439,7 +427,10 @@ agent_generation(struct agent_state *a, const struct t while (agent_next(a, &imsg)) { type = imsg_get_type(&imsg); - p = frame_bytes(&imsg, &len); + if (imsgev_get_payload(&imsg, &payload) == -1) + fatal("get subagent provider payload"); + p = payload.data; + len = payload.len; switch (type) { case FUGU_IMSG_A_TEXT: if (len > FUGU_RESPONSE_MAX - a->text.len) { @@ -564,6 +555,7 @@ agent_web(struct agent_state *a, struct agent_tcall *t struct tool_req req; struct tool_result result; struct imsg imsg; + struct imsgev_payload payload; const u_char *p; size_t len; @@ -576,7 +568,10 @@ agent_web(struct agent_state *a, struct agent_tcall *t buf_reset(out); *is_error = 1; while (agent_next(a, &imsg)) { - p = frame_bytes(&imsg, &len); + if (imsgev_get_payload(&imsg, &payload) == -1) + fatal("get subagent web payload"); + p = payload.data; + len = payload.len; switch (imsg_get_type(&imsg)) { case FUGU_IMSG_AGENT_WEB_OUT: if (p == NULL || len == 0 || len > FUGU_WEB_OUT_MAX - out->len) blob - b06198cd808cda70d20ee3537d1329ccc42fd8ce blob + 2f07ba49a039d9992f3210584cd7ced3f6ef9042 --- src/fugu-tool/main.c +++ src/fugu-tool/main.c @@ -101,20 +101,6 @@ pump_jobs(int fd, short ev, void *arg) job_pump(ts->ctx->jobs); } -/* A read-only view of an imsg's payload; valid until imsg_free. */ -static const u_char * -imsg_bytes(struct imsg *imsg, size_t *lenp) -{ - struct ibuf ib; - - if (imsg_get_len(imsg) == 0 || imsg_get_ibuf(imsg, &ib) == -1) { - *lenp = 0; - return (NULL); - } - *lenp = ibuf_size(&ib); - return (ibuf_data(&ib)); -} - /* * Unveil the protect entries away with empty permissions (I5/I9). * @@ -236,11 +222,15 @@ tool_lockdown(struct worker *w, struct imsg *imsg) { struct tool_state *ts = w->ctx; struct hello_tool h; + struct imsgev_payload payload; const u_char *p; size_t len; int passed_fd, snapshot_fd, write_ok, net_ok; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get tool HELLO payload"); + p = payload.data; + len = payload.len; if (p == NULL || len < sizeof(h)) fatalx("fugu-tool: short HELLO"); memcpy(&h, p, sizeof(h)); @@ -399,22 +389,32 @@ static int tool_dispatch(struct worker *w, struct imsg *imsg) { struct tool_state *ts = w->ctx; + struct imsgev_payload payload; const u_char *p; size_t len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_AGENT_START: - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get AGENT_START payload"); + p = payload.data; + len = payload.len; if (!ts->agent || agent_boot_start(&ts->boot, p, len) == -1) fatalx("fugu-tool: bad AGENT_START"); return (0); case FUGU_IMSG_AGENT_SYSTEM: - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get AGENT_SYSTEM payload"); + p = payload.data; + len = payload.len; if (!ts->agent || agent_boot_system(&ts->boot, p, len) == -1) fatalx("fugu-tool: bad AGENT_SYSTEM"); return (0); case FUGU_IMSG_AGENT_PROMPT: - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get AGENT_PROMPT payload"); + p = payload.data; + len = payload.len; if (!ts->agent || agent_boot_prompt(&ts->boot, p, len) == -1) fatalx("fugu-tool: bad AGENT_PROMPT"); return (0); @@ -451,7 +451,10 @@ tool_dispatch(struct worker *w, struct imsg *imsg) case FUGU_IMSG_TOOL_REQ: { struct tool_req req; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get TOOL_REQ payload"); + p = payload.data; + len = payload.len; if (p == NULL || len < sizeof(req)) fatalx("fugu-tool: short TOOL_REQ"); memcpy(&req, p, sizeof(req)); @@ -462,7 +465,10 @@ tool_dispatch(struct worker *w, struct imsg *imsg) return (0); } case FUGU_IMSG_TOOL_ARG: - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get TOOL_ARG payload"); + p = payload.data; + len = payload.len; if (ts->arg.len + len > FUGU_TOOL_ARG_MAX) fatalx("fugu-tool: tool input too large"); if (p != NULL && len > 0) @@ -474,7 +480,10 @@ tool_dispatch(struct worker *w, struct imsg *imsg) size_t off; /* the payload is a NUL-terminated path (coordinator-built) */ - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get CTX_READ payload"); + p = payload.data; + len = payload.len; if (p == NULL || len == 0 || len >= sizeof(path) || memchr(p, '\0', len) != NULL) fatalx("fugu-tool: bad CTX_READ"); @@ -501,7 +510,10 @@ tool_dispatch(struct worker *w, struct imsg *imsg) size_t plen; /* path '\0' bullet-bytes */ - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get CTX_APPEND payload"); + p = payload.data; + len = payload.len; if (p == NULL || (plen = strnlen((const char *)p, len)) == len) fatalx("fugu-tool: bad CTX_APPEND"); path = (const char *)p; blob - 28f63779f1fa42debfdf0de1872100134d910011 blob + a3bfff69f738ee02517ed6fd50a3bd136efdecc8 --- src/fugu-tty/ui.c +++ src/fugu-tty/ui.c @@ -162,20 +162,6 @@ struct ui { static struct ui *UI; /* for the atexit terminal restore */ -/* Borrow an imsg's payload bytes (length-checked by the caller). */ -static const u_char * -imsg_bytes(struct imsg *imsg, size_t *lenp) -{ - struct ibuf ib; - - if (imsg_get_len(imsg) == 0 || imsg_get_ibuf(imsg, &ib) == -1) { - *lenp = 0; - return (NULL); - } - *lenp = ibuf_size(&ib); - return (ibuf_data(&ib)); -} - /* ---- small helpers -------------------------------------------------- */ static int @@ -1531,12 +1517,16 @@ int ui_render(struct worker *w, struct imsg *imsg) { struct ui *u = w->ctx; + struct imsgev_payload payload; const u_char *p; size_t len; if (u == NULL) return (-1); - p = imsg_bytes(imsg, &len); /* fetched once: the ibuf is consumed */ + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get UI payload"); + p = payload.data; + len = payload.len; switch (imsg_get_type(imsg)) { case FUGU_IMSG_UI_CONFIG: blob - 7e6959a1391bfc8c861ed9768748cdee3b54e804 blob + efcc30a384f2600ea0ffd58567d501f97d1025dc --- src/fugu-web/main.c +++ src/fugu-web/main.c @@ -58,19 +58,6 @@ struct web_state { static struct web_state *web_cleanup_state; -static const u_char * -imsg_bytes(struct imsg *imsg, size_t *lenp) -{ - struct ibuf ib; - - if (imsg_get_len(imsg) == 0 || imsg_get_ibuf(imsg, &ib) == -1) { - *lenp = 0; - return (NULL); - } - *lenp = ibuf_size(&ib); - return (ibuf_data(&ib)); -} - static const char * env_or(const char *name, const char *fallback) { @@ -124,10 +111,14 @@ web_lockdown(struct worker *w, struct imsg *imsg) { struct web_state *ws = w->ctx; struct hello_web h; + struct imsgev_payload payload; const u_char *p, *token, *allow, *block; size_t len, left, providerlen; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get web HELLO payload"); + p = payload.data; + len = payload.len; if (p == NULL || len < sizeof(h) || len > FUGU_WEB_HELLO_MAX) fatalx("fugu-web: malformed HELLO"); memcpy(&h, p, sizeof(h)); @@ -227,6 +218,7 @@ static int web_dispatch(struct worker *w, struct imsg *imsg) { struct web_state *ws = w->ctx; + struct imsgev_payload payload; const u_char *p; size_t len, i, namelen; @@ -234,7 +226,10 @@ web_dispatch(struct worker *w, struct imsg *imsg) case FUGU_IMSG_WEB_REQ: { struct tool_req req; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get WEB_REQ payload"); + p = payload.data; + len = payload.len; if (p == NULL || len != sizeof(req) || ws->have_name || imsg_get_id(imsg) == 0) fatalx("fugu-web: malformed WEB_REQ"); @@ -252,7 +247,10 @@ web_dispatch(struct worker *w, struct imsg *imsg) return (0); } case FUGU_IMSG_WEB_ARG: - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get WEB_ARG payload"); + p = payload.data; + len = payload.len; if (!ws->have_name || imsg_get_id(imsg) != ws->reqid || p == NULL || len == 0 || len > FUGU_WEB_ARG_MAX - ws->arg.len) @@ -264,7 +262,10 @@ web_dispatch(struct worker *w, struct imsg *imsg) struct buf out; int is_error; - p = imsg_bytes(imsg, &len); + if (imsgev_get_payload(imsg, &payload) == -1) + fatal("get WEB_RUN payload"); + p = payload.data; + len = payload.len; if (p != NULL || len != 0 || !ws->have_name || imsg_get_id(imsg) != ws->reqid) fatalx("fugu-web: malformed WEB_RUN");