DF-5498 / c5498_user.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | /* * DF-5498 userspace model: production ROM *builder* off-by-one. * * crom_add_simple_text() computes the text-leaf length including the * 12-byte struct csrtext header: * * sys/bus/firewire/fwcrom.c:459 * tl->crc_len = howmany(sizeof(struct csrtext) + len, 4); * * But crc_len counts the quadlets FOLLOWING the crc quadlet (compare the * directory builder: crom_add_quad() counts entries only), and * crom_load() adds the crc quadlet back: * * sys/bus/firewire/fwcrom.c:520-522 * len = 1 + chunk->data.crc_len; * crom_copy(..., len, ...) -> bcopy of len*4 bytes * sys/bus/firewire/fwcrom.c:517-518 * chunk->data.crc = crom_crc(&chunk->data.buf[0], * chunk->data.crc_len); * * => the copy/CRC always consume ONE quadlet past the text; for text * length 69..72 (MAX_TEXT == 72, fwcrom.c:442) that quadlet lies past * chunk->data[] (84 bytes = 21 quadlets): a sub-object OOB read whose * bytes are published verbatim in the host's Config ROM. * * Model: struct crom_chunk-sized buffer; bytes [0..116) (the struct up * to the end of data[]) are zeroed, the 4 tail bytes past data[] * (offset 116..120, in-kernel: zeroed tail padding of the kmalloc'd * object / adjacent memory) are pre-filled with 0xCAFEBABE. Run the * PRODUCTION crom_add_simple_text()/crom_load() and scan the generated * ROM: 0xCAFEBABE present == the quadlet past data[] was read and * broadcast. 68-char control: exact fit, no pattern. */ #include <sys/types.h> #include <sys/queue.h> /* STAILQ_*: needed before iec13213.h's -DTEST structs */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stddef.h> #include <bus/firewire/firewire.h> #include <bus/firewire/iec13213.h> #define PATTERN 0xCAFEBABEu static int run_case(int tlen, const char *label) { struct crom_src src; struct crom_chunk root; char raw[sizeof(struct crom_chunk) + 16]; struct crom_chunk *chunk = (struct crom_chunk *)(void *)raw; char text[80]; u_int32_t out[256]; size_t used = offsetof(struct crom_chunk, data) + sizeof(chunk->data); /* == 116 */ int i, n, found = -1, leafhdr = -1; /* pattern everywhere, then zero the meaningful prefix so ONLY the * bytes past data[] keep the pattern */ memset(raw, 0xBB, sizeof(raw)); memset(raw, 0, used); *(u_int32_t *)(raw + used) = PATTERN; memset(&src, 0, sizeof(src)); memset(&root, 0, sizeof(root)); src.hdr.info_len = 4; STAILQ_INIT(&src.chunk_list); crom_add_chunk(&src, NULL, &root, 0); memset(text, 'A', sizeof(text)); text[tlen] = '\0'; crom_add_simple_text(&src, &root, chunk, text); printf("%s: strlen=%d builder crc_len=%d (data holds 21 quads; " "1+crc_len=%d quads will be copied/CRC'd)\n", label, tlen, chunk->data.crc_len, 1 + chunk->data.crc_len); memset(out, 0, sizeof(out)); n = crom_load(&src, out, 256); if (n < 0) { printf("%s: crom_load failed\n", label); return (1); } /* text chunk starts after 5 bus quads + 1+root quads (root has 1 * entry): out[7] is the leaf header. */ leafhdr = out[7]; for (i = 0; i < n; i++) if (out[i] == PATTERN) found = i; printf("%s: ROM quadlets=%d, published leaf header=0x%08x " "(crc_len field=%d, IEEE-1212-correct=%d), PATTERN %s\n", label, n, leafhdr, (leafhdr >> 16) & 0xffff, 2 + (tlen + 3) / 4, found >= 0 ? "FOUND in generated ROM (OOB quadlet published)" : "absent"); return (found >= 0); } int main(void) { int r1, r2; puts("DF-5498 userspace model: production fwcrom.c builder"); r1 = run_case(72, "case1 len=72 (max)"); r2 = run_case(68, "case2 len=68 (control, exact fit)"); printf("RESULT: %s\n", (r1 && !r2) ? "REPRODUCED: the quadlet past chunk->data[] was read by " "crom_load/crom_crc and published in the Config ROM" : "not reproduced"); return (r1 && !r2) ? 42 : 1; } |