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
This commit is contained in:
Ian Dowse 2003-03-28 02:50:10 +00:00
parent c591e5ebee
commit 6205bf3107
2 changed files with 25 additions and 4 deletions

View File

@ -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]);

View File

@ -44,6 +44,7 @@ struct msgbuf {
int msg_bufx; /* write pointer */
int msg_bufr; /* read pointer */
char *msg_ptr; /* pointer to buffer */
u_int msg_cksum; /* checksum of contents */
};
#ifdef _KERNEL