Skip to content

Commit 7153a40

Browse files
author
Paolo Abeni
committed
Florian Westphal says: ==================== netfilter updates for net This PR contains nf_tables updates for your *net* tree. This time almost all fixes are for old bugs: First patch fixes a 4-byte stack OOB write, from myself. This was broken ever since nftables was switches from 128 to 32bit register addressing in v4.1. 2nd patch fixes an out-of-bounds read. This has been broken ever since xt_osf got added in 2.6.31, the bug was then just moved around during refactoring, from Wander Lairson Costa. 3rd patch adds a missing enum description, from Phil Sutter. 4th patch fixes a UaF inftables that occurs when userspace adds elements with a timeout so small that expiration happens while the transaction is still in progress. Fix from Pablo Neira Ayuso. Patch 5 fixes a memory out of bounds access, this was broken since v4.20. Patch from Kyle Zeng and Jozsef Kadlecsik. Patch 6 fixes another bogus memory access when building audit record. Bug added in the previous pull request, fix from Pablo. netfilter pull request 2023-09-06 * tag 'nf-23-09-06' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nf_tables: Unbreak audit log reset netfilter: ipset: add the missing IP_SET_HASH_WITH_NET0 macro for ip_set_hash_netportnet.c netfilter: nft_set_rbtree: skip sync GC for new elements in this transaction netfilter: nf_tables: uapi: Describe NFTA_RULE_CHAIN_ID netfilter: nfnetlink_osf: avoid OOB read netfilter: nftables: exthdr: fix 4-byte stack OOB write ==================== Link: https://lore.kernel.org/r/20230906162525.11079-1-fw@strlen.de Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2 parents 35494b0 + 9b5ba5c commit 7153a40

File tree

6 files changed

+36
-15
lines changed

6 files changed

+36
-15
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ enum nft_chain_attributes {
263263
* @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
264264
* @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32)
265265
* @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32)
266+
* @NFTA_RULE_CHAIN_ID: add the rule to chain by ID, alternative to @NFTA_RULE_CHAIN (NLA_U32)
266267
*/
267268
enum nft_rule_attributes {
268269
NFTA_RULE_UNSPEC,

net/netfilter/ipset/ip_set_hash_netportnet.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ MODULE_ALIAS("ip_set_hash:net,port,net");
3636
#define IP_SET_HASH_WITH_PROTO
3737
#define IP_SET_HASH_WITH_NETS
3838
#define IPSET_NET_COUNT 2
39+
#define IP_SET_HASH_WITH_NET0
3940

4041
/* IPv4 variant */
4142

net/netfilter/nf_tables_api.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3480,6 +3480,10 @@ static int __nf_tables_dump_rules(struct sk_buff *skb,
34803480
cont_skip:
34813481
(*idx)++;
34823482
}
3483+
3484+
if (reset && *idx)
3485+
audit_log_rule_reset(table, cb->seq, *idx);
3486+
34833487
return 0;
34843488
}
34853489

@@ -3540,9 +3544,6 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
35403544
done:
35413545
rcu_read_unlock();
35423546

3543-
if (reset && idx > cb->args[0])
3544-
audit_log_rule_reset(table, cb->seq, idx - cb->args[0]);
3545-
35463547
cb->args[0] = idx;
35473548
return skb->len;
35483549
}
@@ -5760,15 +5761,15 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
57605761
if (!args.iter.err && args.iter.count == cb->args[0])
57615762
args.iter.err = nft_set_catchall_dump(net, skb, set,
57625763
reset, cb->seq);
5763-
rcu_read_unlock();
5764-
57655764
nla_nest_end(skb, nest);
57665765
nlmsg_end(skb, nlh);
57675766

57685767
if (reset && args.iter.count > args.iter.skip)
57695768
audit_log_nft_set_reset(table, cb->seq,
57705769
args.iter.count - args.iter.skip);
57715770

5771+
rcu_read_unlock();
5772+
57725773
if (args.iter.err && args.iter.err != -EMSGSIZE)
57735774
return args.iter.err;
57745775
if (args.iter.count == cb->args[0])

net/netfilter/nfnetlink_osf.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,14 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,
315315

316316
f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
317317

318+
if (f->opt_num > ARRAY_SIZE(f->opt))
319+
return -EINVAL;
320+
321+
if (!memchr(f->genre, 0, MAXGENRELEN) ||
322+
!memchr(f->subtype, 0, MAXGENRELEN) ||
323+
!memchr(f->version, 0, MAXGENRELEN))
324+
return -EINVAL;
325+
318326
kf = kmalloc(sizeof(struct nf_osf_finger), GFP_KERNEL);
319327
if (!kf)
320328
return -ENOMEM;

net/netfilter/nft_exthdr.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ static unsigned int optlen(const u8 *opt, unsigned int offset)
3535
return opt[offset + 1];
3636
}
3737

38+
static int nft_skb_copy_to_reg(const struct sk_buff *skb, int offset, u32 *dest, unsigned int len)
39+
{
40+
if (len % NFT_REG32_SIZE)
41+
dest[len / NFT_REG32_SIZE] = 0;
42+
43+
return skb_copy_bits(skb, offset, dest, len);
44+
}
45+
3846
static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
3947
struct nft_regs *regs,
4048
const struct nft_pktinfo *pkt)
@@ -56,8 +64,7 @@ static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
5664
}
5765
offset += priv->offset;
5866

59-
dest[priv->len / NFT_REG32_SIZE] = 0;
60-
if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
67+
if (nft_skb_copy_to_reg(pkt->skb, offset, dest, priv->len) < 0)
6168
goto err;
6269
return;
6370
err:
@@ -153,8 +160,7 @@ static void nft_exthdr_ipv4_eval(const struct nft_expr *expr,
153160
}
154161
offset += priv->offset;
155162

156-
dest[priv->len / NFT_REG32_SIZE] = 0;
157-
if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
163+
if (nft_skb_copy_to_reg(pkt->skb, offset, dest, priv->len) < 0)
158164
goto err;
159165
return;
160166
err:
@@ -210,7 +216,8 @@ static void nft_exthdr_tcp_eval(const struct nft_expr *expr,
210216
if (priv->flags & NFT_EXTHDR_F_PRESENT) {
211217
*dest = 1;
212218
} else {
213-
dest[priv->len / NFT_REG32_SIZE] = 0;
219+
if (priv->len % NFT_REG32_SIZE)
220+
dest[priv->len / NFT_REG32_SIZE] = 0;
214221
memcpy(dest, opt + offset, priv->len);
215222
}
216223

@@ -388,9 +395,8 @@ static void nft_exthdr_sctp_eval(const struct nft_expr *expr,
388395
offset + ntohs(sch->length) > pkt->skb->len)
389396
break;
390397

391-
dest[priv->len / NFT_REG32_SIZE] = 0;
392-
if (skb_copy_bits(pkt->skb, offset + priv->offset,
393-
dest, priv->len) < 0)
398+
if (nft_skb_copy_to_reg(pkt->skb, offset + priv->offset,
399+
dest, priv->len) < 0)
394400
break;
395401
return;
396402
}

net/netfilter/nft_set_rbtree.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
312312
struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL;
313313
struct rb_node *node, *next, *parent, **p, *first = NULL;
314314
struct nft_rbtree *priv = nft_set_priv(set);
315+
u8 cur_genmask = nft_genmask_cur(net);
315316
u8 genmask = nft_genmask_next(net);
316317
int d, err;
317318

@@ -357,8 +358,11 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
357358
if (!nft_set_elem_active(&rbe->ext, genmask))
358359
continue;
359360

360-
/* perform garbage collection to avoid bogus overlap reports. */
361-
if (nft_set_elem_expired(&rbe->ext)) {
361+
/* perform garbage collection to avoid bogus overlap reports
362+
* but skip new elements in this transaction.
363+
*/
364+
if (nft_set_elem_expired(&rbe->ext) &&
365+
nft_set_elem_active(&rbe->ext, cur_genmask)) {
362366
err = nft_rbtree_gc_elem(set, priv, rbe, genmask);
363367
if (err < 0)
364368
return err;

0 commit comments

Comments
 (0)