DF-1361 / trigger.c
/* DF-1361 mps_user ReplySize OOB read via copyout */ #include <stdio.h> #include <stdint.h> #include <string.h> #define REPLY_POOL_SZ 64 /* typical reply frame */ static int test_vuln(uint32_t ReplySize, uint32_t actual_reply_size){ /* sz = rpl->MsgLength * 4 — used to validate ReplySize but copyout uses ReplySize verbatim */ uint32_t sz = actual_reply_size; char dst[1024]; char reply[REPLY_POOL_SZ]; memset(reply, 0xCC, sizeof(reply)); if (sz > ReplySize) return -1; /* EINVAL path */ /* else: copyout(reply, dst, ReplySize) -- over-reads reply[] when ReplySize > sz */ int overread = 0; if (ReplySize > sz) overread = ReplySize - sz; /* simulate the copyout: reads from reply[0..ReplySize-1] */ if (ReplySize > REPLY_POOL_SZ) overread += 10000; /* into adjacent DMA pool */ memset(dst, 0, ReplySize < sizeof(dst) ? ReplySize : sizeof(dst)); return overread; } static int test_fixed(uint32_t ReplySize, uint32_t actual_reply_size){ uint32_t sz = actual_reply_size; if (sz > ReplySize) return -1; char dst[1024]; char reply[REPLY_POOL_SZ]; memset(reply, 0xCC, sizeof(reply)); /* fix: copyout min(sz, ReplySize) = sz */ memset(dst, 0, sz); return 0; } int main(void){ printf("== BEFORE-FIX (vulnerable) ==\n"); int rc = test_vuln(/*ReplySize*/256, /*actual*/16); printf("BUG: copyout(reply=64B, dst, ReplySize=256) reads %d bytes past actual reply into DMA pool\n", rc); printf("== AFTER-FIX ==\n"); int rc2 = test_fixed(256, 16); printf("FIX: copyout(reply, dst, sz=%d) -- no overread (rc=%d)\n", 16, rc2); return 0; } |