summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2003-03-28 02:50:10 +0000
committeriedowse <iedowse@FreeBSD.org>2003-03-28 02:50:10 +0000
commitb399d5ecbd4716ab7d85123d538e0eac2cfecdec (patch)
tree30c3acce3e8fb42b966dd12505c6284f5d7c6b04 /sys/kern
parent41a48ccd9eddb0fca56b439efaa5db84a4dcfb37 (diff)
downloadFreeBSD-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.c28
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]);
OpenPOWER on IntegriCloud