mirror of
https://dev.lirent.ru/Vatrog/vm-automation-signaling.git
synced 2026-06-26 04:36:37 +03:00
memwrite: per-process (cr3) target and full-extent socket SRC
- CMD_MEMWRITE now carries a target page-table root (cr3) as its first field; cr3 == 0 keeps the kernel address-space default (backward-compatible). A control that has discovered a process's cr3 through its own read-only perception can write that process's private memory under the same exclusive write lease. Freshness of the cr3 is the control's responsibility — signaling does not validate it (that is perception, not coherence), mirroring the read side. - A socket control can now carry an SRC larger than the inline frame budget: a length-prefixed SRC tail follows the CMD_MEMWRITE frame (flag SRC_PAYLOAD, the length being the frame's own len). A per-connection two-phase receiver accumulates the tail into a fixed conn-owned buffer up to the extent bound, matching the in-process payload path. A zero or over-bound length is a framing violation that closes the connection: leaving the promised tail unread would desync the stream and draining an arbitrary length would be a denial of service. The capability, exclusive lease, source and extent gates are unchanged and reused; only the event header gained the cr3 field and the socket transport gained the tail receiver. The adapter resolves cr3 == 0 to the kernel root on its worker thread and writes atomically.
This commit is contained in:
@@ -59,11 +59,13 @@ enum { MC_JOB_BOOTSTRAP = 0, MC_JOB_WRITE = 1 };
|
||||
/* worker req/res (POD <= VMSIG_WORK_SLOT). One off-loop worker runs BOTH the cold
|
||||
* bootstrap and the atomic writes (FIFO serializes a write against the close-on-rebootstrap).
|
||||
* boot_count drives the stub kcr3 (changes per epoch); the real guest kcr3 does NOT depend
|
||||
* on it (armed reads the System DTB). MC_JOB_WRITE copies SRC off-loop into req.src. */
|
||||
* on it (armed reads the System DTB). MC_JOB_WRITE copies SRC off-loop into req.src plus the
|
||||
* target cr3 (0 => System DTB; resolved on the worker against a->kcr3). */
|
||||
typedef struct {
|
||||
uint32_t op; /* MC_JOB_* */
|
||||
uint32_t boot_count; /* MC_JOB_BOOTSTRAP */
|
||||
/* --- MC_JOB_WRITE --- */
|
||||
uint64_t cr3; /* target AS root; 0 => a->kcr3 (kernel AS), resolved on worker */
|
||||
uint64_t gva;
|
||||
uint32_t len;
|
||||
uint32_t corr;
|
||||
@@ -168,8 +170,10 @@ static int mc_job(void* user, const void* req, void* res) {
|
||||
if (a->stub) { rs->ok = 1; return 0; } /* stub: ack without actuation */
|
||||
#ifdef VMSIG_WITH_VMIE
|
||||
/* a->mem is NULL until a bootstrap has succeeded (or after one failed and cleared it):
|
||||
* the guard turns that into an ok=0 ACK (observable to the initiator), not a crash. */
|
||||
rs->ok = (a->mem && gva_write(a->mem, (uintptr_t)a->kcr3, (uintptr_t)rq->gva,
|
||||
* the guard turns that into an ok=0 ACK (observable to the initiator), not a crash.
|
||||
* cr3 resolve is on the worker (sole owner of a->kcr3): 0 => kernel AS (System DTB). */
|
||||
uint64_t target = rq->cr3 ? rq->cr3 : a->kcr3;
|
||||
rs->ok = (a->mem && gva_write(a->mem, (uintptr_t)target, (uintptr_t)rq->gva,
|
||||
rq->src, rq->len) == 0);
|
||||
return rs->ok ? 0 : -1;
|
||||
#else
|
||||
@@ -363,13 +367,13 @@ static int mc_submit(vmsig_adapter* a, const vmsig_event* ev) {
|
||||
return 0;
|
||||
}
|
||||
mc_req rq; memset(&rq, 0, sizeof rq);
|
||||
rq.op = MC_JOB_WRITE; rq.gva = mw->gva; rq.len = len;
|
||||
rq.op = MC_JOB_WRITE; rq.cr3 = mw->cr3; rq.gva = mw->gva; rq.len = len;
|
||||
rq.corr = ev->corr; rq.origin = ev->origin;
|
||||
|
||||
/* copy SRC into the worker req (off-loop gva_write reads from rq.src). */
|
||||
if (mw->flags & VMSIG_MW_SRC_INLINE) {
|
||||
if (len > VMSIG_MEMWRITE_INLINE) { mc_memwrite_ack(a, 0, ev->corr, ev->origin); return 0; }
|
||||
memcpy(rq.src, ev->inln + sizeof *mw, len); /* inln tail after the 16-byte header */
|
||||
memcpy(rq.src, ev->inln + sizeof *mw, len); /* inln tail after the 24-byte header */
|
||||
} else if (mw->flags & VMSIG_MW_SRC_PAYLOAD) {
|
||||
if (!ev->payload.data || ev->payload.len < len) { mc_memwrite_ack(a, 0, ev->corr, ev->origin); return 0; }
|
||||
memcpy(rq.src, ev->payload.data, len); /* in-proc borrowed payload */
|
||||
|
||||
Reference in New Issue
Block a user