Skip to content

Commit d953e0e

Browse files
George Spelvingregkh
George Spelvin
authored andcommitted
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>
1 parent 03a7ffe commit d953e0e

File tree

1 file changed

+10
-4
lines changed

1 file changed

+10
-4
lines changed

drivers/pps/pps.c

+10-4
Original file line numberDiff line numberDiff line change
@@ -247,12 +247,15 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
247247
struct pps_device *pps = container_of(inode->i_cdev,
248248
struct pps_device, cdev);
249249
file->private_data = pps;
250-
250+
kobject_get(&pps->dev->kobj);
251251
return 0;
252252
}
253253

254254
static int pps_cdev_release(struct inode *inode, struct file *file)
255255
{
256+
struct pps_device *pps = container_of(inode->i_cdev,
257+
struct pps_device, cdev);
258+
kobject_put(&pps->dev->kobj);
256259
return 0;
257260
}
258261

@@ -274,8 +277,10 @@ static void pps_device_destruct(struct device *dev)
274277
{
275278
struct pps_device *pps = dev_get_drvdata(dev);
276279

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);
279284
mutex_lock(&pps_idr_lock);
280285
idr_remove(&pps_idr, pps->id);
281286
mutex_unlock(&pps_idr_lock);
@@ -332,6 +337,7 @@ int pps_register_cdev(struct pps_device *pps)
332337
goto del_cdev;
333338
}
334339

340+
/* Override the release function with our own */
335341
pps->dev->release = pps_device_destruct;
336342

337343
pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
@@ -352,9 +358,9 @@ int pps_register_cdev(struct pps_device *pps)
352358

353359
void pps_unregister_cdev(struct pps_device *pps)
354360
{
361+
pr_debug("unregistering pps%d\n", pps->id);
355362
pps->lookup_cookie = NULL;
356363
device_destroy(pps_class, pps->dev->devt);
357-
cdev_del(&pps->cdev);
358364
}
359365

360366
/*

0 commit comments

Comments
 (0)