Skip to content

Commit cfd9694

Browse files
committed
Merge: netfilter: nf_tables: netlink api rebase on net.git
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/3028 JIRA: https://issues.redhat.com/browse/RHEL-1720 JIRA: https://issues.redhat.com/browse/RHEL-1721 Upstream Status: all upstream except top most patch CVE: CVE-2023-4244 Omitted-fix: ebd032f ("netfilter: nf_tables: do not remove elements if set backend implements .abort") This is a major rebase to get the set element garbage collection into RHEL. This rework was necessary to address race conditions between the netlink control plane, the datapath (set element insertion/removal via nft_dynset expression from the nftables ruleset) and the asynchronous garbage collection to remove timed-out elements. With this rework, all set element removals happen under protection of the transaction mutex, similar to how netlink control plane add/removal is done. Removal from async worker queues the removal requests via work queue, work queue then can serialize this via mutex. The topmost patch resolves a problem that occurs with the nftables version shipped with RHEL, see description for details. The omitted fix has been reverted uptream. Signed-off-by: Florian Westphal <fwestpha@redhat.com> Approved-by: Phil Sutter <psutter@redhat.com> Approved-by: Eric Garver <egarver@redhat.com> Signed-off-by: Scott Weaver <scweaver@redhat.com>
2 parents bf9e08c + 45aad05 commit cfd9694

File tree

15 files changed

+1554
-694
lines changed

15 files changed

+1554
-694
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 119 additions & 97 deletions
Large diffs are not rendered by default.

net/netfilter/nf_tables_api.c

Lines changed: 852 additions & 227 deletions
Large diffs are not rendered by default.

net/netfilter/nft_bitwise.c

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,16 @@ static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
9393
static int nft_bitwise_init_bool(struct nft_bitwise *priv,
9494
const struct nlattr *const tb[])
9595
{
96-
struct nft_data_desc mask, xor;
96+
struct nft_data_desc mask = {
97+
.type = NFT_DATA_VALUE,
98+
.size = sizeof(priv->mask),
99+
.len = priv->len,
100+
};
101+
struct nft_data_desc xor = {
102+
.type = NFT_DATA_VALUE,
103+
.size = sizeof(priv->xor),
104+
.len = priv->len,
105+
};
97106
int err;
98107

99108
if (tb[NFTA_BITWISE_DATA])
@@ -103,36 +112,30 @@ static int nft_bitwise_init_bool(struct nft_bitwise *priv,
103112
!tb[NFTA_BITWISE_XOR])
104113
return -EINVAL;
105114

106-
err = nft_data_init(NULL, &priv->mask, sizeof(priv->mask), &mask,
107-
tb[NFTA_BITWISE_MASK]);
115+
err = nft_data_init(NULL, &priv->mask, &mask, tb[NFTA_BITWISE_MASK]);
108116
if (err < 0)
109117
return err;
110-
if (mask.type != NFT_DATA_VALUE || mask.len != priv->len) {
111-
err = -EINVAL;
112-
goto err1;
113-
}
114118

115-
err = nft_data_init(NULL, &priv->xor, sizeof(priv->xor), &xor,
116-
tb[NFTA_BITWISE_XOR]);
119+
err = nft_data_init(NULL, &priv->xor, &xor, tb[NFTA_BITWISE_XOR]);
117120
if (err < 0)
118-
goto err1;
119-
if (xor.type != NFT_DATA_VALUE || xor.len != priv->len) {
120-
err = -EINVAL;
121-
goto err2;
122-
}
121+
goto err_xor_err;
123122

124123
return 0;
125-
err2:
126-
nft_data_release(&priv->xor, xor.type);
127-
err1:
124+
125+
err_xor_err:
128126
nft_data_release(&priv->mask, mask.type);
127+
129128
return err;
130129
}
131130

132131
static int nft_bitwise_init_shift(struct nft_bitwise *priv,
133132
const struct nlattr *const tb[])
134133
{
135-
struct nft_data_desc d;
134+
struct nft_data_desc desc = {
135+
.type = NFT_DATA_VALUE,
136+
.size = sizeof(priv->data),
137+
.len = sizeof(u32),
138+
};
136139
int err;
137140

138141
if (tb[NFTA_BITWISE_MASK] ||
@@ -142,13 +145,12 @@ static int nft_bitwise_init_shift(struct nft_bitwise *priv,
142145
if (!tb[NFTA_BITWISE_DATA])
143146
return -EINVAL;
144147

145-
err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &d,
146-
tb[NFTA_BITWISE_DATA]);
148+
err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_BITWISE_DATA]);
147149
if (err < 0)
148150
return err;
149-
if (d.type != NFT_DATA_VALUE || d.len != sizeof(u32) ||
150-
priv->data.data[0] >= BITS_PER_TYPE(u32)) {
151-
nft_data_release(&priv->data, d.type);
151+
152+
if (priv->data.data[0] >= BITS_PER_TYPE(u32)) {
153+
nft_data_release(&priv->data, desc.type);
152154
return -EINVAL;
153155
}
154156

@@ -291,22 +293,21 @@ static const struct nft_expr_ops nft_bitwise_ops = {
291293
static int
292294
nft_bitwise_extract_u32_data(const struct nlattr * const tb, u32 *out)
293295
{
294-
struct nft_data_desc desc;
295296
struct nft_data data;
296-
int err = 0;
297+
struct nft_data_desc desc = {
298+
.type = NFT_DATA_VALUE,
299+
.size = sizeof(data),
300+
.len = sizeof(u32),
301+
};
302+
int err;
297303

298-
err = nft_data_init(NULL, &data, sizeof(data), &desc, tb);
304+
err = nft_data_init(NULL, &data, &desc, tb);
299305
if (err < 0)
300306
return err;
301307

302-
if (desc.type != NFT_DATA_VALUE || desc.len != sizeof(u32)) {
303-
err = -EINVAL;
304-
goto err;
305-
}
306308
*out = data.data[0];
307-
err:
308-
nft_data_release(&data, desc.type);
309-
return err;
309+
310+
return 0;
310311
}
311312

312313
static int nft_bitwise_fast_init(const struct nft_ctx *ctx,

net/netfilter/nft_cmp.c

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,16 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
7373
const struct nlattr * const tb[])
7474
{
7575
struct nft_cmp_expr *priv = nft_expr_priv(expr);
76-
struct nft_data_desc desc;
76+
struct nft_data_desc desc = {
77+
.type = NFT_DATA_VALUE,
78+
.size = sizeof(priv->data),
79+
};
7780
int err;
7881

79-
err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc,
80-
tb[NFTA_CMP_DATA]);
82+
err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
8183
if (err < 0)
8284
return err;
8385

84-
if (desc.type != NFT_DATA_VALUE) {
85-
err = -EINVAL;
86-
nft_data_release(&priv->data, desc.type);
87-
return err;
88-
}
89-
9086
err = nft_parse_register_load(tb[NFTA_CMP_SREG], &priv->sreg, desc.len);
9187
if (err < 0)
9288
return err;
@@ -202,12 +198,14 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
202198
const struct nlattr * const tb[])
203199
{
204200
struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
205-
struct nft_data_desc desc;
206201
struct nft_data data;
202+
struct nft_data_desc desc = {
203+
.type = NFT_DATA_VALUE,
204+
.size = sizeof(data),
205+
};
207206
int err;
208207

209-
err = nft_data_init(NULL, &data, sizeof(data), &desc,
210-
tb[NFTA_CMP_DATA]);
208+
err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
211209
if (err < 0)
212210
return err;
213211

@@ -277,8 +275,11 @@ const struct nft_expr_ops nft_cmp_fast_ops = {
277275
static const struct nft_expr_ops *
278276
nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
279277
{
280-
struct nft_data_desc desc;
281278
struct nft_data data;
279+
struct nft_data_desc desc = {
280+
.type = NFT_DATA_VALUE,
281+
.size = sizeof(data),
282+
};
282283
enum nft_cmp_ops op;
283284
int err;
284285

@@ -300,21 +301,14 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
300301
return ERR_PTR(-EINVAL);
301302
}
302303

303-
err = nft_data_init(NULL, &data, sizeof(data), &desc,
304-
tb[NFTA_CMP_DATA]);
304+
err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
305305
if (err < 0)
306306
return ERR_PTR(err);
307307

308-
if (desc.type != NFT_DATA_VALUE)
309-
goto err1;
310-
311308
if (desc.len <= sizeof(u32) && (op == NFT_CMP_EQ || op == NFT_CMP_NEQ))
312309
return &nft_cmp_fast_ops;
313310

314311
return &nft_cmp_ops;
315-
err1:
316-
nft_data_release(&data, desc.type);
317-
return ERR_PTR(-EINVAL);
318312
}
319313

320314
struct nft_expr_type nft_cmp_type __read_mostly = {

net/netfilter/nft_dynset.c

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,34 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
4444
return 0;
4545
}
4646

47-
static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
48-
struct nft_regs *regs)
47+
static struct nft_elem_priv *nft_dynset_new(struct nft_set *set,
48+
const struct nft_expr *expr,
49+
struct nft_regs *regs)
4950
{
5051
const struct nft_dynset *priv = nft_expr_priv(expr);
5152
struct nft_set_ext *ext;
53+
void *elem_priv;
5254
u64 timeout;
53-
void *elem;
5455

5556
if (!atomic_add_unless(&set->nelems, 1, set->size))
5657
return NULL;
5758

5859
timeout = priv->timeout ? : set->timeout;
59-
elem = nft_set_elem_init(set, &priv->tmpl,
60-
&regs->data[priv->sreg_key], NULL,
61-
&regs->data[priv->sreg_data],
62-
timeout, 0, GFP_ATOMIC);
63-
if (elem == NULL)
60+
elem_priv = nft_set_elem_init(set, &priv->tmpl,
61+
&regs->data[priv->sreg_key], NULL,
62+
&regs->data[priv->sreg_data],
63+
timeout, 0, GFP_ATOMIC);
64+
if (IS_ERR(elem_priv))
6465
goto err1;
6566

66-
ext = nft_set_elem_ext(set, elem);
67+
ext = nft_set_elem_ext(set, elem_priv);
6768
if (priv->num_exprs && nft_dynset_expr_setup(priv, ext) < 0)
6869
goto err2;
6970

70-
return elem;
71+
return elem_priv;
7172

7273
err2:
73-
nft_set_elem_destroy(set, elem, false);
74+
nft_set_elem_destroy(set, elem_priv, false);
7475
err1:
7576
if (set->size)
7677
atomic_dec(&set->nelems);
@@ -191,6 +192,9 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
191192
if (IS_ERR(set))
192193
return PTR_ERR(set);
193194

195+
if (set->flags & NFT_SET_OBJECT)
196+
return -EOPNOTSUPP;
197+
194198
if (set->ops->update == NULL)
195199
return -EOPNOTSUPP;
196200

net/netfilter/nft_flow_offload.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,10 @@ static int nft_flow_offload_init(const struct nft_ctx *ctx,
381381
if (IS_ERR(flowtable))
382382
return PTR_ERR(flowtable);
383383

384+
if (!nft_use_inc(&flowtable->use))
385+
return -EMFILE;
386+
384387
priv->flowtable = flowtable;
385-
flowtable->use++;
386388

387389
return nf_ct_netns_get(ctx->net, ctx->family);
388390
}
@@ -401,7 +403,7 @@ static void nft_flow_offload_activate(const struct nft_ctx *ctx,
401403
{
402404
struct nft_flow_offload *priv = nft_expr_priv(expr);
403405

404-
priv->flowtable->use++;
406+
nft_use_inc_restore(&priv->flowtable->use);
405407
}
406408

407409
static void nft_flow_offload_destroy(const struct nft_ctx *ctx,

net/netfilter/nft_immediate.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,36 @@ static const struct nla_policy nft_immediate_policy[NFTA_IMMEDIATE_MAX + 1] = {
2929
[NFTA_IMMEDIATE_DATA] = { .type = NLA_NESTED },
3030
};
3131

32+
static enum nft_data_types nft_reg_to_type(const struct nlattr *nla)
33+
{
34+
enum nft_data_types type;
35+
u8 reg;
36+
37+
reg = ntohl(nla_get_be32(nla));
38+
if (reg == NFT_REG_VERDICT)
39+
type = NFT_DATA_VERDICT;
40+
else
41+
type = NFT_DATA_VALUE;
42+
43+
return type;
44+
}
45+
3246
static int nft_immediate_init(const struct nft_ctx *ctx,
3347
const struct nft_expr *expr,
3448
const struct nlattr * const tb[])
3549
{
3650
struct nft_immediate_expr *priv = nft_expr_priv(expr);
37-
struct nft_data_desc desc;
51+
struct nft_data_desc desc = {
52+
.size = sizeof(priv->data),
53+
};
3854
int err;
3955

4056
if (tb[NFTA_IMMEDIATE_DREG] == NULL ||
4157
tb[NFTA_IMMEDIATE_DATA] == NULL)
4258
return -EINVAL;
4359

44-
err = nft_data_init(ctx, &priv->data, sizeof(priv->data), &desc,
45-
tb[NFTA_IMMEDIATE_DATA]);
60+
desc.type = nft_reg_to_type(tb[NFTA_IMMEDIATE_DREG]);
61+
err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]);
4662
if (err < 0)
4763
return err;
4864

@@ -109,15 +125,27 @@ static void nft_immediate_activate(const struct nft_ctx *ctx,
109125
return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg));
110126
}
111127

128+
static void nft_immediate_chain_deactivate(const struct nft_ctx *ctx,
129+
struct nft_chain *chain,
130+
enum nft_trans_phase phase)
131+
{
132+
struct nft_ctx chain_ctx;
133+
struct nft_rule *rule;
134+
135+
chain_ctx = *ctx;
136+
chain_ctx.chain = chain;
137+
138+
list_for_each_entry(rule, &chain->rules, list)
139+
nft_rule_expr_deactivate(&chain_ctx, rule, phase);
140+
}
141+
112142
static void nft_immediate_deactivate(const struct nft_ctx *ctx,
113143
const struct nft_expr *expr,
114144
enum nft_trans_phase phase)
115145
{
116146
const struct nft_immediate_expr *priv = nft_expr_priv(expr);
117147
const struct nft_data *data = &priv->data;
118-
struct nft_ctx chain_ctx;
119148
struct nft_chain *chain;
120-
struct nft_rule *rule;
121149

122150
if (priv->dreg == NFT_REG_VERDICT) {
123151
switch (data->verdict.code) {
@@ -127,23 +155,20 @@ static void nft_immediate_deactivate(const struct nft_ctx *ctx,
127155
if (!nft_chain_binding(chain))
128156
break;
129157

130-
chain_ctx = *ctx;
131-
chain_ctx.chain = chain;
132-
133-
list_for_each_entry(rule, &chain->rules, list)
134-
nft_rule_expr_deactivate(&chain_ctx, rule, phase);
135-
136158
switch (phase) {
137159
case NFT_TRANS_PREPARE_ERROR:
138160
nf_tables_unbind_chain(ctx, chain);
139-
fallthrough;
161+
nft_deactivate_next(ctx->net, chain);
162+
break;
140163
case NFT_TRANS_PREPARE:
164+
nft_immediate_chain_deactivate(ctx, chain, phase);
141165
nft_deactivate_next(ctx->net, chain);
142166
break;
143167
default:
168+
nft_immediate_chain_deactivate(ctx, chain, phase);
144169
nft_chain_del(chain);
145170
chain->bound = false;
146-
chain->table->use--;
171+
nft_use_dec(&chain->table->use);
147172
break;
148173
}
149174
break;
@@ -182,17 +207,17 @@ static void nft_immediate_destroy(const struct nft_ctx *ctx,
182207
* let the transaction records release this chain and its rules.
183208
*/
184209
if (chain->bound) {
185-
chain->use--;
210+
nft_use_dec(&chain->use);
186211
break;
187212
}
188213

189214
/* Rule has been deleted, release chain and its rules. */
190215
chain_ctx = *ctx;
191216
chain_ctx.chain = chain;
192217

193-
chain->use--;
218+
nft_use_dec(&chain->use);
194219
list_for_each_entry_safe(rule, n, &chain->rules, list) {
195-
chain->use--;
220+
nft_use_dec(&chain->use);
196221
list_del(&rule->list);
197222
nf_tables_rule_destroy(&chain_ctx, rule);
198223
}

0 commit comments

Comments
 (0)