Skip to content

Commit cc8e58f

Browse files
congwangkuba-moo
authored andcommitted
act_ife: load meta modules before tcf_idr_check_alloc()
The following deadlock scenario is triggered by syzbot: Thread A: Thread B: tcf_idr_check_alloc() ... populate_metalist() rtnl_unlock() rtnl_lock() ... request_module() tcf_idr_check_alloc() rtnl_lock() At this point, thread A is waiting for thread B to release RTNL lock, while thread B is waiting for thread A to commit the IDR change with tcf_idr_insert() later. Break this deadlock situation by preloading ife modules earlier, before tcf_idr_check_alloc(), this is fine because we only need to load modules we need potentially. Reported-and-tested-by: [email protected] Fixes: 0190c1d ("net: sched: atomically check-allocate action") Cc: Jamal Hadi Salim <[email protected]> Cc: Vlad Buslov <[email protected]> Cc: Jiri Pirko <[email protected]> Signed-off-by: Cong Wang <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent c2b9478 commit cc8e58f

File tree

1 file changed

+34
-10
lines changed

1 file changed

+34
-10
lines changed

net/sched/act_ife.c

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,25 @@ static void tcf_ife_cleanup(struct tc_action *a)
436436
kfree_rcu(p, rcu);
437437
}
438438

439+
static int load_metalist(struct nlattr **tb, bool rtnl_held)
440+
{
441+
int i;
442+
443+
for (i = 1; i < max_metacnt; i++) {
444+
if (tb[i]) {
445+
void *val = nla_data(tb[i]);
446+
int len = nla_len(tb[i]);
447+
int rc;
448+
449+
rc = load_metaops_and_vet(i, val, len, rtnl_held);
450+
if (rc != 0)
451+
return rc;
452+
}
453+
}
454+
455+
return 0;
456+
}
457+
439458
static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
440459
bool exists, bool rtnl_held)
441460
{
@@ -449,10 +468,6 @@ static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
449468
val = nla_data(tb[i]);
450469
len = nla_len(tb[i]);
451470

452-
rc = load_metaops_and_vet(i, val, len, rtnl_held);
453-
if (rc != 0)
454-
return rc;
455-
456471
rc = add_metainfo(ife, i, val, len, exists);
457472
if (rc)
458473
return rc;
@@ -509,6 +524,21 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
509524
if (!p)
510525
return -ENOMEM;
511526

527+
if (tb[TCA_IFE_METALST]) {
528+
err = nla_parse_nested_deprecated(tb2, IFE_META_MAX,
529+
tb[TCA_IFE_METALST], NULL,
530+
NULL);
531+
if (err) {
532+
kfree(p);
533+
return err;
534+
}
535+
err = load_metalist(tb2, rtnl_held);
536+
if (err) {
537+
kfree(p);
538+
return err;
539+
}
540+
}
541+
512542
index = parm->index;
513543
err = tcf_idr_check_alloc(tn, &index, a, bind);
514544
if (err < 0) {
@@ -570,15 +600,9 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
570600
}
571601

572602
if (tb[TCA_IFE_METALST]) {
573-
err = nla_parse_nested_deprecated(tb2, IFE_META_MAX,
574-
tb[TCA_IFE_METALST], NULL,
575-
NULL);
576-
if (err)
577-
goto metadata_parse_err;
578603
err = populate_metalist(ife, tb2, exists, rtnl_held);
579604
if (err)
580605
goto metadata_parse_err;
581-
582606
} else {
583607
/* if no passed metadata allow list or passed allow-all
584608
* then here we process by adding as many supported metadatum

0 commit comments

Comments
 (0)