DF-2548 / fix.diff
diff --git a/sys/kern/tty.c b/sys/kern/tty.c --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -2911,6 +2911,43 @@ t = *tp; if (t.t_dev) t.t_dev = (cdev_t)(uintptr_t)devid_from_dev(t.t_dev); + /* + * Zero every kernel-pointer-bearing field before copyout so we + * do not leak kernel .text/.rodata/.heap addresses (KASLR + * defeat + heap layout) to unprivileged readers of kern.ttys. + * Only t_dev is rewritten (to a small devid) above; every other + * pointer field is nulled here. Mirrors the sanitized-export + * pattern used by kinfo_file in kern_descrip.c. + * + * Fields cleared (see sys/sys/tty.h): + * - t_token : lwkt_token { t_ref, t_desc } + * - t_rawq/t_canq/t_outq .c_data : clist data buffers + * - t_pgrp/t_session/t_sigio : heap object pointers + * - t_rkq/t_wkq : kqinfo { ki_note (klist ptr) } + * - t_oproc/t_stop/t_param/t_unhold : driver .text fn ptrs + * - t_sc/t_slsc : driver softc / line-disc softc + * - t_list : TAILQ_ENTRY linkage { tqe_next, tqe_prev } + * The remaining exported fields (termios, winsize, watermarks, + * state/flags, column, etc.) are pure scalars and are what + * pstat(8) actually consumes. + */ + bzero(&t.t_token, sizeof(t.t_token)); + t.t_rawq.c_data = NULL; + t.t_canq.c_data = NULL; + t.t_outq.c_data = NULL; + t.t_pgrp = NULL; + t.t_session = NULL; + t.t_sigio = NULL; + bzero(&t.t_rkq, sizeof(t.t_rkq)); + bzero(&t.t_wkq, sizeof(t.t_wkq)); + t.t_oproc = NULL; + t.t_stop = NULL; + t.t_param = NULL; + t.t_unhold = NULL; + t.t_sc = NULL; + t.t_slsc = NULL; + t.t_list.tqe_next = NULL; + t.t_list.tqe_prev = NULL; error = SYSCTL_OUT(req, (caddr_t)&t, sizeof(t)); if (error) break; |