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

driver core: Fix unbalanced device reference in drivers_probe

bus_find_device_by_name() acquires a device reference which is never
released. This results in an object leak, which on older kernels
results in failure to release all resources of PCI devices. libvirt
uses drivers_probe to re-attach devices to the host after assignment
and is therefore a common trigger for this leak.

Example:

# cd /sys/bus/pci/
# dmesg -C
# echo 1 > devices/0000\:01\:00.0/sriov_numvfs
# echo 0 > devices/0000\:01\:00.0/sriov_numvfs
# dmesg | grep 01:10
pci 0000:01:10.0: [8086:10ca] type 00 class 0x020000
kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_add_internal: parent: '0000:00:01.0', set: 'devices'
kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_uevent_env
kobject: '0000:01:10.0' (ffff8801d79cd0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0'
kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_uevent_env
kobject: '0000:01:10.0' (ffff8801d79cd0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0'
kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_uevent_env
kobject: '0000:01:10.0' (ffff8801d79cd0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0'
kobject: '0000:01:10.0' (ffff8801d79cd0a8): kobject_cleanup, parent (null)
kobject: '0000:01:10.0' (ffff8801d79cd0a8): calling ktype release
kobject: '0000:01:10.0': free name

[kobject freed as expected]

# dmesg -C
# echo 1 > devices/0000\:01\:00.0/sriov_numvfs
# echo 0000:01:10.0 > drivers_probe
# echo 0 > devices/0000\:01\:00.0/sriov_numvfs
# dmesg | grep 01:10
pci 0000:01:10.0: [8086:10ca] type 00 class 0x020000
kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_add_internal: parent: '0000:00:01.0', set: 'devices'
kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_uevent_env
kobject: '0000:01:10.0' (ffff8801d79ce0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0'
kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_uevent_env
kobject: '0000:01:10.0' (ffff8801d79ce0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0'
kobject: '0000:01:10.0' (ffff8801d79ce0a8): kobject_uevent_env
kobject: '0000:01:10.0' (ffff8801d79ce0a8): fill_kobj_path: path = '/devices/pci0000:00/0000:00:01.0/0000:01:10.0'

[no free]

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alex Williamson and committed by
Greg Kroah-Hartman
bb34cb6b 7750efd5

+5 -3
+5 -3
drivers/base/bus.c
··· 254 254 const char *buf, size_t count) 255 255 { 256 256 struct device *dev; 257 + int err = -EINVAL; 257 258 258 259 dev = bus_find_device_by_name(bus, NULL, buf); 259 260 if (!dev) 260 261 return -ENODEV; 261 - if (bus_rescan_devices_helper(dev, NULL) != 0) 262 - return -EINVAL; 263 - return count; 262 + if (bus_rescan_devices_helper(dev, NULL) == 0) 263 + err = count; 264 + put_device(dev); 265 + return err; 264 266 } 265 267 266 268 static struct device *next_device(struct klist_iter *i)