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

of: overlay: check prevents multiple fragments add or delete same node

Multiple overlay fragments adding or deleting the same node is not
supported. Replace code comment of such, with check to detect the
attempt and fail the overlay apply.

Devicetree unittest where multiple fragments added the same node was
added in the previous patch in the series. After applying this patch
the unittest messages will no longer include:

Duplicate name in motor-1, renamed to "controller#1"
OF: overlay: of_overlay_apply() err=0
### dt-test ### of_overlay_fdt_apply() expected -22, ret=0, overlay_bad_add_dup_node
### dt-test ### FAIL of_unittest_overlay_high_level():2419 Adding overlay 'overlay_bad_add_dup_node' failed

...

### dt-test ### end of unittest - 210 passed, 1 failed

but will instead include:

OF: overlay: ERROR: multiple overlay fragments add and/or delete node /testcase-data-2/substation@100/motor-1/controller

...

### dt-test ### end of unittest - 211 passed, 0 failed

Tested-by: Alan Tull <atull@kernel.org>
Signed-off-by: Frank Rowand <frank.rowand@sony.com>

+49 -9
+49 -9
drivers/of/overlay.c
··· 392 392 * a live devicetree created from Open Firmware. 393 393 * 394 394 * NOTE_2: Multiple mods of created nodes not supported. 395 - * If more than one fragment contains a node that does not already exist 396 - * in the live tree, then for each fragment of_changeset_attach_node() 397 - * will add a changeset entry to add the node. When the changeset is 398 - * applied, __of_attach_node() will attach the node twice (once for 399 - * each fragment). At this point the device tree will be corrupted. 400 - * 401 - * TODO: add integrity check to ensure that multiple fragments do not 402 - * create the same node. 403 395 * 404 396 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if 405 397 * invalid @overlay. ··· 509 517 } 510 518 511 519 /** 520 + * check_changeset_dup_add_node() - changeset validation: duplicate add node 521 + * @ovcs: Overlay changeset 522 + * 523 + * Check changeset @ovcs->cset for multiple add node entries for the same 524 + * node. 525 + * 526 + * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if 527 + * invalid overlay in @ovcs->fragments[]. 528 + */ 529 + static int check_changeset_dup_add_node(struct overlay_changeset *ovcs) 530 + { 531 + struct of_changeset_entry *ce_1, *ce_2; 532 + char *fn_1, *fn_2; 533 + int name_match; 534 + 535 + list_for_each_entry(ce_1, &ovcs->cset.entries, node) { 536 + 537 + if (ce_1->action == OF_RECONFIG_ATTACH_NODE || 538 + ce_1->action == OF_RECONFIG_DETACH_NODE) { 539 + 540 + ce_2 = ce_1; 541 + list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) { 542 + if (ce_2->action == OF_RECONFIG_ATTACH_NODE || 543 + ce_2->action == OF_RECONFIG_DETACH_NODE) { 544 + /* inexpensive name compare */ 545 + if (!of_node_cmp(ce_1->np->full_name, 546 + ce_2->np->full_name)) { 547 + /* expensive full path name compare */ 548 + fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np); 549 + fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np); 550 + name_match = !strcmp(fn_1, fn_2); 551 + kfree(fn_1); 552 + kfree(fn_2); 553 + if (name_match) { 554 + pr_err("ERROR: multiple overlay fragments add and/or delete node %pOF\n", 555 + ce_1->np); 556 + return -EINVAL; 557 + } 558 + } 559 + } 560 + } 561 + } 562 + } 563 + 564 + return 0; 565 + } 566 + 567 + /** 512 568 * build_changeset() - populate overlay changeset in @ovcs from @ovcs->fragments 513 569 * @ovcs: Overlay changeset 514 570 * ··· 611 571 } 612 572 } 613 573 614 - return 0; 574 + return check_changeset_dup_add_node(ovcs); 615 575 } 616 576 617 577 /*