Commit d953e0e837e65ecc1ddaa4f9560f7925878a0de6

Authored by George Spelvin
Committed by Greg Kroah-Hartman
1 parent 03a7ffe4e5

pps: Fix a use-after free bug when unregistering a source.

Remove the cdev from the system (with cdev_del) *before* deallocating it
(in pps_device_destruct, called via kobject_put from device_destroy).

Also prevent deallocating a device with open file handles.

A better long-term fix is probably to remove the cdev from the pps_device
entirely, and instead have all devices reference one global cdev.  Then
the deallocation ordering becomes simpler.

But that's more complex and invasive change, so we leave that
for later.

Signed-off-by: George Spelvin <linux@horizon.com>
Cc: stable <stable@vger.kernel.org>
Acked-by: Rodolfo Giometti <giometti@enneenne.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 1 changed file with 10 additions and 4 deletions Side-by-side Diff

... ... @@ -247,12 +247,15 @@
247 247 struct pps_device *pps = container_of(inode->i_cdev,
248 248 struct pps_device, cdev);
249 249 file->private_data = pps;
250   -
  250 + kobject_get(&pps->dev->kobj);
251 251 return 0;
252 252 }
253 253  
254 254 static int pps_cdev_release(struct inode *inode, struct file *file)
255 255 {
  256 + struct pps_device *pps = container_of(inode->i_cdev,
  257 + struct pps_device, cdev);
  258 + kobject_put(&pps->dev->kobj);
256 259 return 0;
257 260 }
258 261  
... ... @@ -274,8 +277,10 @@
274 277 {
275 278 struct pps_device *pps = dev_get_drvdata(dev);
276 279  
277   - /* release id here to protect others from using it while it's
278   - * still in use */
  280 + cdev_del(&pps->cdev);
  281 +
  282 + /* Now we can release the ID for re-use */
  283 + pr_debug("deallocating pps%d\n", pps->id);
279 284 mutex_lock(&pps_idr_lock);
280 285 idr_remove(&pps_idr, pps->id);
281 286 mutex_unlock(&pps_idr_lock);
... ... @@ -332,6 +337,7 @@
332 337 goto del_cdev;
333 338 }
334 339  
  340 + /* Override the release function with our own */
335 341 pps->dev->release = pps_device_destruct;
336 342  
337 343 pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
338 344  
... ... @@ -352,9 +358,9 @@
352 358  
353 359 void pps_unregister_cdev(struct pps_device *pps)
354 360 {
  361 + pr_debug("unregistering pps%d\n", pps->id);
355 362 pps->lookup_cookie = NULL;
356 363 device_destroy(pps_class, pps->dev->devt);
357   - cdev_del(&pps->cdev);
358 364 }
359 365  
360 366 /*