Commit a15d49fd3094cff90e5410ca454a870e0a722fe1

Authored by Hannes Reinecke
Committed by Greg Kroah-Hartman
1 parent 97ec448aea

driver core: check start node in klist_iter_init_node

klist_iter_init_node() takes a node as a start argument.
However, this node might not be valid anymore.
This patch updates the klist_iter_init_node() and
dependent functions to return an error if so.
All calling functions have been audited to check
for a return code here.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Cc: Greg Kroah-Hartmann <gregkh@linuxfoundation.org>
Cc: Kay Sievers <kay@vrfy.org>
Cc: Stable Kernel <stable@kernel.org>
Cc: Linux Kernel <linux-kernel@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 6 changed files with 76 additions and 46 deletions Side-by-side Diff

... ... @@ -296,11 +296,13 @@
296 296 if (!bus)
297 297 return -EINVAL;
298 298  
299   - klist_iter_init_node(&bus->p->klist_devices, &i,
300   - (start ? &start->p->knode_bus : NULL));
301   - while ((dev = next_device(&i)) && !error)
302   - error = fn(dev, data);
303   - klist_iter_exit(&i);
  299 + error = klist_iter_init_node(&bus->p->klist_devices, &i,
  300 + (start ? &start->p->knode_bus : NULL));
  301 + if (!error) {
  302 + while ((dev = next_device(&i)) && !error)
  303 + error = fn(dev, data);
  304 + klist_iter_exit(&i);
  305 + }
304 306 return error;
305 307 }
306 308 EXPORT_SYMBOL_GPL(bus_for_each_dev);
... ... @@ -330,8 +332,10 @@
330 332 if (!bus)
331 333 return NULL;
332 334  
333   - klist_iter_init_node(&bus->p->klist_devices, &i,
334   - (start ? &start->p->knode_bus : NULL));
  335 + if (klist_iter_init_node(&bus->p->klist_devices, &i,
  336 + (start ? &start->p->knode_bus : NULL)) < 0)
  337 + return NULL;
  338 +
335 339 while ((dev = next_device(&i)))
336 340 if (match(dev, data) && get_device(dev))
337 341 break;
... ... @@ -384,7 +388,9 @@
384 388 return NULL;
385 389  
386 390 if (hint) {
387   - klist_iter_init_node(&subsys->p->klist_devices, &i, &hint->p->knode_bus);
  391 + if (klist_iter_init_node(&subsys->p->klist_devices, &i,
  392 + &hint->p->knode_bus) < 0)
  393 + return NULL;
388 394 dev = next_device(&i);
389 395 if (dev && dev->id == id && get_device(dev)) {
390 396 klist_iter_exit(&i);
... ... @@ -446,11 +452,13 @@
446 452 if (!bus)
447 453 return -EINVAL;
448 454  
449   - klist_iter_init_node(&bus->p->klist_drivers, &i,
450   - start ? &start->p->knode_bus : NULL);
451   - while ((drv = next_driver(&i)) && !error)
452   - error = fn(drv, data);
453   - klist_iter_exit(&i);
  455 + error = klist_iter_init_node(&bus->p->klist_drivers, &i,
  456 + start ? &start->p->knode_bus : NULL);
  457 + if (!error) {
  458 + while ((drv = next_driver(&i)) && !error)
  459 + error = fn(drv, data);
  460 + klist_iter_exit(&i);
  461 + }
454 462 return error;
455 463 }
456 464 EXPORT_SYMBOL_GPL(bus_for_each_drv);
457 465  
458 466  
... ... @@ -1111,15 +1119,19 @@
1111 1119 * otherwise if it is NULL, the iteration starts at the beginning of
1112 1120 * the list.
1113 1121 */
1114   -void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys,
1115   - struct device *start, const struct device_type *type)
  1122 +int subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys,
  1123 + struct device *start, const struct device_type *type)
1116 1124 {
1117 1125 struct klist_node *start_knode = NULL;
  1126 + int error;
1118 1127  
1119 1128 if (start)
1120 1129 start_knode = &start->p->knode_bus;
1121   - klist_iter_init_node(&subsys->p->klist_devices, &iter->ki, start_knode);
1122   - iter->type = type;
  1130 + error = klist_iter_init_node(&subsys->p->klist_devices, &iter->ki,
  1131 + start_knode);
  1132 + if (!error)
  1133 + iter->type = type;
  1134 + return error;
1123 1135 }
1124 1136 EXPORT_SYMBOL_GPL(subsys_dev_iter_init);
1125 1137  
drivers/base/class.c
... ... @@ -301,15 +301,20 @@
301 301 * otherwise if it is NULL, the iteration starts at the beginning of
302 302 * the list.
303 303 */
304   -void class_dev_iter_init(struct class_dev_iter *iter, struct class *class,
305   - struct device *start, const struct device_type *type)
  304 +int class_dev_iter_init(struct class_dev_iter *iter, struct class *class,
  305 + struct device *start, const struct device_type *type)
306 306 {
307 307 struct klist_node *start_knode = NULL;
  308 + int error;
308 309  
309 310 if (start)
310 311 start_knode = &start->knode_class;
311   - klist_iter_init_node(&class->p->klist_devices, &iter->ki, start_knode);
312   - iter->type = type;
  312 + error = klist_iter_init_node(&class->p->klist_devices, &iter->ki,
  313 + start_knode);
  314 + if (!error)
  315 + iter->type = type;
  316 +
  317 + return error;
313 318 }
314 319 EXPORT_SYMBOL_GPL(class_dev_iter_init);
315 320  
316 321  
... ... @@ -387,14 +392,15 @@
387 392 return -EINVAL;
388 393 }
389 394  
390   - class_dev_iter_init(&iter, class, start, NULL);
391   - while ((dev = class_dev_iter_next(&iter))) {
392   - error = fn(dev, data);
393   - if (error)
394   - break;
  395 + error = class_dev_iter_init(&iter, class, start, NULL);
  396 + if (!error) {
  397 + while ((dev = class_dev_iter_next(&iter))) {
  398 + error = fn(dev, data);
  399 + if (error)
  400 + break;
  401 + }
  402 + class_dev_iter_exit(&iter);
395 403 }
396   - class_dev_iter_exit(&iter);
397   -
398 404 return error;
399 405 }
400 406 EXPORT_SYMBOL_GPL(class_for_each_device);
... ... @@ -434,7 +440,9 @@
434 440 return NULL;
435 441 }
436 442  
437   - class_dev_iter_init(&iter, class, start, NULL);
  443 + if (class_dev_iter_init(&iter, class, start, NULL) < 0)
  444 + return NULL;
  445 +
438 446 while ((dev = class_dev_iter_next(&iter))) {
439 447 if (match(dev, data)) {
440 448 get_device(dev);
drivers/base/driver.c
... ... @@ -49,11 +49,13 @@
49 49 if (!drv)
50 50 return -EINVAL;
51 51  
52   - klist_iter_init_node(&drv->p->klist_devices, &i,
53   - start ? &start->p->knode_driver : NULL);
54   - while ((dev = next_device(&i)) && !error)
55   - error = fn(dev, data);
56   - klist_iter_exit(&i);
  52 + error = klist_iter_init_node(&drv->p->klist_devices, &i,
  53 + start ? &start->p->knode_driver : NULL);
  54 + if (!error) {
  55 + while ((dev = next_device(&i)) && !error)
  56 + error = fn(dev, data);
  57 + klist_iter_exit(&i);
  58 + }
57 59 return error;
58 60 }
59 61 EXPORT_SYMBOL_GPL(driver_for_each_device);
... ... @@ -83,8 +85,10 @@
83 85 if (!drv)
84 86 return NULL;
85 87  
86   - klist_iter_init_node(&drv->p->klist_devices, &i,
87   - (start ? &start->p->knode_driver : NULL));
  88 + if (klist_iter_init_node(&drv->p->klist_devices, &i,
  89 + (start ? &start->p->knode_driver : NULL)) < 0)
  90 + return NULL;
  91 +
88 92 while ((dev = next_device(&i)))
89 93 if (match(dev, data) && get_device(dev))
90 94 break;
include/linux/device.h
... ... @@ -128,7 +128,7 @@
128 128 struct klist_iter ki;
129 129 const struct device_type *type;
130 130 };
131   -void subsys_dev_iter_init(struct subsys_dev_iter *iter,
  131 +int subsys_dev_iter_init(struct subsys_dev_iter *iter,
132 132 struct bus_type *subsys,
133 133 struct device *start,
134 134 const struct device_type *type);
... ... @@ -380,10 +380,10 @@
380 380 void class_compat_remove_link(struct class_compat *cls, struct device *dev,
381 381 struct device *device_link);
382 382  
383   -extern void class_dev_iter_init(struct class_dev_iter *iter,
384   - struct class *class,
385   - struct device *start,
386   - const struct device_type *type);
  383 +extern int class_dev_iter_init(struct class_dev_iter *iter,
  384 + struct class *class,
  385 + struct device *start,
  386 + const struct device_type *type);
387 387 extern struct device *class_dev_iter_next(struct class_dev_iter *iter);
388 388 extern void class_dev_iter_exit(struct class_dev_iter *iter);
389 389  
include/linux/klist.h
... ... @@ -60,7 +60,7 @@
60 60  
61 61  
62 62 extern void klist_iter_init(struct klist *k, struct klist_iter *i);
63   -extern void klist_iter_init_node(struct klist *k, struct klist_iter *i,
  63 +extern int klist_iter_init_node(struct klist *k, struct klist_iter *i,
64 64 struct klist_node *n);
65 65 extern void klist_iter_exit(struct klist_iter *i);
66 66 extern struct klist_node *klist_next(struct klist_iter *i);
... ... @@ -278,13 +278,19 @@
278 278 * Similar to klist_iter_init(), but starts the action off with @n,
279 279 * instead of with the list head.
280 280 */
281   -void klist_iter_init_node(struct klist *k, struct klist_iter *i,
282   - struct klist_node *n)
  281 +int klist_iter_init_node(struct klist *k, struct klist_iter *i,
  282 + struct klist_node *n)
283 283 {
  284 + if (n) {
  285 + kref_get(&n->n_ref);
  286 + if (!n->n_klist) {
  287 + kref_put(&n->n_ref);
  288 + return -ENODEV;
  289 + }
  290 + }
284 291 i->i_klist = k;
285 292 i->i_cur = n;
286   - if (n)
287   - kref_get(&n->n_ref);
  293 + return 0;
288 294 }
289 295 EXPORT_SYMBOL_GPL(klist_iter_init_node);
290 296