DF-5015 / probe.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 114 115 116 | /* * probe.c -- DF-5015 verification: read syscons history state via /dev/kmem. * (root-only evidence tool; the bug itself is triggered by unpriv ioctls) * * usage: probe state print vtb size/buffer/tail of console scp * probe cellsum count Z-cells (0x075a) in [buf-4096, buf) * and in the buffer itself * probe snap <file> hexdump [buf-4096, buf+4096) to file */ #include <fcntl.h> #include <kvm.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define MAIN_SOFTC 0xffffffff81b25700ULL #define OFF_CONSOLE_SCP 112 #define OFF_HISTORY 400 #define OFF_VTB_SIZE 16 #define OFF_VTB_BUFFER 24 #define OFF_VTB_TAIL 32 static kvm_t *kd; static int kread(uint64_t kva, void *buf, size_t len) { return kvm_read(kd, (unsigned long)kva, buf, len) == (ssize_t)len ? 0 : -1; } static uint64_t kread64(uint64_t kva) { uint64_t v = 0; if (kread(kva, &v, sizeof(v))) return 0; return v; } int main(int argc, char **argv) { uint64_t scp, vtb, buf; int size, tail; if (argc < 2) return 64; kd = kvm_open(NULL, "/dev/kmem", NULL, O_RDONLY, "probe"); if (kd == NULL) { fprintf(stderr, "kvm_open failed\n"); return 1; } scp = kread64(MAIN_SOFTC + OFF_CONSOLE_SCP); vtb = kread64(scp + OFF_HISTORY); if (kread(vtb + OFF_VTB_SIZE, &size, 4)) return 2; buf = kread64(vtb + OFF_VTB_BUFFER); if (kread(vtb + OFF_VTB_TAIL, &tail, 4)) return 2; if (!strcmp(argv[1], "state")) { printf("scp=%#llx vtb=%#llx size=%d buf=%#llx tail=%d\n", (unsigned long long)scp, (unsigned long long)vtb, size, (unsigned long long)buf, tail); return 0; } if (!strcmp(argv[1], "cellsum")) { uint16_t cells[2048]; int i, before = 0, inbuf = 0; memset(cells, 0, sizeof(cells)); if (kread(buf - 4096, cells, 4096) == 0) { for (i = 0; i < 2048; i++) if (cells[i] == 0x075a) before++; } else { printf("note: page before buf unreadable\n"); } memset(cells, 0, sizeof(cells)); if (kread(buf, cells, size * 2) == 0) { for (i = 0; i < size && i < 2048; i++) if (cells[i] == 0x075a) inbuf++; } printf("zcells_before=%d zcells_inbuf=%d\n", before, inbuf); return 0; } if (!strcmp(argv[1], "snap") && argc == 3) { FILE *f = fopen(argv[2], "w"); unsigned char raw[8192]; int i; if (f == NULL) return 2; memset(raw, 0, sizeof(raw)); if (kread(buf - 4096, raw, 8192) != 0) fprintf(f, "# partial read\n"); for (i = 0; i < 8192; i += 16) { fprintf(f, "%+#10llx %04x %04x %04x %04x %04x %04x " "%04x %04x\n", (unsigned long long)(buf - 4096 + i), *(uint16_t *)(raw + i), *(uint16_t *)(raw + i + 2), *(uint16_t *)(raw + i + 4), *(uint16_t *)(raw + i + 6), *(uint16_t *)(raw + i + 8), *(uint16_t *)(raw + i + 10), *(uint16_t *)(raw + i + 12), *(uint16_t *)(raw + i + 14)); } fclose(f); printf("snap written (buf=%#llx)\n", (unsigned long long)buf); return 0; } return 64; } |