Skip to content

Commit 2fe0e87

Browse files
committed
of: overlay: check prevents multiple fragments touching same property
Add test case of two fragments updating the same property. After adding the test case, the system hangs at end of boot, after after slub stack dumps from kfree() in crypto modprobe code. Multiple overlay fragments adding, modifying, or deleting the same property is not supported. Add check to detect the attempt and fail the overlay apply. Before this patch, the first fragment error would terminate processing. Allow fragment checking to proceed and report all of the fragment errors before terminating the overlay apply. This is not a hot path, thus not a performance issue (the error is not transient and requires fixing the overlay before attempting to apply it again). After applying this patch, the devicetree unittest messages will include: OF: overlay: ERROR: multiple fragments add, update, and/or delete property /testcase-data-2/substation@100/motor-1/rpm_avail ... ### dt-test ### end of unittest - 212 passed, 0 failed The check to detect two fragments updating the same property is folded into the patch that created the test case to maintain bisectability. Tested-by: Alan Tull <atull@kernel.org> Signed-off-by: Frank Rowand <frank.rowand@sony.com>
1 parent c168263 commit 2fe0e87

File tree

5 files changed

+112
-37
lines changed

5 files changed

+112
-37
lines changed

drivers/of/overlay.c

Lines changed: 81 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -508,52 +508,96 @@ static int build_changeset_symbols_node(struct overlay_changeset *ovcs,
508508
return 0;
509509
}
510510

511+
static int find_dup_cset_node_entry(struct overlay_changeset *ovcs,
512+
struct of_changeset_entry *ce_1)
513+
{
514+
struct of_changeset_entry *ce_2;
515+
char *fn_1, *fn_2;
516+
int node_path_match;
517+
518+
if (ce_1->action != OF_RECONFIG_ATTACH_NODE &&
519+
ce_1->action != OF_RECONFIG_DETACH_NODE)
520+
return 0;
521+
522+
ce_2 = ce_1;
523+
list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) {
524+
if ((ce_2->action != OF_RECONFIG_ATTACH_NODE &&
525+
ce_2->action != OF_RECONFIG_DETACH_NODE) ||
526+
of_node_cmp(ce_1->np->full_name, ce_2->np->full_name))
527+
continue;
528+
529+
fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np);
530+
fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np);
531+
node_path_match = !strcmp(fn_1, fn_2);
532+
kfree(fn_1);
533+
kfree(fn_2);
534+
if (node_path_match) {
535+
pr_err("ERROR: multiple fragments add and/or delete node %pOF\n",
536+
ce_1->np);
537+
return -EINVAL;
538+
}
539+
}
540+
541+
return 0;
542+
}
543+
544+
static int find_dup_cset_prop(struct overlay_changeset *ovcs,
545+
struct of_changeset_entry *ce_1)
546+
{
547+
struct of_changeset_entry *ce_2;
548+
char *fn_1, *fn_2;
549+
int node_path_match;
550+
551+
if (ce_1->action != OF_RECONFIG_ADD_PROPERTY &&
552+
ce_1->action != OF_RECONFIG_REMOVE_PROPERTY &&
553+
ce_1->action != OF_RECONFIG_UPDATE_PROPERTY)
554+
return 0;
555+
556+
ce_2 = ce_1;
557+
list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) {
558+
if ((ce_2->action != OF_RECONFIG_ADD_PROPERTY &&
559+
ce_2->action != OF_RECONFIG_REMOVE_PROPERTY &&
560+
ce_2->action != OF_RECONFIG_UPDATE_PROPERTY) ||
561+
of_node_cmp(ce_1->np->full_name, ce_2->np->full_name))
562+
continue;
563+
564+
fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np);
565+
fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np);
566+
node_path_match = !strcmp(fn_1, fn_2);
567+
kfree(fn_1);
568+
kfree(fn_2);
569+
if (node_path_match &&
570+
!of_prop_cmp(ce_1->prop->name, ce_2->prop->name)) {
571+
pr_err("ERROR: multiple fragments add, update, and/or delete property %pOF/%s\n",
572+
ce_1->np, ce_1->prop->name);
573+
return -EINVAL;
574+
}
575+
}
576+
577+
return 0;
578+
}
579+
511580
/**
512-
* check_changeset_dup_add_node() - changeset validation: duplicate add node
581+
* changeset_dup_entry_check() - check for duplicate entries
513582
* @ovcs: Overlay changeset
514583
*
515-
* Check changeset @ovcs->cset for multiple add node entries for the same
516-
* node.
584+
* Check changeset @ovcs->cset for multiple {add or delete} node entries for
585+
* the same node or duplicate {add, delete, or update} properties entries
586+
* for the same property.
517587
*
518-
* Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
519-
* invalid overlay in @ovcs->fragments[].
588+
* Returns 0 on success, or -EINVAL if duplicate changeset entry found.
520589
*/
521-
static int check_changeset_dup_add_node(struct overlay_changeset *ovcs)
590+
static int changeset_dup_entry_check(struct overlay_changeset *ovcs)
522591
{
523-
struct of_changeset_entry *ce_1, *ce_2;
524-
char *fn_1, *fn_2;
525-
int name_match;
592+
struct of_changeset_entry *ce_1;
593+
int dup_entry = 0;
526594

527595
list_for_each_entry(ce_1, &ovcs->cset.entries, node) {
528-
529-
if (ce_1->action == OF_RECONFIG_ATTACH_NODE ||
530-
ce_1->action == OF_RECONFIG_DETACH_NODE) {
531-
532-
ce_2 = ce_1;
533-
list_for_each_entry_continue(ce_2, &ovcs->cset.entries, node) {
534-
if (ce_2->action == OF_RECONFIG_ATTACH_NODE ||
535-
ce_2->action == OF_RECONFIG_DETACH_NODE) {
536-
/* inexpensive name compare */
537-
if (!of_node_cmp(ce_1->np->full_name,
538-
ce_2->np->full_name)) {
539-
/* expensive full path name compare */
540-
fn_1 = kasprintf(GFP_KERNEL, "%pOF", ce_1->np);
541-
fn_2 = kasprintf(GFP_KERNEL, "%pOF", ce_2->np);
542-
name_match = !strcmp(fn_1, fn_2);
543-
kfree(fn_1);
544-
kfree(fn_2);
545-
if (name_match) {
546-
pr_err("ERROR: multiple overlay fragments add and/or delete node %pOF\n",
547-
ce_1->np);
548-
return -EINVAL;
549-
}
550-
}
551-
}
552-
}
553-
}
596+
dup_entry |= find_dup_cset_node_entry(ovcs, ce_1);
597+
dup_entry |= find_dup_cset_prop(ovcs, ce_1);
554598
}
555599

556-
return 0;
600+
return dup_entry ? -EINVAL : 0;
557601
}
558602

559603
/**
@@ -611,7 +655,7 @@ static int build_changeset(struct overlay_changeset *ovcs)
611655
}
612656
}
613657

614-
return check_changeset_dup_add_node(ovcs);
658+
return changeset_dup_entry_check(ovcs);
615659
}
616660

617661
/*

drivers/of/unittest-data/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ obj-$(CONFIG_OF_OVERLAY) += overlay.dtb.o \
1818
overlay_13.dtb.o \
1919
overlay_15.dtb.o \
2020
overlay_bad_add_dup_node.dtb.o \
21+
overlay_bad_add_dup_prop.dtb.o \
2122
overlay_bad_phandle.dtb.o \
2223
overlay_bad_symbol.dtb.o \
2324
overlay_base.dtb.o
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/dts-v1/;
3+
/plugin/;
4+
5+
/*
6+
* &electric_1/motor-1 and &spin_ctrl_1 are the same node:
7+
* /testcase-data-2/substation@100/motor-1
8+
*
9+
* Thus the property "rpm_avail" in each fragment will
10+
* result in an attempt to update the same property twice.
11+
* This will result in an error and the overlay apply
12+
* will fail.
13+
*/
14+
15+
&electric_1 {
16+
17+
motor-1 {
18+
rpm_avail = < 100 >;
19+
};
20+
};
21+
22+
&spin_ctrl_1 {
23+
rpm_avail = < 100 200 >;
24+
};

drivers/of/unittest-data/overlay_base.dts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
spin_ctrl_1: motor-1 {
3131
compatible = "ot,ferris-wheel-motor";
3232
spin = "clockwise";
33+
rpm_avail = < 50 >;
3334
};
3435

3536
spin_ctrl_2: motor-8 {

drivers/of/unittest.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2162,6 +2162,7 @@ OVERLAY_INFO_EXTERN(overlay_12);
21622162
OVERLAY_INFO_EXTERN(overlay_13);
21632163
OVERLAY_INFO_EXTERN(overlay_15);
21642164
OVERLAY_INFO_EXTERN(overlay_bad_add_dup_node);
2165+
OVERLAY_INFO_EXTERN(overlay_bad_add_dup_prop);
21652166
OVERLAY_INFO_EXTERN(overlay_bad_phandle);
21662167
OVERLAY_INFO_EXTERN(overlay_bad_symbol);
21672168

@@ -2185,6 +2186,7 @@ static struct overlay_info overlays[] = {
21852186
OVERLAY_INFO(overlay_13, 0),
21862187
OVERLAY_INFO(overlay_15, 0),
21872188
OVERLAY_INFO(overlay_bad_add_dup_node, -EINVAL),
2189+
OVERLAY_INFO(overlay_bad_add_dup_prop, -EINVAL),
21882190
OVERLAY_INFO(overlay_bad_phandle, -EINVAL),
21892191
OVERLAY_INFO(overlay_bad_symbol, -EINVAL),
21902192
{}
@@ -2435,6 +2437,9 @@ static __init void of_unittest_overlay_high_level(void)
24352437
unittest(overlay_data_apply("overlay_bad_add_dup_node", NULL),
24362438
"Adding overlay 'overlay_bad_add_dup_node' failed\n");
24372439

2440+
unittest(overlay_data_apply("overlay_bad_add_dup_prop", NULL),
2441+
"Adding overlay 'overlay_bad_add_dup_prop' failed\n");
2442+
24382443
unittest(overlay_data_apply("overlay_bad_phandle", NULL),
24392444
"Adding overlay 'overlay_bad_phandle' failed\n");
24402445

0 commit comments

Comments
 (0)