diff options
author | iedowse <iedowse@FreeBSD.org> | 2003-03-28 02:50:10 +0000 |
---|---|---|
committer | iedowse <iedowse@FreeBSD.org> | 2003-03-28 02:50:10 +0000 |
commit | b399d5ecbd4716ab7d85123d538e0eac2cfecdec (patch) | |
tree | 30c3acce3e8fb42b966dd12505c6284f5d7c6b04 /sys/kern | |
parent | 41a48ccd9eddb0fca56b439efaa5db84a4dcfb37 (diff) | |
download | FreeBSD-src-b399d5ecbd4716ab7d85123d538e0eac2cfecdec.zip FreeBSD-src-b399d5ecbd4716ab7d85123d538e0eac2cfecdec.tar.gz |
Add a checksum to the kernel message buffer, and update it every
time a character is written. Use this at boot time to reject the
existing buffer contents if they are corrupt. This fixes a problem
seen on some hardware (especially laptops) where the message buffer
gets partially corrupted during a short power cycle or reset, but
the msgbuf structure is left intact so it gets reused, resulting
in random junk and control characters appearing in dmesg and
/var/log/messages.
PR: kern/28497
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/subr_prf.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/sys/kern/subr_prf.c b/sys/kern/subr_prf.c index 99b37f8..3efb7c2 100644 --- a/sys/kern/subr_prf.c +++ b/sys/kern/subr_prf.c @@ -92,6 +92,7 @@ struct tty *constty; /* pointer to console "window" tty */ static void (*v_putc)(int) = cnputc; /* routine to putc on virtual console */ static void msglogchar(int c, int pri); static void msgaddchar(int c, void *dummy); +static u_int msgbufcksum(char *cp, size_t size, u_int cksum); static void putchar(int ch, void *arg); static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len); static void snprintf_func(int ch, void *arg); @@ -818,6 +819,7 @@ msgaddchar(int c, void *dummy) if (!msgbufmapped) return; mbp = msgbufp; + mbp->msg_cksum += (u_char)c - (u_char)mbp->msg_ptr[mbp->msg_bufx]; mbp->msg_ptr[mbp->msg_bufx++] = c; if (mbp->msg_bufx >= mbp->msg_size) mbp->msg_bufx = 0; @@ -852,11 +854,12 @@ msgbufinit(void *ptr, int size) msgbufp = (struct msgbuf *) (cp + size); if (msgbufp->msg_magic != MSG_MAGIC || msgbufp->msg_size != size || msgbufp->msg_bufx >= size || msgbufp->msg_bufx < 0 || - msgbufp->msg_bufr >= size || msgbufp->msg_bufr < 0) { + msgbufp->msg_bufr >= size || msgbufp->msg_bufr < 0 || + msgbufcksum(cp, size, msgbufp->msg_cksum) != msgbufp->msg_cksum) { bzero(cp, size); bzero(msgbufp, sizeof(*msgbufp)); msgbufp->msg_magic = MSG_MAGIC; - msgbufp->msg_size = (char *)msgbufp - cp; + msgbufp->msg_size = size; } msgbufp->msg_ptr = cp; if (msgbufmapped && oldp != msgbufp) @@ -865,6 +868,22 @@ msgbufinit(void *ptr, int size) oldp = msgbufp; } +static u_int +msgbufcksum(char *cp, size_t size, u_int cksum) +{ + u_int sum; + int i; + + sum = 0; + for (i = 0; i < size; i++) + sum += (u_char)cp[i]; + if (sum != cksum) + printf("msgbuf cksum mismatch (read %x, calc %x)\n", cksum, + sum); + + return (sum); +} + SYSCTL_DECL(_security_bsd); static int unprivileged_read_msgbuf = 1; @@ -913,6 +932,7 @@ sysctl_kern_msgbuf_clear(SYSCTL_HANDLER_ARGS) /* Clear the buffer and reset write pointer */ bzero(msgbufp->msg_ptr, msgbufp->msg_size); msgbufp->msg_bufr = msgbufp->msg_bufx = 0; + msgbufp->msg_cksum = 0; msgbuf_clear = 0; } return (error); @@ -933,9 +953,9 @@ DB_SHOW_COMMAND(msgbuf, db_show_msgbuf) return; } db_printf("msgbufp = %p\n", msgbufp); - db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p\n", + db_printf("magic = %x, size = %d, r= %d, w = %d, ptr = %p, cksum= %d\n", msgbufp->msg_magic, msgbufp->msg_size, msgbufp->msg_bufr, - msgbufp->msg_bufx, msgbufp->msg_ptr); + msgbufp->msg_bufx, msgbufp->msg_ptr, msgbufp->msg_cksum); for (i = 0; i < msgbufp->msg_size; i++) { j = (i + msgbufp->msg_bufr) % msgbufp->msg_size; db_printf("%c", msgbufp->msg_ptr[j]); |