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:
parent
c591e5ebee
commit
6205bf3107
@ -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]);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user