Skip to content

Commit 8a12f88

Browse files
anirudhrbdavem330
authored andcommitted
net: hso: fix null-ptr-deref during tty device unregistration
Multiple ttys try to claim the same the minor number causing a double unregistration of the same device. The first unregistration succeeds but the next one results in a null-ptr-deref. The get_free_serial_index() function returns an available minor number but doesn't assign it immediately. The assignment is done by the caller later. But before this assignment, calls to get_free_serial_index() would return the same minor number. Fix this by modifying get_free_serial_index to assign the minor number immediately after one is found to be and rename it to obtain_minor() to better reflect what it does. Similary, rename set_serial_by_index() to release_minor() and modify it to free up the minor number of the given hso_serial. Every obtain_minor() should have corresponding release_minor() call. Fixes: 72dc1c0 ("HSO: add option hso driver") Reported-by: [email protected] Tested-by: [email protected] Reviewed-by: Greg Kroah-Hartman <[email protected]> Signed-off-by: Anirudh Rayabharam <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5d1dbac commit 8a12f88

File tree

1 file changed

+12
-21
lines changed

1 file changed

+12
-21
lines changed

drivers/net/usb/hso.c

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -611,16 +611,18 @@ static struct hso_serial *get_serial_by_index(unsigned index)
611611
return serial;
612612
}
613613

614-
static int get_free_serial_index(void)
614+
static int obtain_minor(struct hso_serial *serial)
615615
{
616616
int index;
617617
unsigned long flags;
618618

619619
spin_lock_irqsave(&serial_table_lock, flags);
620620
for (index = 0; index < HSO_SERIAL_TTY_MINORS; index++) {
621621
if (serial_table[index] == NULL) {
622+
serial_table[index] = serial->parent;
623+
serial->minor = index;
622624
spin_unlock_irqrestore(&serial_table_lock, flags);
623-
return index;
625+
return 0;
624626
}
625627
}
626628
spin_unlock_irqrestore(&serial_table_lock, flags);
@@ -629,15 +631,12 @@ static int get_free_serial_index(void)
629631
return -1;
630632
}
631633

632-
static void set_serial_by_index(unsigned index, struct hso_serial *serial)
634+
static void release_minor(struct hso_serial *serial)
633635
{
634636
unsigned long flags;
635637

636638
spin_lock_irqsave(&serial_table_lock, flags);
637-
if (serial)
638-
serial_table[index] = serial->parent;
639-
else
640-
serial_table[index] = NULL;
639+
serial_table[serial->minor] = NULL;
641640
spin_unlock_irqrestore(&serial_table_lock, flags);
642641
}
643642

@@ -2230,6 +2229,7 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
22302229
static void hso_serial_tty_unregister(struct hso_serial *serial)
22312230
{
22322231
tty_unregister_device(tty_drv, serial->minor);
2232+
release_minor(serial);
22332233
}
22342234

22352235
static void hso_serial_common_free(struct hso_serial *serial)
@@ -2253,24 +2253,22 @@ static void hso_serial_common_free(struct hso_serial *serial)
22532253
static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
22542254
int rx_size, int tx_size)
22552255
{
2256-
int minor;
22572256
int i;
22582257

22592258
tty_port_init(&serial->port);
22602259

2261-
minor = get_free_serial_index();
2262-
if (minor < 0)
2260+
if (obtain_minor(serial))
22632261
goto exit2;
22642262

22652263
/* register our minor number */
22662264
serial->parent->dev = tty_port_register_device_attr(&serial->port,
2267-
tty_drv, minor, &serial->parent->interface->dev,
2265+
tty_drv, serial->minor, &serial->parent->interface->dev,
22682266
serial->parent, hso_serial_dev_groups);
2269-
if (IS_ERR(serial->parent->dev))
2267+
if (IS_ERR(serial->parent->dev)) {
2268+
release_minor(serial);
22702269
goto exit2;
2270+
}
22712271

2272-
/* fill in specific data for later use */
2273-
serial->minor = minor;
22742272
serial->magic = HSO_SERIAL_MAGIC;
22752273
spin_lock_init(&serial->serial_lock);
22762274
serial->num_rx_urbs = num_urbs;
@@ -2667,9 +2665,6 @@ static struct hso_device *hso_create_bulk_serial_device(
26672665

26682666
serial->write_data = hso_std_serial_write_data;
26692667

2670-
/* and record this serial */
2671-
set_serial_by_index(serial->minor, serial);
2672-
26732668
/* setup the proc dirs and files if needed */
26742669
hso_log_port(hso_dev);
26752670

@@ -2726,9 +2721,6 @@ struct hso_device *hso_create_mux_serial_device(struct usb_interface *interface,
27262721
serial->shared_int->ref_count++;
27272722
mutex_unlock(&serial->shared_int->shared_int_lock);
27282723

2729-
/* and record this serial */
2730-
set_serial_by_index(serial->minor, serial);
2731-
27322724
/* setup the proc dirs and files if needed */
27332725
hso_log_port(hso_dev);
27342726

@@ -3113,7 +3105,6 @@ static void hso_free_interface(struct usb_interface *interface)
31133105
cancel_work_sync(&serial_table[i]->async_get_intf);
31143106
hso_serial_tty_unregister(serial);
31153107
kref_put(&serial_table[i]->ref, hso_serial_ref_free);
3116-
set_serial_by_index(i, NULL);
31173108
}
31183109
}
31193110

0 commit comments

Comments
 (0)