⬢ DragonFlyBSD Kernel Audit
DF-3008 / df3008.c
← back to finding ↓ download raw
/* DF-3008 - kern.devname race vs clone churn.
 * thread A: open /dev/ptmx, stat slave, publish rdev, close both (churn)
 * thread B: sysctl kern.devname on latest published rdev, record results
 * report: any returned name that is not "pts/N", plus tally
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>

static volatile dev_t cur = 0;
static volatile int stop = 0;
static long ok=0, enoent=0, other=0, queries=0;
static char weird[1024]; static int weird_n=0;

static void *churn(void *a)
{

    struct stat st;
    while (!stop) {
        int m = open("/dev/ptmx", O_RDWR);
        if (m < 0) { usleep(1000); continue; }
        if (fstat(m, &st) == 0) cur = st.st_rdev;   /* cloned master cdev */
        close(m);
    }
    return NULL;
}
static void *query(void *a)
{
    char out[256]; size_t len; dev_t d;
    while (!stop) {
        d = cur;
        if (d == 0) continue;
        len = sizeof(out);
        memset(out,0,sizeof out);
        if (sysctlbyname("kern.devname", out, &len, &d, sizeof(d)) == 0) {
            int n, good=0;
            if (len>0 && out[len-1]=='\0') len--;
            if (sscanf(out, "pts/%d", &n)==1) good=1;
            if (good) ok++;
            else { other++;
                   if (weird_n < 20) weird_n += snprintf(weird+weird_n, sizeof(weird)-weird_n, "[%s]", out); }
        } else {
            if (errno==ENOENT) enoent++;
            else other++;
        }
        queries++;
    }
    return NULL;
}
int main(void)
{
    pthread_t a,b;
    pthread_create(&a,NULL,churn,NULL);
    pthread_create(&b,NULL,query,NULL);
    sleep(20); stop=1;
    pthread_join(a,NULL); pthread_join(b,NULL);
    printf("queries=%ld ok_pts=%ld enoent=%ld other=%ld weird=%s\n",
           queries, ok, enoent, other, weird_n?weird:"-");
    return 0;
}