/proc/tty/driver/serial kernel oops and other problems -- FIX

BJerrick@easystreet.com
Sun, 24 Oct 1999 09:54:36 -0700


I had been having problems related to accessing /proc/tty/driver/serial,
since roughly 2.3.5 . These are (were; a fix is included here):

1. Consistent "Bad address" errno's reported by simple utilities such as
'cat /proc/tty/driver/serial'.
2. Occasional garbage characters (lots) after the last line report (in
my case, the usual 0-3).
3. Kernel oops from the call sequence rs_read_proc()/line_info()/serial_in()
in drivers/char/serial.c .
4. Severe system hanging -- no response to anything except the reset
button (and, I suppose, the power switch).

#3 and #4 happened only under duress: only with SMP config'd (on a dual PII)
and running a homebrew X-based performance gauge that displays serial r/w
rates, reading the proc file twice a second. #1 and #2 could be seen using
'cat' (I suggest using 'cat -v'). For me, #2 disappeared if the output
was piped into something else (!), e.g., 'cat /proc/tty/driver/serial | cat'.

Inspection showed some very dubious code in drivers/char/serial.c (and you've
probably already guessed that auto variables (stack data) was involved).
serial_in() was dereferencing some un-initalized elements of its info pointer
arg.

A fix is below; the comments in it tell more of the story. The idea was
to set things up better for serial_in(), based on what it needs and what
autoconfig() does. It's not all needed (as noted), but I opted for
"completeness", just for easy comparison against autoconfig().

If anyone's interested in the pathology, I can send the kernel oopses (I
have about four or five), but I'd recommend just examining the line_info()
and serial_in() code in serial.c before diving into an oops.

This diff is against 2.3.23 from linux.kernel.org; expect a 5 line offset,
since I've elided my RCS stuff.

--- drivers/char/serial.c 1999/10/23 20:08:40 1.1
+++ drivers/char/serial.c 1999/10/23 23:06:26
@@ -3061,20 +3066,41 @@
}

/*
- * Figure out the current RS-232 lines
+ * Figure out the current RS-232 control and status lines.
*/
if (!info) {
- info = &scr_info; /* This is just for serial_{in,out} */
+ info = &scr_info; /* This is just for serial_in() */

- info->magic = SERIAL_MAGIC;
+ /*
+ * Based on info initialization in autoconfig() below.
+ */
+ info->magic = SERIAL_MAGIC; /* unused */
+ info->state = state; /* unused */
info->port = state->port;
- info->flags = state->flags;
+ info->flags = state->flags; /* unused */
+#ifdef CONFIG_HUB6
+ info->hub6 = state->hub6;
+#endif
+#ifdef CONFIG_SERIAL_PCI_MEMMAPPED
+ info->iomem_base = state->iomem_base;
+ info->iomem_reg_shift = state->iomem_reg_shift;
+#endif
+ /*
+ * Other references used below.
+ */
+ info->MCR = 0;
info->quot = 0;
- info->tty = 0;
}
+
+ /*
+ * Is info->MCR always valid here? Or should we always do
+ * serial_in(info, UART_MCR)?
+ * In any case, the old info ? test is unneeded.
+ */
+ control = info->MCR;
+
save_flags(flags); cli();
status = serial_in(info, UART_MSR);
- control = info ? info->MCR : serial_in(info, UART_MCR);
restore_flags(flags);

stat_buf[0] = 0;

Bruce Jerrick
Portland, Oregon, USA
email: bjerrick@easystreet.com

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/