mirror of
https://github.com/torvalds/linux.git
synced 2024-12-28 13:51:44 +00:00
[PATCH] Remove race between con_open and con_close
[ Same race and same patch also by Steven Rostedt <rostedt@goodmis.org> ] I have a laptop (G3 powerbook) which will pretty reliably hit a race between con_open and con_close late in the boot process and oops in vt_ioctl due to tty->driver_data being NULL. What happens is this: process A opens /dev/tty6; it comes into con_open() (drivers/char/vt.c) and assign a non-NULL value to tty->driver_data. Then process A closes that and concurrently process B opens /dev/tty6. Process A gets through con_close() and clears tty->driver_data, since tty->count == 1. However, before process A can decrement tty->count, we switch to process B (e.g. at the down(&tty_sem) call at drivers/char/tty_io.c line 1626). So process B gets to run and comes into con_open with tty->count == 2, as tty->count is incremented (in init_dev) before con_open is called. Because tty->count != 1, we don't set tty->driver_data. Then when the process tries to do anything with that fd, it oopses. The simple and effective fix for this is to test tty->driver_data rather than tty->count in con_open. The testing and setting of tty->driver_data is serialized with respect to the clearing of tty->driver_data in con_close by the console_sem. We can't get a situation where con_open sees tty->driver_data != NULL and then con_close on a different fd clears tty->driver_data, because tty->count is incremented before con_open is called. Thus this patch eliminates the race, and in fact with this patch my laptop doesn't oops. Signed-off-by: Paul Mackerras <paulus@samba.org> [ Same patch Signed-off-by: Steven Rostedt <rostedt@goodmis.org> in http://marc.theaimsgroup.com/?l=linux-kernel&m=112450820432121&w=2 ] Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
3859f6a248
commit
f786648b89
@ -2433,7 +2433,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
acquire_console_sem();
|
acquire_console_sem();
|
||||||
if (tty->count == 1) {
|
if (tty->driver_data == NULL) {
|
||||||
ret = vc_allocate(currcons);
|
ret = vc_allocate(currcons);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
struct vc_data *vc = vc_cons[currcons].d;
|
struct vc_data *vc = vc_cons[currcons].d;
|
||||||
|
Loading…
Reference in New Issue
Block a user