DF-1843 / fix.diff
diff --git a/sys/dev/disk/dm/device-mapper.c b/sys/dev/disk/dm/device-mapper.c --- a/sys/dev/disk/dm/device-mapper.c +++ b/sys/dev/disk/dm/device-mapper.c @@ -209,8 +209,12 @@ if ((dmv = dm_dev_lookup(NULL, NULL, minor(dev))) == NULL) return ENXIO; + /* Hold the busy reference for the lifetime of the open. Previously + * dmopen called dm_dev_unbusy immediately, leaving the open fd with + * dev->si_drv1 -> dmv but no refcount. dm_dev_remove_ioctl could + * then race is_open=0, free the dmv, and leave a UAF for the next + * dmstrategy. The matching extra dm_dev_unbusy is in dmclose. */ dmv->is_open = 1; - dm_dev_unbusy(dmv); dmdebug("minor=%" PRIu32 "\n", minor(ap->a_head.a_dev)); return 0; @@ -230,6 +234,9 @@ return ENXIO; dmv->is_open = 0; + /* Drop dmopen's held reference first (so disable_dev's ref_cnt==0 + * wait can complete in order), then drop this lookup's reference. */ + dm_dev_unbusy(dmv); dm_dev_unbusy(dmv); dmdebug("minor=%" PRIu32 "\n", minor(ap->a_head.a_dev)); |