Hi Greg, I think there is a race between usb_serial_put() and usb_serial_get_by_index() (and get_free_serial()) with regards to handling the serial port refcount.
usb_serial_get_by_index() gets a reference on the serial port under table_lock while return_serial releases all the returned ports from the table under the same lock. However, the table_lock is not taken around the call to kref_put, theoretically allowing to sneak in and grab a reference after kref_put has already determined that the reference count is zero (and before calling destroy_serial) causing use after free. How about this fix? >From b91b9cffd8bbb727c6480dfb18f79655806237e6 Mon Sep 17 00:00:00 2001 From: Benny Halevy <[EMAIL PROTECTED]> Date: Tue, 15 May 2007 10:41:31 +0300 Subject: [PATCH] fix usb_serial_put synchronization Signed-off-by: Benny Halevy <[EMAIL PROTECTED]> --- drivers/usb/serial/usb-serial.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 87f3788..4e5b996 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -120,11 +120,9 @@ static void return_serial(struct usb_serial *serial) if (serial == NULL) return; - spin_lock(&table_lock); for (i = 0; i < serial->num_ports; ++i) { serial_table[serial->minor + i] = NULL; } - spin_unlock(&table_lock); } static void destroy_serial(struct kref *kref) @@ -172,7 +170,9 @@ static void destroy_serial(struct kref *kref) void usb_serial_put(struct usb_serial *serial) { + spin_lock(&table_lock); kref_put(&serial->kref, destroy_serial); + spin_unlock(&table_lock); } /***************************************************************************** - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/