Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: fix locking in idmouse

Pete caused me to lock at buggy drivers in this respect. The idmouse has
a race between open and disconnect. This patch

- solves the open/disconnect race
- switches locking to mutexes

Signed-off-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>


authored by

Oliver Neukum and committed by
Greg Kroah-Hartman
54d2bc06 439a903a

+28 -17
+28 -17
drivers/usb/misc/idmouse.c
··· 66 66 USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000) 67 67 68 68 MODULE_DEVICE_TABLE(usb, idmouse_table); 69 + static DEFINE_MUTEX(open_disc_mutex); 69 70 70 71 /* structure to hold all of our device specific stuff */ 71 72 struct usb_idmouse { ··· 81 80 82 81 int open; /* if the port is open or not */ 83 82 int present; /* if the device is not disconnected */ 84 - struct semaphore sem; /* locks this structure */ 83 + struct mutex lock; /* locks this structure */ 85 84 86 85 }; 87 86 ··· 214 213 if (!interface) 215 214 return -ENODEV; 216 215 216 + mutex_lock(&open_disc_mutex); 217 217 /* get the device information block from the interface */ 218 218 dev = usb_get_intfdata(interface); 219 - if (!dev) 219 + if (!dev) { 220 + mutex_unlock(&open_disc_mutex); 220 221 return -ENODEV; 222 + } 221 223 222 224 /* lock this device */ 223 - down(&dev->sem); 225 + mutex_lock(&dev->lock); 226 + mutex_unlock(&open_disc_mutex); 224 227 225 228 /* check if already open */ 226 229 if (dev->open) { ··· 250 245 error: 251 246 252 247 /* unlock this device */ 253 - up(&dev->sem); 248 + mutex_unlock(&dev->lock); 254 249 return result; 255 250 } 256 251 ··· 263 258 if (dev == NULL) 264 259 return -ENODEV; 265 260 261 + mutex_lock(&open_disc_mutex); 266 262 /* lock our device */ 267 - down(&dev->sem); 263 + mutex_lock(&dev->lock); 268 264 269 265 /* are we really open? */ 270 266 if (dev->open <= 0) { 271 - up(&dev->sem); 267 + mutex_unlock(&dev->lock); 268 + mutex_unlock(&open_disc_mutex); 272 269 return -ENODEV; 273 270 } 274 271 ··· 278 271 279 272 if (!dev->present) { 280 273 /* the device was unplugged before the file was released */ 281 - up(&dev->sem); 274 + mutex_unlock(&dev->lock); 275 + mutex_unlock(&open_disc_mutex); 282 276 idmouse_delete(dev); 283 277 } else { 284 - up(&dev->sem); 278 + mutex_unlock(&dev->lock); 279 + mutex_unlock(&open_disc_mutex); 285 280 } 286 281 return 0; 287 282 } ··· 295 286 int result; 296 287 297 288 /* lock this object */ 298 - down(&dev->sem); 289 + mutex_lock(&dev->lock); 299 290 300 291 /* verify that the device wasn't unplugged */ 301 292 if (!dev->present) { 302 - up(&dev->sem); 293 + mutex_unlock(&dev->lock); 303 294 return -ENODEV; 304 295 } 305 296 306 297 result = simple_read_from_buffer(buffer, count, ppos, 307 298 dev->bulk_in_buffer, IMGSIZE); 308 299 /* unlock the device */ 309 - up(&dev->sem); 300 + mutex_unlock(&dev->lock); 310 301 return result; 311 302 } 312 303 ··· 329 320 if (dev == NULL) 330 321 return -ENOMEM; 331 322 332 - init_MUTEX(&dev->sem); 323 + mutex_init(&dev->lock); 333 324 dev->udev = udev; 334 325 dev->interface = interface; 335 326 ··· 381 372 382 373 /* get device structure */ 383 374 dev = usb_get_intfdata(interface); 384 - usb_set_intfdata(interface, NULL); 385 375 386 376 /* give back our minor */ 387 377 usb_deregister_dev(interface, &idmouse_class); 388 378 389 - /* lock it */ 390 - down(&dev->sem); 379 + mutex_lock(&open_disc_mutex); 380 + usb_set_intfdata(interface, NULL); 381 + /* lock the device */ 382 + mutex_lock(&dev->lock); 383 + mutex_unlock(&open_disc_mutex); 391 384 392 385 /* prevent device read, write and ioctl */ 393 386 dev->present = 0; 394 387 395 388 /* if the device is opened, idmouse_release will clean this up */ 396 389 if (!dev->open) { 397 - up(&dev->sem); 390 + mutex_unlock(&dev->lock); 398 391 idmouse_delete(dev); 399 392 } else { 400 393 /* unlock */ 401 - up(&dev->sem); 394 + mutex_unlock(&dev->lock); 402 395 } 403 396 404 397 info("%s disconnected", DRIVER_DESC);