DragonFlyBSD Kernel Audit
DF-2937 / sched_probe.c
← back to finding ↓ download raw
/*
 * DF-2937 probe: map the unpriv attack surface of sys/kern/kern_p1003_1b.c
 * and demonstrate that ksched_setscheduler() returns success (0) for
 * invalid policies (POSIX requires EINVAL), while rejecting out-of-range
 * priorities only for SCHED_RR/FIFO.
 *
 * Build: cc -o sched_probe sched_probe.c
 * Run:   ./sched_probe          (as invoking user)
 */
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sched.h>
#include <time.h>

static void r(const char *what, int rc)
{
	if (rc == -1)
		printf("%-46s rc=-1 errno=%d (%s)\n", what, errno, strerror(errno));
	else
		printf("%-46s rc=%d errno=0\n", what, rc);
}

int main(void)
{
	struct sched_param sp;
	struct timespec ts;
	pid_t me = getpid();

	printf("uid=%d euid=%d pid=%d  "
	       "SCHED_OTHER=%d SCHED_FIFO=%d SCHED_RR=%d\n",
	       getuid(), geteuid(), me, SCHED_OTHER, SCHED_FIFO, SCHED_RR);

	memset(&sp, 0, sizeof(sp));
	sp.sched_priority = 0;

	/* ---- self (pid 0 and own pid) ---- */
	r("sched_setparam(0, {0})", sched_setparam(0, &sp));
	errno = 0; r("sched_getparam(0, &sp)", sched_getparam(0, &sp));
	errno = 0; r("sched_getscheduler(0)", sched_getscheduler(0));
	errno = 0; r("sched_setscheduler(0, SCHED_RR, {0})",
		     sched_setscheduler(0, SCHED_RR, &sp));
	errno = 0; r("sched_rr_get_interval(0, &ts)",
		     sched_rr_get_interval(0, &ts));
	errno = 0; r("sched_setparam(self, {0})", sched_setparam(me, &sp));
	errno = 0; r("sched_getscheduler(self)", sched_getscheduler(me));

	/* ---- other proc (pid 1 = root proc) ---- */
	errno = 0; r("sched_getscheduler(1)", sched_getscheduler(1));
	errno = 0; r("sched_getparam(1, &sp)", sched_getparam(1, &sp));

	/* ---- nonexistent / negative pids ---- */
	errno = 0; r("sched_getscheduler(999999)", sched_getscheduler(999999));
	errno = 0; r("sched_getscheduler(-1)", sched_getscheduler(-1));
	errno = 0; r("sched_setparam(-1, {0})", sched_setparam(-1, &sp));
	errno = 0; r("sched_getscheduler(-99999999)", sched_getscheduler(-99999999));

	/* ---- policy-free ops ---- */
	errno = 0; r("sched_yield()", sched_yield());
	errno = 0; r("sched_get_priority_max(SCHED_FIFO)",
		     sched_get_priority_max(SCHED_FIFO));
	errno = 0; r("sched_get_priority_min(SCHED_FIFO)",
		     sched_get_priority_min(SCHED_FIFO));
	errno = 0; r("sched_get_priority_max(SCHED_OTHER)",
		     sched_get_priority_max(SCHED_OTHER));
	errno = 0; r("sched_get_priority_max(4711)",
		     sched_get_priority_max(4711));

	/* ---- invalid policies: POSIX requires EINVAL ---- */
	sp.sched_priority = 0;
	errno = 0; r("sched_setscheduler(0, 0 /*Linux SCHED_OTHER*/, {0})",
		     sched_setscheduler(0, 0, &sp));
	errno = 0; r("sched_setscheduler(0, 4711, {0})",
		     sched_setscheduler(0, 4711, &sp));
	errno = 0; r("sched_setscheduler(0, -1, {0})",
		     sched_setscheduler(0, -1, &sp));
	errno = 0; r("sched_setscheduler(0, INT_MAX, {0})",
		     sched_setscheduler(0, 2147483647, &sp));

	return 0;
}