Skip to content

Commit 4e60de1

Browse files
committed
Merge tag 'nf-23-08-31' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net The following patchset contains Netfilter fixes for net: 1) Fix mangling of TCP options with non-linear skbuff, from Xiao Liang. 2) OOB read in xt_sctp due to missing sanitization of array length field. From Wander Lairson Costa. 3) OOB read in xt_u32 due to missing sanitization of array length field. Also from Wander Lairson Costa. All of them above, always broken for several releases. 4) Missing audit log for set element reset command, from Phil Sutter. 5) Missing audit log for rule reset command, also from Phil. These audit log support are missing in 6.5. * tag 'nf-23-08-31' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nf_tables: Audit log rule reset netfilter: nf_tables: Audit log setelem reset netfilter: xt_u32: validate user space input netfilter: xt_sctp: validate the flag_info count netfilter: nft_exthdr: Fix non-linear header modification ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents ee940b5 + ea078ae commit 4e60de1

File tree

6 files changed

+81
-15
lines changed

6 files changed

+81
-15
lines changed

include/linux/audit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ enum audit_nfcfgop {
117117
AUDIT_NFT_OP_OBJ_RESET,
118118
AUDIT_NFT_OP_FLOWTABLE_REGISTER,
119119
AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
120+
AUDIT_NFT_OP_SETELEM_RESET,
121+
AUDIT_NFT_OP_RULE_RESET,
120122
AUDIT_NFT_OP_INVALID,
121123
};
122124

kernel/auditsc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ static const struct audit_nfcfgop_tab audit_nfcfgs[] = {
143143
{ AUDIT_NFT_OP_OBJ_RESET, "nft_reset_obj" },
144144
{ AUDIT_NFT_OP_FLOWTABLE_REGISTER, "nft_register_flowtable" },
145145
{ AUDIT_NFT_OP_FLOWTABLE_UNREGISTER, "nft_unregister_flowtable" },
146+
{ AUDIT_NFT_OP_SETELEM_RESET, "nft_reset_setelem" },
147+
{ AUDIT_NFT_OP_RULE_RESET, "nft_reset_rule" },
146148
{ AUDIT_NFT_OP_INVALID, "nft_invalid" },
147149
};
148150

net/netfilter/nf_tables_api.c

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ static const u8 nft2audit_op[NFT_MSG_MAX] = { // enum nf_tables_msg_types
102102
[NFT_MSG_NEWFLOWTABLE] = AUDIT_NFT_OP_FLOWTABLE_REGISTER,
103103
[NFT_MSG_GETFLOWTABLE] = AUDIT_NFT_OP_INVALID,
104104
[NFT_MSG_DELFLOWTABLE] = AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
105+
[NFT_MSG_GETSETELEM_RESET] = AUDIT_NFT_OP_SETELEM_RESET,
105106
};
106107

107108
static void nft_validate_state_update(struct nft_table *table, u8 new_validate_state)
@@ -3421,6 +3422,18 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
34213422
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
34223423
}
34233424

3425+
static void audit_log_rule_reset(const struct nft_table *table,
3426+
unsigned int base_seq,
3427+
unsigned int nentries)
3428+
{
3429+
char *buf = kasprintf(GFP_ATOMIC, "%s:%u",
3430+
table->name, base_seq);
3431+
3432+
audit_log_nfcfg(buf, table->family, nentries,
3433+
AUDIT_NFT_OP_RULE_RESET, GFP_ATOMIC);
3434+
kfree(buf);
3435+
}
3436+
34243437
struct nft_rule_dump_ctx {
34253438
char *table;
34263439
char *chain;
@@ -3527,6 +3540,9 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
35273540
done:
35283541
rcu_read_unlock();
35293542

3543+
if (reset && idx > cb->args[0])
3544+
audit_log_rule_reset(table, cb->seq, idx - cb->args[0]);
3545+
35303546
cb->args[0] = idx;
35313547
return skb->len;
35323548
}
@@ -3634,6 +3650,9 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
36343650
if (err < 0)
36353651
goto err_fill_rule_info;
36363652

3653+
if (reset)
3654+
audit_log_rule_reset(table, nft_pernet(net)->base_seq, 1);
3655+
36373656
return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
36383657

36393658
err_fill_rule_info:
@@ -5624,13 +5643,25 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
56245643
return nf_tables_fill_setelem(args->skb, set, elem, args->reset);
56255644
}
56265645

5646+
static void audit_log_nft_set_reset(const struct nft_table *table,
5647+
unsigned int base_seq,
5648+
unsigned int nentries)
5649+
{
5650+
char *buf = kasprintf(GFP_ATOMIC, "%s:%u", table->name, base_seq);
5651+
5652+
audit_log_nfcfg(buf, table->family, nentries,
5653+
AUDIT_NFT_OP_SETELEM_RESET, GFP_ATOMIC);
5654+
kfree(buf);
5655+
}
5656+
56275657
struct nft_set_dump_ctx {
56285658
const struct nft_set *set;
56295659
struct nft_ctx ctx;
56305660
};
56315661

56325662
static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
5633-
const struct nft_set *set, bool reset)
5663+
const struct nft_set *set, bool reset,
5664+
unsigned int base_seq)
56345665
{
56355666
struct nft_set_elem_catchall *catchall;
56365667
u8 genmask = nft_genmask_cur(net);
@@ -5646,6 +5677,8 @@ static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
56465677

56475678
elem.priv = catchall->elem;
56485679
ret = nf_tables_fill_setelem(skb, set, &elem, reset);
5680+
if (reset && !ret)
5681+
audit_log_nft_set_reset(set->table, base_seq, 1);
56495682
break;
56505683
}
56515684

@@ -5725,12 +5758,17 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
57255758
set->ops->walk(&dump_ctx->ctx, set, &args.iter);
57265759

57275760
if (!args.iter.err && args.iter.count == cb->args[0])
5728-
args.iter.err = nft_set_catchall_dump(net, skb, set, reset);
5761+
args.iter.err = nft_set_catchall_dump(net, skb, set,
5762+
reset, cb->seq);
57295763
rcu_read_unlock();
57305764

57315765
nla_nest_end(skb, nest);
57325766
nlmsg_end(skb, nlh);
57335767

5768+
if (reset && args.iter.count > args.iter.skip)
5769+
audit_log_nft_set_reset(table, cb->seq,
5770+
args.iter.count - args.iter.skip);
5771+
57345772
if (args.iter.err && args.iter.err != -EMSGSIZE)
57355773
return args.iter.err;
57365774
if (args.iter.count == cb->args[0])
@@ -5955,13 +5993,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
59555993
struct netlink_ext_ack *extack = info->extack;
59565994
u8 genmask = nft_genmask_cur(info->net);
59575995
u8 family = info->nfmsg->nfgen_family;
5996+
int rem, err = 0, nelems = 0;
59585997
struct net *net = info->net;
59595998
struct nft_table *table;
59605999
struct nft_set *set;
59616000
struct nlattr *attr;
59626001
struct nft_ctx ctx;
59636002
bool reset = false;
5964-
int rem, err = 0;
59656003

59666004
table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
59676005
genmask, 0);
@@ -6004,8 +6042,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
60046042
NL_SET_BAD_ATTR(extack, attr);
60056043
break;
60066044
}
6045+
nelems++;
60076046
}
60086047

6048+
if (reset)
6049+
audit_log_nft_set_reset(table, nft_pernet(net)->base_seq,
6050+
nelems);
6051+
60096052
return err;
60106053
}
60116054

net/netfilter/nft_exthdr.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,12 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
238238
if (!tcph)
239239
goto err;
240240

241+
if (skb_ensure_writable(pkt->skb, nft_thoff(pkt) + tcphdr_len))
242+
goto err;
243+
244+
tcph = (struct tcphdr *)(pkt->skb->data + nft_thoff(pkt));
241245
opt = (u8 *)tcph;
246+
242247
for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
243248
union {
244249
__be16 v16;
@@ -253,15 +258,6 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
253258
if (i + optl > tcphdr_len || priv->len + priv->offset > optl)
254259
goto err;
255260

256-
if (skb_ensure_writable(pkt->skb,
257-
nft_thoff(pkt) + i + priv->len))
258-
goto err;
259-
260-
tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff,
261-
&tcphdr_len);
262-
if (!tcph)
263-
goto err;
264-
265261
offset = i + priv->offset;
266262

267263
switch (priv->len) {
@@ -325,9 +321,9 @@ static void nft_exthdr_tcp_strip_eval(const struct nft_expr *expr,
325321
if (skb_ensure_writable(pkt->skb, nft_thoff(pkt) + tcphdr_len))
326322
goto drop;
327323

328-
opt = (u8 *)nft_tcp_header_pointer(pkt, sizeof(buff), buff, &tcphdr_len);
329-
if (!opt)
330-
goto err;
324+
tcph = (struct tcphdr *)(pkt->skb->data + nft_thoff(pkt));
325+
opt = (u8 *)tcph;
326+
331327
for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
332328
unsigned int j;
333329

net/netfilter/xt_sctp.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ static int sctp_mt_check(const struct xt_mtchk_param *par)
149149
{
150150
const struct xt_sctp_info *info = par->matchinfo;
151151

152+
if (info->flag_count > ARRAY_SIZE(info->flag_info))
153+
return -EINVAL;
152154
if (info->flags & ~XT_SCTP_VALID_FLAGS)
153155
return -EINVAL;
154156
if (info->invflags & ~XT_SCTP_VALID_FLAGS)

net/netfilter/xt_u32.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,32 @@ static bool u32_mt(const struct sk_buff *skb, struct xt_action_param *par)
9696
return ret ^ data->invert;
9797
}
9898

99+
static int u32_mt_checkentry(const struct xt_mtchk_param *par)
100+
{
101+
const struct xt_u32 *data = par->matchinfo;
102+
const struct xt_u32_test *ct;
103+
unsigned int i;
104+
105+
if (data->ntests > ARRAY_SIZE(data->tests))
106+
return -EINVAL;
107+
108+
for (i = 0; i < data->ntests; ++i) {
109+
ct = &data->tests[i];
110+
111+
if (ct->nnums > ARRAY_SIZE(ct->location) ||
112+
ct->nvalues > ARRAY_SIZE(ct->value))
113+
return -EINVAL;
114+
}
115+
116+
return 0;
117+
}
118+
99119
static struct xt_match xt_u32_mt_reg __read_mostly = {
100120
.name = "u32",
101121
.revision = 0,
102122
.family = NFPROTO_UNSPEC,
103123
.match = u32_mt,
124+
.checkentry = u32_mt_checkentry,
104125
.matchsize = sizeof(struct xt_u32),
105126
.me = THIS_MODULE,
106127
};

0 commit comments

Comments
 (0)