mirror of
https://dev.lirent.ru/Vatrog/vm-introspection-engine.git
synced 2026-06-18 00:56:37 +03:00
Make the guest agent wait until ack; collapse the contract magics
The agent no longer self-terminates on a 120s deadline: a VMI host may attach at any time, so the beacon now polls its ack flag indefinitely and exits only once the host sets it. The fixed lifetime was an artifact, not a requirement. The contract drops from three constants to one. The companion magic is derived as the byte-reversed primary (__builtin_bswap64, folded to an immediate at -O2), giving the same 16-byte beacon signature from a single source of truth; the host acknowledges by echoing that value into the ack slot instead of carrying a separate ack constant.
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
#ifndef CONTRACT_MAGIC0
|
||||
#define CONTRACT_MAGIC0 0x3A7C1E94B2D6F058ull
|
||||
#ifndef CONTRACT_MAGIC
|
||||
#define CONTRACT_MAGIC 0x3A7C1E94B2D6F058ull
|
||||
#endif
|
||||
|
||||
#ifndef CONTRACT_MAGIC1
|
||||
#define CONTRACT_MAGIC1 0x9F41D80E6BC57A23ull
|
||||
#endif
|
||||
|
||||
#ifndef CONTRACT_ACK
|
||||
#define CONTRACT_ACK 0xACED5EEDACED5EEDull
|
||||
/* Companion magic = byte-reversed primary, folded to an immediate at -O2 (no
|
||||
* runtime bswap). One source of truth; in memory magic0 ++ magic1 forms a
|
||||
* 16-byte palindrome. The host echoes this value into `ack` to acknowledge, so
|
||||
* there is no separate ack constant. (CONTRACT_MAGIC must not be a byte
|
||||
* palindrome, or magic1 would equal magic0.) */
|
||||
#ifndef CONTRACT_MAGIC_R
|
||||
#define CONTRACT_MAGIC_R (__builtin_bswap64(CONTRACT_MAGIC))
|
||||
#endif
|
||||
|
||||
#ifndef VMIE_CONTRACT_H
|
||||
|
||||
+13
-19
@@ -5,13 +5,8 @@
|
||||
#define ACK_POLL_MS 5u
|
||||
#endif
|
||||
|
||||
#ifndef ACK_TIMEOUT_MS
|
||||
#define ACK_TIMEOUT_MS (120*1000u)
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
contract* c = VirtualAlloc(NULL, sizeof *c, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
uint32_t timeout = ACK_TIMEOUT_MS;
|
||||
if (c == NULL) {
|
||||
return 1;
|
||||
}
|
||||
@@ -20,22 +15,21 @@ int main(void) {
|
||||
|
||||
c->va_self = (uint64_t)(uintptr_t)c;
|
||||
c->ack = 0;
|
||||
c->magic1 = CONTRACT_MAGIC1;
|
||||
c->magic1 = CONTRACT_MAGIC_R;
|
||||
|
||||
MemoryBarrier();
|
||||
c->magic0 = CONTRACT_MAGIC0;
|
||||
c->magic0 = CONTRACT_MAGIC;
|
||||
|
||||
do {
|
||||
if (*(volatile uint64_t*)&c->ack == CONTRACT_ACK) {
|
||||
c->magic0 = 0;
|
||||
c->magic1 = 0;
|
||||
VirtualUnlock(c, sizeof *c);
|
||||
VirtualFree(c, 0, MEM_RELEASE);
|
||||
break;
|
||||
}
|
||||
/* Live until acknowledged. A VMI host may attach at any moment - or only
|
||||
* after the guest has idled for a long time - so there is no justified
|
||||
* deadline: poll the ack flag forever, exit only once the host sets it. */
|
||||
while (*(volatile uint64_t*)&c->ack != CONTRACT_MAGIC_R) {
|
||||
Sleep(ACK_POLL_MS);
|
||||
}
|
||||
|
||||
Sleep(ACK_POLL_MS);
|
||||
} while (timeout -= ACK_POLL_MS);
|
||||
|
||||
return timeout > 0 ? 0 : 255;
|
||||
c->magic0 = 0;
|
||||
c->magic1 = 0;
|
||||
VirtualUnlock(c, sizeof *c);
|
||||
VirtualFree(c, 0, MEM_RELEASE);
|
||||
return 0;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ static int beacon_find(vmie_mem* m, uint64_t* pa, uint64_t* va) {
|
||||
|
||||
do {
|
||||
const contract* c = (void*)ptr;
|
||||
if (c->magic0 == CONTRACT_MAGIC0 && c->magic1 == CONTRACT_MAGIC1) {
|
||||
if (c->magic0 == CONTRACT_MAGIC && c->magic1 == CONTRACT_MAGIC_R) {
|
||||
*pa = offset_gpa(m, ptr - m->pa);
|
||||
*va = c->va_self;
|
||||
return 0;
|
||||
@@ -204,7 +204,7 @@ static uint32_t ko_export_rva(vmie_mem* m, uintptr_t cr3, uint64_t kbase, const
|
||||
}
|
||||
|
||||
static void beacon_ack(vmie_mem* m, uint64_t anchor_pa) {
|
||||
uint64_t ack = CONTRACT_ACK;
|
||||
uint64_t ack = CONTRACT_MAGIC_R;
|
||||
gpa_write(m, anchor_pa + offsetof(contract, ack), &ack, 8);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user