Skip to content

Commit a4771f9

Browse files
committed
netfilter: nf_tables: add support to destroy operation
jira VULN-430 cve-pre CVE-2023-4244 commit-author Fernando Fernandez Mancera <[email protected]> commit f80a612 Introduce NFT_MSG_DESTROY* message type. The destroy operation performs a delete operation but ignoring the ENOENT errors. This is useful for the transaction semantics, where failing to delete an object which does not exist results in aborting the transaction. This new command allows the transaction to proceed in case the object does not exist. Signed-off-by: Fernando Fernandez Mancera <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]> Signed-off-by: Florian Westphal <[email protected]> (cherry picked from commit f80a612) Signed-off-by: Marcin Wcisło <[email protected]>
1 parent 8a0661f commit a4771f9

File tree

2 files changed

+117
-8
lines changed

2 files changed

+117
-8
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,13 @@ enum nft_verdicts {
9898
* @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
9999
* @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
100100
* @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions (enum nft_obj_attributes)
101+
* @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes)
102+
* @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes)
103+
* @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes)
104+
* @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes)
105+
* @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes)
106+
* @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes)
107+
* @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes)
101108
*/
102109
enum nf_tables_msg_types {
103110
NFT_MSG_NEWTABLE,
@@ -126,6 +133,13 @@ enum nf_tables_msg_types {
126133
NFT_MSG_GETFLOWTABLE,
127134
NFT_MSG_DELFLOWTABLE,
128135
NFT_MSG_GETRULE_RESET,
136+
NFT_MSG_DESTROYTABLE,
137+
NFT_MSG_DESTROYCHAIN,
138+
NFT_MSG_DESTROYRULE,
139+
NFT_MSG_DESTROYSET,
140+
NFT_MSG_DESTROYSETELEM,
141+
NFT_MSG_DESTROYOBJ,
142+
NFT_MSG_DESTROYFLOWTABLE,
129143
NFT_MSG_MAX,
130144
};
131145

net/netfilter/nf_tables_api.c

Lines changed: 103 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,6 +1413,10 @@ static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
14131413
}
14141414

14151415
if (IS_ERR(table)) {
1416+
if (PTR_ERR(table) == -ENOENT &&
1417+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYTABLE)
1418+
return 0;
1419+
14161420
NL_SET_BAD_ATTR(extack, attr);
14171421
return PTR_ERR(table);
14181422
}
@@ -2640,6 +2644,10 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
26402644
chain = nft_chain_lookup(net, table, attr, genmask);
26412645
}
26422646
if (IS_ERR(chain)) {
2647+
if (PTR_ERR(chain) == -ENOENT &&
2648+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYCHAIN)
2649+
return 0;
2650+
26432651
NL_SET_BAD_ATTR(extack, attr);
26442652
return PTR_ERR(chain);
26452653
}
@@ -3736,6 +3744,10 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
37363744
chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
37373745
genmask);
37383746
if (IS_ERR(chain)) {
3747+
if (PTR_ERR(rule) == -ENOENT &&
3748+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
3749+
return 0;
3750+
37393751
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
37403752
return PTR_ERR(chain);
37413753
}
@@ -3749,6 +3761,10 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
37493761
if (nla[NFTA_RULE_HANDLE]) {
37503762
rule = nft_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
37513763
if (IS_ERR(rule)) {
3764+
if (PTR_ERR(rule) == -ENOENT &&
3765+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
3766+
return 0;
3767+
37523768
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_HANDLE]);
37533769
return PTR_ERR(rule);
37543770
}
@@ -4824,6 +4840,10 @@ static int nf_tables_delset(struct sk_buff *skb, const struct nfnl_info *info,
48244840
}
48254841

48264842
if (IS_ERR(set)) {
4843+
if (PTR_ERR(set) == -ENOENT &&
4844+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSET)
4845+
return 0;
4846+
48274847
NL_SET_BAD_ATTR(extack, attr);
48284848
return PTR_ERR(set);
48294849
}
@@ -6678,6 +6698,10 @@ static int nf_tables_delsetelem(struct sk_buff *skb,
66786698

66796699
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
66806700
err = nft_del_setelem(&ctx, set, attr);
6701+
if (err == -ENOENT &&
6702+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM)
6703+
continue;
6704+
66816705
if (err < 0) {
66826706
NL_SET_BAD_ATTR(extack, attr);
66836707
break;
@@ -7322,6 +7346,10 @@ static int nf_tables_delobj(struct sk_buff *skb, const struct nfnl_info *info,
73227346
}
73237347

73247348
if (IS_ERR(obj)) {
7349+
if (PTR_ERR(obj) == -ENOENT &&
7350+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYOBJ)
7351+
return 0;
7352+
73257353
NL_SET_BAD_ATTR(extack, attr);
73267354
return PTR_ERR(obj);
73277355
}
@@ -7953,6 +7981,10 @@ static int nf_tables_delflowtable(struct sk_buff *skb,
79537981
}
79547982

79557983
if (IS_ERR(flowtable)) {
7984+
if (PTR_ERR(flowtable) == -ENOENT &&
7985+
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYFLOWTABLE)
7986+
return 0;
7987+
79567988
NL_SET_BAD_ATTR(extack, attr);
79577989
return PTR_ERR(flowtable);
79587990
}
@@ -8362,6 +8394,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
83628394
.attr_count = NFTA_TABLE_MAX,
83638395
.policy = nft_table_policy,
83648396
},
8397+
[NFT_MSG_DESTROYTABLE] = {
8398+
.call = nf_tables_deltable,
8399+
.type = NFNL_CB_BATCH,
8400+
.attr_count = NFTA_TABLE_MAX,
8401+
.policy = nft_table_policy,
8402+
},
83658403
[NFT_MSG_NEWCHAIN] = {
83668404
.call = nf_tables_newchain,
83678405
.type = NFNL_CB_BATCH,
@@ -8380,6 +8418,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
83808418
.attr_count = NFTA_CHAIN_MAX,
83818419
.policy = nft_chain_policy,
83828420
},
8421+
[NFT_MSG_DESTROYCHAIN] = {
8422+
.call = nf_tables_delchain,
8423+
.type = NFNL_CB_BATCH,
8424+
.attr_count = NFTA_CHAIN_MAX,
8425+
.policy = nft_chain_policy,
8426+
},
83838427
[NFT_MSG_NEWRULE] = {
83848428
.call = nf_tables_newrule,
83858429
.type = NFNL_CB_BATCH,
@@ -8404,6 +8448,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84048448
.attr_count = NFTA_RULE_MAX,
84058449
.policy = nft_rule_policy,
84068450
},
8451+
[NFT_MSG_DESTROYRULE] = {
8452+
.call = nf_tables_delrule,
8453+
.type = NFNL_CB_BATCH,
8454+
.attr_count = NFTA_RULE_MAX,
8455+
.policy = nft_rule_policy,
8456+
},
84078457
[NFT_MSG_NEWSET] = {
84088458
.call = nf_tables_newset,
84098459
.type = NFNL_CB_BATCH,
@@ -8422,6 +8472,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84228472
.attr_count = NFTA_SET_MAX,
84238473
.policy = nft_set_policy,
84248474
},
8475+
[NFT_MSG_DESTROYSET] = {
8476+
.call = nf_tables_delset,
8477+
.type = NFNL_CB_BATCH,
8478+
.attr_count = NFTA_SET_MAX,
8479+
.policy = nft_set_policy,
8480+
},
84258481
[NFT_MSG_NEWSETELEM] = {
84268482
.call = nf_tables_newsetelem,
84278483
.type = NFNL_CB_BATCH,
@@ -8440,6 +8496,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84408496
.attr_count = NFTA_SET_ELEM_LIST_MAX,
84418497
.policy = nft_set_elem_list_policy,
84428498
},
8499+
[NFT_MSG_DESTROYSETELEM] = {
8500+
.call = nf_tables_delsetelem,
8501+
.type = NFNL_CB_BATCH,
8502+
.attr_count = NFTA_SET_ELEM_LIST_MAX,
8503+
.policy = nft_set_elem_list_policy,
8504+
},
84438505
[NFT_MSG_GETGEN] = {
84448506
.call = nf_tables_getgen,
84458507
.type = NFNL_CB_RCU,
@@ -8462,6 +8524,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84628524
.attr_count = NFTA_OBJ_MAX,
84638525
.policy = nft_obj_policy,
84648526
},
8527+
[NFT_MSG_DESTROYOBJ] = {
8528+
.call = nf_tables_delobj,
8529+
.type = NFNL_CB_BATCH,
8530+
.attr_count = NFTA_OBJ_MAX,
8531+
.policy = nft_obj_policy,
8532+
},
84658533
[NFT_MSG_GETOBJ_RESET] = {
84668534
.call = nf_tables_getobj,
84678535
.type = NFNL_CB_RCU,
@@ -8486,6 +8554,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84868554
.attr_count = NFTA_FLOWTABLE_MAX,
84878555
.policy = nft_flowtable_policy,
84888556
},
8557+
[NFT_MSG_DESTROYFLOWTABLE] = {
8558+
.call = nf_tables_delflowtable,
8559+
.type = NFNL_CB_BATCH,
8560+
.attr_count = NFTA_FLOWTABLE_MAX,
8561+
.policy = nft_flowtable_policy,
8562+
},
84898563
};
84908564

84918565
static int nf_tables_validate(struct net *net)
@@ -8581,30 +8655,37 @@ static void nft_commit_release(struct nft_trans *trans)
85818655
{
85828656
switch (trans->msg_type) {
85838657
case NFT_MSG_DELTABLE:
8658+
case NFT_MSG_DESTROYTABLE:
85848659
nf_tables_table_destroy(&trans->ctx);
85858660
break;
85868661
case NFT_MSG_NEWCHAIN:
85878662
free_percpu(nft_trans_chain_stats(trans));
85888663
kfree(nft_trans_chain_name(trans));
85898664
break;
85908665
case NFT_MSG_DELCHAIN:
8666+
case NFT_MSG_DESTROYCHAIN:
85918667
nf_tables_chain_destroy(&trans->ctx);
85928668
break;
85938669
case NFT_MSG_DELRULE:
8670+
case NFT_MSG_DESTROYRULE:
85948671
nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
85958672
break;
85968673
case NFT_MSG_DELSET:
8674+
case NFT_MSG_DESTROYSET:
85978675
nft_set_destroy(&trans->ctx, nft_trans_set(trans));
85988676
break;
85998677
case NFT_MSG_DELSETELEM:
8678+
case NFT_MSG_DESTROYSETELEM:
86008679
nf_tables_set_elem_destroy(&trans->ctx,
86018680
nft_trans_elem_set(trans),
86028681
nft_trans_elem(trans).priv);
86038682
break;
86048683
case NFT_MSG_DELOBJ:
8684+
case NFT_MSG_DESTROYOBJ:
86058685
nft_obj_destroy(&trans->ctx, nft_trans_obj(trans));
86068686
break;
86078687
case NFT_MSG_DELFLOWTABLE:
8688+
case NFT_MSG_DESTROYFLOWTABLE:
86088689
if (nft_trans_flowtable_update(trans))
86098690
nft_flowtable_hooks_destroy(&nft_trans_flowtable_hooks(trans));
86108691
else
@@ -9007,8 +9088,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90079088
nft_trans_destroy(trans);
90089089
break;
90099090
case NFT_MSG_DELTABLE:
9091+
case NFT_MSG_DESTROYTABLE:
90109092
list_del_rcu(&trans->ctx.table->list);
9011-
nf_tables_table_notify(&trans->ctx, NFT_MSG_DELTABLE);
9093+
nf_tables_table_notify(&trans->ctx, trans->msg_type);
90129094
break;
90139095
case NFT_MSG_NEWCHAIN:
90149096
if (nft_trans_chain_update(trans)) {
@@ -9023,8 +9105,9 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90239105
}
90249106
break;
90259107
case NFT_MSG_DELCHAIN:
9108+
case NFT_MSG_DESTROYCHAIN:
90269109
nft_chain_del(trans->ctx.chain);
9027-
nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
9110+
nf_tables_chain_notify(&trans->ctx, trans->msg_type);
90289111
nf_tables_unregister_hook(trans->ctx.net,
90299112
trans->ctx.table,
90309113
trans->ctx.chain);
@@ -9040,10 +9123,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90409123
nft_trans_destroy(trans);
90419124
break;
90429125
case NFT_MSG_DELRULE:
9126+
case NFT_MSG_DESTROYRULE:
90439127
list_del_rcu(&nft_trans_rule(trans)->list);
90449128
nf_tables_rule_notify(&trans->ctx,
90459129
nft_trans_rule(trans),
9046-
NFT_MSG_DELRULE);
9130+
trans->msg_type);
90479131
nft_rule_expr_deactivate(&trans->ctx,
90489132
nft_trans_rule(trans),
90499133
NFT_TRANS_COMMIT);
@@ -9071,9 +9155,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90719155
nft_trans_destroy(trans);
90729156
break;
90739157
case NFT_MSG_DELSET:
9158+
case NFT_MSG_DESTROYSET:
90749159
list_del_rcu(&nft_trans_set(trans)->list);
90759160
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
9076-
NFT_MSG_DELSET, GFP_KERNEL);
9161+
trans->msg_type, GFP_KERNEL);
90779162
break;
90789163
case NFT_MSG_NEWSETELEM:
90799164
te = (struct nft_trans_elem *)trans->data;
@@ -9085,11 +9170,12 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90859170
nft_trans_destroy(trans);
90869171
break;
90879172
case NFT_MSG_DELSETELEM:
9173+
case NFT_MSG_DESTROYSETELEM:
90889174
te = (struct nft_trans_elem *)trans->data;
90899175

90909176
nf_tables_setelem_notify(&trans->ctx, te->set,
90919177
&te->elem,
9092-
NFT_MSG_DELSETELEM);
9178+
trans->msg_type);
90939179
nft_setelem_remove(net, te->set, &te->elem);
90949180
if (!nft_setelem_is_catchall(te->set, &te->elem)) {
90959181
atomic_dec(&te->set->nelems);
@@ -9111,9 +9197,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
91119197
}
91129198
break;
91139199
case NFT_MSG_DELOBJ:
9200+
case NFT_MSG_DESTROYOBJ:
91149201
nft_obj_del(nft_trans_obj(trans));
91159202
nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans),
9116-
NFT_MSG_DELOBJ);
9203+
trans->msg_type);
91179204
break;
91189205
case NFT_MSG_NEWFLOWTABLE:
91199206
if (nft_trans_flowtable_update(trans)) {
@@ -9135,19 +9222,20 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
91359222
nft_trans_destroy(trans);
91369223
break;
91379224
case NFT_MSG_DELFLOWTABLE:
9225+
case NFT_MSG_DESTROYFLOWTABLE:
91389226
if (nft_trans_flowtable_update(trans)) {
91399227
nf_tables_flowtable_notify(&trans->ctx,
91409228
nft_trans_flowtable(trans),
91419229
&nft_trans_flowtable_hooks(trans),
9142-
NFT_MSG_DELFLOWTABLE);
9230+
trans->msg_type);
91439231
nft_unregister_flowtable_net_hooks(net,
91449232
&nft_trans_flowtable_hooks(trans));
91459233
} else {
91469234
list_del_rcu(&nft_trans_flowtable(trans)->list);
91479235
nf_tables_flowtable_notify(&trans->ctx,
91489236
nft_trans_flowtable(trans),
91499237
&nft_trans_flowtable(trans)->hook_list,
9150-
NFT_MSG_DELFLOWTABLE);
9238+
trans->msg_type);
91519239
nft_unregister_flowtable_net_hooks(net,
91529240
&nft_trans_flowtable(trans)->hook_list);
91539241
}
@@ -9243,6 +9331,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
92439331
}
92449332
break;
92459333
case NFT_MSG_DELTABLE:
9334+
case NFT_MSG_DESTROYTABLE:
92469335
nft_clear(trans->ctx.net, trans->ctx.table);
92479336
nft_trans_destroy(trans);
92489337
break;
@@ -9264,6 +9353,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
92649353
}
92659354
break;
92669355
case NFT_MSG_DELCHAIN:
9356+
case NFT_MSG_DESTROYCHAIN:
92679357
trans->ctx.table->use++;
92689358
nft_clear(trans->ctx.net, trans->ctx.chain);
92699359
nft_trans_destroy(trans);
@@ -9282,6 +9372,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
92829372
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
92839373
break;
92849374
case NFT_MSG_DELRULE:
9375+
case NFT_MSG_DESTROYRULE:
92859376
trans->ctx.chain->use++;
92869377
nft_clear(trans->ctx.net, nft_trans_rule(trans));
92879378
nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
@@ -9303,6 +9394,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
93039394
list_del_rcu(&nft_trans_set(trans)->list);
93049395
break;
93059396
case NFT_MSG_DELSET:
9397+
case NFT_MSG_DESTROYSET:
93069398
trans->ctx.table->use++;
93079399
nft_clear(trans->ctx.net, nft_trans_set(trans));
93089400
nft_trans_destroy(trans);
@@ -9318,6 +9410,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
93189410
atomic_dec(&te->set->nelems);
93199411
break;
93209412
case NFT_MSG_DELSETELEM:
9413+
case NFT_MSG_DESTROYSETELEM:
93219414
te = (struct nft_trans_elem *)trans->data;
93229415

93239416
nft_setelem_data_activate(net, te->set, &te->elem);
@@ -9337,6 +9430,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
93379430
}
93389431
break;
93399432
case NFT_MSG_DELOBJ:
9433+
case NFT_MSG_DESTROYOBJ:
93409434
trans->ctx.table->use++;
93419435
nft_clear(trans->ctx.net, nft_trans_obj(trans));
93429436
nft_trans_destroy(trans);
@@ -9353,6 +9447,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
93539447
}
93549448
break;
93559449
case NFT_MSG_DELFLOWTABLE:
9450+
case NFT_MSG_DESTROYFLOWTABLE:
93569451
if (nft_trans_flowtable_update(trans)) {
93579452
list_splice(&nft_trans_flowtable_hooks(trans),
93589453
&nft_trans_flowtable(trans)->hook_list);

0 commit comments

Comments
 (0)