DF-2951 / stress_ucred_race.c
/* DF-2951 stress: race sysctl_hostname's unlocked p->p_ucred loads * (kern_mib.c:221-229) against ucred replacement via setgroups churn * (cratom_proc, kern_prot.c:1166-1188). Readers hammer kern.hostname; * churners replace p_ucred as fast as possible. Run as jailed uid-0 * (setgroups is allowed in jails; hostname read is ungated). */ #include <sys/sysctl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> static volatile int stop_flag; static unsigned long total_rd, total_sg; static pthread_mutex_t cnt_mx = PTHREAD_MUTEX_INITIALIZER; static void * reader(void *arg) { char buf[300]; size_t l; unsigned long n = 0, errs = 0; while (!stop_flag) { l = sizeof(buf); if (sysctlbyname("kern.hostname", buf, &l, 0, 0) < 0) errs++; n++; } pthread_mutex_lock(&cnt_mx); total_rd += n + (errs << 40); pthread_mutex_unlock(&cnt_mx); return (NULL); } static void * churner(void *arg) { gid_t ga[2] = {0, 1001}; gid_t gb[1] = {0}; unsigned long n = 0, errs = 0; int i = 0; while (!stop_flag) { if (setgroups((i & 1) ? 1 : 2, (i & 1) ? gb : ga) < 0) errs++; n++; i++; } pthread_mutex_lock(&cnt_mx); total_sg += n + (errs << 40); pthread_mutex_unlock(&cnt_mx); return (NULL); } int main(int argc, char **argv) { pthread_t th[8]; int secs = (argc > 1) ? atoi(argv[1]) : 120; int i; for (i = 0; i < 4; i++) pthread_create(&th[i], NULL, reader, NULL); for (i = 4; i < 8; i++) pthread_create(&th[i], NULL, churner, NULL); sleep(secs); stop_flag = 1; for (i = 0; i < 8; i++) pthread_join(th[i], NULL); printf("reads: %lu (errs hi-40: %lu) setgroups: %lu (errs hi-40: %lu)\n", total_rd & 0xffffffffffUL, total_rd >> 40, total_sg & 0xffffffffffUL, total_sg >> 40); return (0); } |