⬢ DragonFlyBSD Kernel Audit
DF-3902 / sio_ioctl_test.c
← back to finding ↓ download raw
/*
 * sio.c pass-2 live ioctl-glue verification (guest console is sio0).
 * Exercises: control-device (ttyid/ttyld) TIOCGETA/TIOCSETA/TIOCGWINSZ,
 * termios lock-merge on the live console, TIOCMGET, TIOCTIMESTAMP zero-init.
 * Read-mostly; restores any state it changes.
 */
#include <sys/ioctl.h>
#include <termios.h>
#include <sys/time.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

static void dump_speed(const char *tag, struct termios *t) {
    printf("%s: ispeed=%u ospeed=%u cflag=0x%x\n",
           tag, (unsigned)t->c_ispeed, (unsigned)t->c_ospeed,
           (unsigned)t->c_cflag);
}

int main(int argc, char **argv) {
    struct termios t, t0;
    struct timeval tv;
    int fd, m, rc;

    /* 1. TIOCTIMESTAMP / TIOCDCDTIMESTAMP on the console: must be
     * all-zero on first use (attach-time bzero) — no stale kernel data. */
    fd = open("/dev/ttyd0", O_RDONLY | O_NONBLOCK);
    if (fd < 0) { printf("FAIL open ttyd0: %s\n", strerror(errno)); return 1; }
    memset(&tv, 0xAA, sizeof(tv));
    rc = ioctl(fd, TIOCTIMESTAMP, &tv);
    printf("TIOCTIMESTAMP rc=%d sec=%lld usec=%ld (expect 0/0 or runtime vals, not 0xAA garbage)\n",
           rc, (long long)tv.tv_sec, tv.tv_usec);
    memset(&tv, 0xAA, sizeof(tv));
    rc = ioctl(fd, TIOCDCDTIMESTAMP, &tv);
    printf("TIOCDCDTIMESTAMP rc=%d sec=%lld usec=%ld\n",
           rc, (long long)tv.tv_sec, tv.tv_usec);

    /* 2. TIOCMGET: commctl DMGET */
    rc = ioctl(fd, TIOCMGET, &m);
    printf("TIOCMGET rc=%d bits=0x%x (LE|DTR|RTS expected)\n", rc, m);

    /* 3. lock-merge on the console: lt_in.c_ispeed locked at boot,
     * so a TIOCSETA speed change must NOT take effect. */
    rc = ioctl(fd, TIOCGETA, &t0);
    dump_speed("ttyd0 TIOCGETA before", &t0);
    t = t0;
    t.c_ispeed = t.c_ospeed = 57600;
    rc = ioctl(fd, TIOCSETA, &t);
    printf("TIOCSETA(57600) rc=%d\n", rc);
    rc = ioctl(fd, TIOCGETA, &t);
    dump_speed("ttyd0 TIOCGETA after (speed must be unchanged: lock holds)", &t);
    if (t.c_ispeed == 57600)
        printf("WARNING: speed lock did NOT hold\n");
    else
        printf("OK: console speed lock enforced by sio.c merge (2077-2099)\n");
    close(fd);

    /* 4. control device ttyid0: TIOCGETA/TIOCSETA + TIOCGWINSZ */
    fd = open("/dev/ttyid0", O_RDONLY);
    if (fd < 0) { printf("FAIL open ttyid0: %s\n", strerror(errno)); return 1; }
    rc = ioctl(fd, TIOCGETA, &t0);
    dump_speed("ttyid0 TIOCGETA (it_in)", &t0);
    memset(&tv, 0xAA, sizeof(tv));
    { struct winsize wz; memset(&wz, 0xAA, sizeof(wz));
      rc = ioctl(fd, TIOCGWINSZ, &wz);
      printf("ttyid0 TIOCGWINSZ rc=%d row=%d col=%d (expect zeros)\n",
             rc, wz.ws_row, wz.ws_col); }
    t = t0;
    t.c_ispeed = t.c_ospeed = 57600;
    rc = ioctl(fd, TIOCSETA, &t);
    printf("ttyid0 TIOCSETA rc=%d (root: expect 0; unpriv: expect EPERM)\n", rc);
    ioctl(fd, TIOCGETA, &t);
    dump_speed("ttyid0 after SETA", &t);
    /* restore */
    rc = ioctl(fd, TIOCSETA, &t0);
    printf("ttyid0 restore rc=%d\n", rc);
    close(fd);

    /* 5. TIOCMSDTRWAIT: priv-gated; round-trip as root */
    fd = open("/dev/ttyd0", O_RDONLY | O_NONBLOCK);
    { int dw = 0, dw2 = 300; /* centiseconds */
      rc = ioctl(fd, TIOCMGDTRWAIT, &dw);
      printf("TIOCMGDTRWAIT rc=%d dtr_wait=%d cs\n", rc, dw);
      rc = ioctl(fd, TIOCMSDTRWAIT, &dw2);
      printf("TIOCMSDTRWAIT(300) rc=%d\n", rc);
      rc = ioctl(fd, TIOCMGDTRWAIT, &dw);
      printf("  readback=%d\n", dw);
      rc = ioctl(fd, TIOCMSDTRWAIT, &dw); /* restore */ }
    close(fd);
    printf("DONE\n");
    return 0;
}