Re: [PATCH] tty: add lockdep annotations

From: Eric Dumazet
Date: Fri Jun 01 2012 - 16:45:07 EST


On Fri, 2012-06-01 at 11:51 -0700, Linus Torvalds wrote:
> On Fri, Jun 1, 2012 at 11:17 AM, Eric Dumazet <eric.dumazet@xxxxxxxxx> wrote:
> >
> > About 10% of boots on my machine, and this looks like (hand written)
> >
> > general protection fault: 0000 [#1] SMP DEBUG_PAGEALLOC
> > ...
> > RIP : tty_shutdown+0x15/)x70
>
> Ok, DEBUG_PAGEALLOC and with that offset fairly early in tty_shutdown,
> it's almost certainly one of the accesses in the
>
> tty->driver->ops->remove
>

Yes, tty->driver deref is ok (tty points to valid memory), but crash is
on tty->driver->ops (driver points to freed/illegal memory)

using slub_debug=FZPU, I can indeed see RDI=6b6b6b6b6b6b6b6b

Typical use after free...

> chain when it does the (inlined)
>
> tty_driver_remove_tty(tty->driver, tty);
>
> you could check which one it is at that offset 0x15, but I think both
> the ops and the driver structures should be statically allocated, so I
> suspect it's the "tty" itself that is already freed.
>
> Odd. But yes, smells very much like a refcount issue, probably due to
> broken locking. Does the problem go away if you revert commits
> d29f3ef39be4 ("tty_lock: Localise the lock") and 3af502b96649
> ("tty_lock: undo the old tty_lock use on the ctty")?

Tried this but seems not straightforward, and its pretty late here in
France, week end starting ;)

By the way, release_one_tty() uses the following racy code :

tty_driver_kref_put(driver);
module_put(driver->owner);

I would use following patch to make sure bad things cant happen...

Thanks
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 9e930c0..b8faf40 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1479,13 +1479,14 @@ static void release_one_tty(struct work_struct *work)
struct tty_struct *tty =
container_of(work, struct tty_struct, hangup_work);
struct tty_driver *driver = tty->driver;
+ struct module *module = driver->owner;

if (tty->ops->cleanup)
tty->ops->cleanup(tty);

tty->magic = 0;
tty_driver_kref_put(driver);
- module_put(driver->owner);
+ module_put(module);

spin_lock(&tty_files_lock);
list_del_init(&tty->tty_files);


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