DF-5676 / df5676_guard.c
/* * DF-5676 — MATCH() preamble memcmp reads past the NUL sentinel. * * _prop_object_internalize_context_alloc() (prop_object.c:739-746) does * * #define MATCH(str) (memcmp(&xml[1], str, sizeof(str) - 1) == 0) * ... * if (MATCH("?xml ") || MATCH("!DOCTYPE plist")) { * * after only proving *xml == '<' and *xml != NUL (prop_object.c:736). * If the '<' is the last byte before the NUL sentinel, &xml[1] IS the * sentinel and the memcmp is permitted (and, with block/vectorized memcmp, * expected) to read up to 15 bytes past the end of the buffer. The parser * never establishes that xml[1..15] exist. * * This harness places the input so the NUL sentinel is the LAST byte of a * page followed by a PROT_NONE guard page and calls prop_array_internalize * (public API of the same-source rig). A byte-at-a-time memcmp stops at * the sentinel (first mismatch) and nothing happens; a block memcmp * (glibc/DF-libc SSE, or gcc-widened constant compares) faults. * * probe1 " <" : xml[1] is the sentinel; MATCH("?xml ") mismatches * on the FIRST byte (byte-wise: 1 byte read, safe; * widened load: guard page) * probe2 " <?xml" : xml[1..5] all match "?xml", sentinel at xml[6] * (byte-wise reads exactly TO the sentinel; widened * loads go past it) * probe3 " <!DOCTYPE": matches the first 9 bytes of "!DOCTYPE plist" * before the sentinel */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> #include <unistd.h> #include <libprop/proplib.h> static void probe(const char *bytes, size_t n, const char *label) { size_t pgsize = (size_t)sysconf(_SC_PAGESIZE); char *page; char *xml; page = mmap(NULL, pgsize * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (page == MAP_FAILED) { perror("mmap"); exit(1); } if (mprotect(page + pgsize, pgsize, PROT_NONE) != 0) { perror("mprotect"); exit(1); } /* input at the very end of the first page; NUL sentinel = last byte */ xml = page + pgsize - (n + 1); memcpy(xml, bytes, n); xml[n] = '\0'; printf("DF5676 probe %-9s (%zu bytes + NUL as last byte of page): " "prop_array_internalize...\n", label, n); fflush(stdout); (void)prop_array_internalize(xml); /* parser runs MATCH() first */ printf("DF5676 probe %-9s: returned, NO fault " "(memcmp stopped at sentinel / byte-wise inlined)\n", label); fflush(stdout); munmap(page, pgsize * 2); } int main(void) { probe(" <", 2, "sentinel"); probe(" <?xml", 6, "prefix5"); probe(" <!DOCTYPE", 10, "prefix9"); printf("no fault observed\n"); return (0); } |