Skip to content

Commit 55bc1af

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Pablo Neira Ayuso says: ==================== Netfilter fixes for net 1) Add SECMARK revision 1 to fix incorrect layout that prevents from remove rule with this target, from Phil Sutter. 2) Fix pernet exit path spat in arptables, from Florian Westphal. 3) Missing rcu_read_unlock() for unknown nfnetlink callbacks, reported by syzbot, from Eric Dumazet. 4) Missing check for skb_header_pointer() NULL pointer in nfnetlink_osf. 5) Remove BUG_ON() after skb_header_pointer() from packet path in several conntrack helper and the TCP tracker. 6) Fix memleak in the new object error path of userdata. 7) Avoid overflows in nft_hash_buckets(), reported by syzbot, also from Eric. 8) Avoid overflows in 32bit arches, from Eric. * git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf: netfilter: nftables: avoid potential overflows on 32bit arches netfilter: nftables: avoid overflows in nft_hash_buckets() netfilter: nftables: Fix a memleak from userdata error path in new objects netfilter: remove BUG_ON() after skb_header_pointer() netfilter: nfnetlink_osf: Fix a missing skb_header_pointer() NULL check netfilter: nfnetlink: add a missing rcu_read_unlock() netfilter: arptables: use pernet ops struct during unregister netfilter: xt_SECMARK: add new revision to fix structure layout ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents e4d4a27 + 6c8774a commit 55bc1af

File tree

15 files changed

+124
-42
lines changed

15 files changed

+124
-42
lines changed

include/linux/netfilter_arp/arp_tables.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ int arpt_register_table(struct net *net, const struct xt_table *table,
5353
const struct arpt_replace *repl,
5454
const struct nf_hook_ops *ops);
5555
void arpt_unregister_table(struct net *net, const char *name);
56-
void arpt_unregister_table_pre_exit(struct net *net, const char *name,
57-
const struct nf_hook_ops *ops);
56+
void arpt_unregister_table_pre_exit(struct net *net, const char *name);
5857
extern unsigned int arpt_do_table(struct sk_buff *skb,
5958
const struct nf_hook_state *state,
6059
struct xt_table *table);

include/uapi/linux/netfilter/xt_SECMARK.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,10 @@ struct xt_secmark_target_info {
2020
char secctx[SECMARK_SECCTX_MAX];
2121
};
2222

23+
struct xt_secmark_target_info_v1 {
24+
__u8 mode;
25+
char secctx[SECMARK_SECCTX_MAX];
26+
__u32 secid;
27+
};
28+
2329
#endif /*_XT_SECMARK_H_target */

net/ipv4/netfilter/arp_tables.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,13 +1556,12 @@ int arpt_register_table(struct net *net,
15561556
return ret;
15571557
}
15581558

1559-
void arpt_unregister_table_pre_exit(struct net *net, const char *name,
1560-
const struct nf_hook_ops *ops)
1559+
void arpt_unregister_table_pre_exit(struct net *net, const char *name)
15611560
{
15621561
struct xt_table *table = xt_find_table(net, NFPROTO_ARP, name);
15631562

15641563
if (table)
1565-
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks));
1564+
nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
15661565
}
15671566
EXPORT_SYMBOL(arpt_unregister_table_pre_exit);
15681567

net/ipv4/netfilter/arptable_filter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ static int __net_init arptable_filter_table_init(struct net *net)
5454

5555
static void __net_exit arptable_filter_net_pre_exit(struct net *net)
5656
{
57-
arpt_unregister_table_pre_exit(net, "filter", arpfilter_ops);
57+
arpt_unregister_table_pre_exit(net, "filter");
5858
}
5959

6060
static void __net_exit arptable_filter_net_exit(struct net *net)

net/netfilter/nf_conntrack_ftp.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,10 @@ static int help(struct sk_buff *skb,
413413

414414
spin_lock_bh(&nf_ftp_lock);
415415
fb_ptr = skb_header_pointer(skb, dataoff, datalen, ftp_buffer);
416-
BUG_ON(fb_ptr == NULL);
416+
if (!fb_ptr) {
417+
spin_unlock_bh(&nf_ftp_lock);
418+
return NF_ACCEPT;
419+
}
417420

418421
ends_in_nl = (fb_ptr[datalen - 1] == '\n');
419422
seq = ntohl(th->seq) + datalen;

net/netfilter/nf_conntrack_h323_main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
146146
/* Get first TPKT pointer */
147147
tpkt = skb_header_pointer(skb, tcpdataoff, tcpdatalen,
148148
h323_buffer);
149-
BUG_ON(tpkt == NULL);
149+
if (!tpkt)
150+
goto clear_out;
150151

151152
/* Validate TPKT identifier */
152153
if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) {

net/netfilter/nf_conntrack_irc.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,10 @@ static int help(struct sk_buff *skb, unsigned int protoff,
143143
spin_lock_bh(&irc_buffer_lock);
144144
ib_ptr = skb_header_pointer(skb, dataoff, skb->len - dataoff,
145145
irc_buffer);
146-
BUG_ON(ib_ptr == NULL);
146+
if (!ib_ptr) {
147+
spin_unlock_bh(&irc_buffer_lock);
148+
return NF_ACCEPT;
149+
}
147150

148151
data = ib_ptr;
149152
data_limit = ib_ptr + skb->len - dataoff;

net/netfilter/nf_conntrack_pptp.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,9 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff,
544544

545545
nexthdr_off = protoff;
546546
tcph = skb_header_pointer(skb, nexthdr_off, sizeof(_tcph), &_tcph);
547-
BUG_ON(!tcph);
547+
if (!tcph)
548+
return NF_ACCEPT;
549+
548550
nexthdr_off += tcph->doff * 4;
549551
datalen = tcplen - tcph->doff * 4;
550552

net/netfilter/nf_conntrack_proto_tcp.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,8 @@ static void tcp_options(const struct sk_buff *skb,
338338

339339
ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
340340
length, buff);
341-
BUG_ON(ptr == NULL);
341+
if (!ptr)
342+
return;
342343

343344
state->td_scale =
344345
state->flags = 0;
@@ -394,7 +395,8 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
394395

395396
ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
396397
length, buff);
397-
BUG_ON(ptr == NULL);
398+
if (!ptr)
399+
return;
398400

399401
/* Fast path for timestamp-only option */
400402
if (length == TCPOLEN_TSTAMP_ALIGNED

net/netfilter/nf_conntrack_sane.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,10 @@ static int help(struct sk_buff *skb,
9595

9696
spin_lock_bh(&nf_sane_lock);
9797
sb_ptr = skb_header_pointer(skb, dataoff, datalen, sane_buffer);
98-
BUG_ON(sb_ptr == NULL);
98+
if (!sb_ptr) {
99+
spin_unlock_bh(&nf_sane_lock);
100+
return NF_ACCEPT;
101+
}
99102

100103
if (dir == IP_CT_DIR_ORIGINAL) {
101104
if (datalen != sizeof(struct sane_request))

net/netfilter/nf_tables_api.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4184,6 +4184,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
41844184
unsigned char *udata;
41854185
struct nft_set *set;
41864186
struct nft_ctx ctx;
4187+
size_t alloc_size;
41874188
u64 timeout;
41884189
char *name;
41894190
int err, i;
@@ -4329,8 +4330,10 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
43294330
size = 0;
43304331
if (ops->privsize != NULL)
43314332
size = ops->privsize(nla, &desc);
4332-
4333-
set = kvzalloc(sizeof(*set) + size + udlen, GFP_KERNEL);
4333+
alloc_size = sizeof(*set) + size + udlen;
4334+
if (alloc_size < size)
4335+
return -ENOMEM;
4336+
set = kvzalloc(alloc_size, GFP_KERNEL);
43344337
if (!set)
43354338
return -ENOMEM;
43364339

@@ -6615,9 +6618,9 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
66156618
INIT_LIST_HEAD(&obj->list);
66166619
return err;
66176620
err_trans:
6618-
kfree(obj->key.name);
6619-
err_userdata:
66206621
kfree(obj->udata);
6622+
err_userdata:
6623+
kfree(obj->key.name);
66216624
err_strdup:
66226625
if (obj->ops->destroy)
66236626
obj->ops->destroy(&ctx, obj);

net/netfilter/nfnetlink.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
295295
nfnl_unlock(subsys_id);
296296
break;
297297
default:
298+
rcu_read_unlock();
298299
err = -EINVAL;
299300
break;
300301
}

net/netfilter/nfnetlink_osf.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ static const struct tcphdr *nf_osf_hdr_ctx_init(struct nf_osf_hdr_ctx *ctx,
186186

187187
ctx->optp = skb_header_pointer(skb, ip_hdrlen(skb) +
188188
sizeof(struct tcphdr), ctx->optsize, opts);
189+
if (!ctx->optp)
190+
return NULL;
189191
}
190192

191193
return tcp;

net/netfilter/nft_set_hash.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,17 @@ static void nft_rhash_destroy(const struct nft_set *set)
412412
(void *)set);
413413
}
414414

415+
/* Number of buckets is stored in u32, so cap our result to 1U<<31 */
416+
#define NFT_MAX_BUCKETS (1U << 31)
417+
415418
static u32 nft_hash_buckets(u32 size)
416419
{
417-
return roundup_pow_of_two(size * 4 / 3);
420+
u64 val = div_u64((u64)size * 4, 3);
421+
422+
if (val >= NFT_MAX_BUCKETS)
423+
return NFT_MAX_BUCKETS;
424+
425+
return roundup_pow_of_two(val);
418426
}
419427

420428
static bool nft_rhash_estimate(const struct nft_set_desc *desc, u32 features,
@@ -615,7 +623,7 @@ static u64 nft_hash_privsize(const struct nlattr * const nla[],
615623
const struct nft_set_desc *desc)
616624
{
617625
return sizeof(struct nft_hash) +
618-
nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
626+
(u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head);
619627
}
620628

621629
static int nft_hash_init(const struct nft_set *set,
@@ -655,8 +663,8 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
655663
return false;
656664

657665
est->size = sizeof(struct nft_hash) +
658-
nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
659-
desc->size * sizeof(struct nft_hash_elem);
666+
(u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
667+
(u64)desc->size * sizeof(struct nft_hash_elem);
660668
est->lookup = NFT_SET_CLASS_O_1;
661669
est->space = NFT_SET_CLASS_O_N;
662670

@@ -673,8 +681,8 @@ static bool nft_hash_fast_estimate(const struct nft_set_desc *desc, u32 features
673681
return false;
674682

675683
est->size = sizeof(struct nft_hash) +
676-
nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
677-
desc->size * sizeof(struct nft_hash_elem);
684+
(u64)nft_hash_buckets(desc->size) * sizeof(struct hlist_head) +
685+
(u64)desc->size * sizeof(struct nft_hash_elem);
678686
est->lookup = NFT_SET_CLASS_O_1;
679687
est->space = NFT_SET_CLASS_O_N;
680688

net/netfilter/xt_SECMARK.c

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@ MODULE_ALIAS("ip6t_SECMARK");
2424
static u8 mode;
2525

2626
static unsigned int
27-
secmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
27+
secmark_tg(struct sk_buff *skb, const struct xt_secmark_target_info_v1 *info)
2828
{
2929
u32 secmark = 0;
30-
const struct xt_secmark_target_info *info = par->targinfo;
3130

3231
switch (mode) {
3332
case SECMARK_MODE_SEL:
@@ -41,7 +40,7 @@ secmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
4140
return XT_CONTINUE;
4241
}
4342

44-
static int checkentry_lsm(struct xt_secmark_target_info *info)
43+
static int checkentry_lsm(struct xt_secmark_target_info_v1 *info)
4544
{
4645
int err;
4746

@@ -73,15 +72,15 @@ static int checkentry_lsm(struct xt_secmark_target_info *info)
7372
return 0;
7473
}
7574

76-
static int secmark_tg_check(const struct xt_tgchk_param *par)
75+
static int
76+
secmark_tg_check(const char *table, struct xt_secmark_target_info_v1 *info)
7777
{
78-
struct xt_secmark_target_info *info = par->targinfo;
7978
int err;
8079

81-
if (strcmp(par->table, "mangle") != 0 &&
82-
strcmp(par->table, "security") != 0) {
80+
if (strcmp(table, "mangle") != 0 &&
81+
strcmp(table, "security") != 0) {
8382
pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n",
84-
par->table);
83+
table);
8584
return -EINVAL;
8685
}
8786

@@ -116,25 +115,76 @@ static void secmark_tg_destroy(const struct xt_tgdtor_param *par)
116115
}
117116
}
118117

119-
static struct xt_target secmark_tg_reg __read_mostly = {
120-
.name = "SECMARK",
121-
.revision = 0,
122-
.family = NFPROTO_UNSPEC,
123-
.checkentry = secmark_tg_check,
124-
.destroy = secmark_tg_destroy,
125-
.target = secmark_tg,
126-
.targetsize = sizeof(struct xt_secmark_target_info),
127-
.me = THIS_MODULE,
118+
static int secmark_tg_check_v0(const struct xt_tgchk_param *par)
119+
{
120+
struct xt_secmark_target_info *info = par->targinfo;
121+
struct xt_secmark_target_info_v1 newinfo = {
122+
.mode = info->mode,
123+
};
124+
int ret;
125+
126+
memcpy(newinfo.secctx, info->secctx, SECMARK_SECCTX_MAX);
127+
128+
ret = secmark_tg_check(par->table, &newinfo);
129+
info->secid = newinfo.secid;
130+
131+
return ret;
132+
}
133+
134+
static unsigned int
135+
secmark_tg_v0(struct sk_buff *skb, const struct xt_action_param *par)
136+
{
137+
const struct xt_secmark_target_info *info = par->targinfo;
138+
struct xt_secmark_target_info_v1 newinfo = {
139+
.secid = info->secid,
140+
};
141+
142+
return secmark_tg(skb, &newinfo);
143+
}
144+
145+
static int secmark_tg_check_v1(const struct xt_tgchk_param *par)
146+
{
147+
return secmark_tg_check(par->table, par->targinfo);
148+
}
149+
150+
static unsigned int
151+
secmark_tg_v1(struct sk_buff *skb, const struct xt_action_param *par)
152+
{
153+
return secmark_tg(skb, par->targinfo);
154+
}
155+
156+
static struct xt_target secmark_tg_reg[] __read_mostly = {
157+
{
158+
.name = "SECMARK",
159+
.revision = 0,
160+
.family = NFPROTO_UNSPEC,
161+
.checkentry = secmark_tg_check_v0,
162+
.destroy = secmark_tg_destroy,
163+
.target = secmark_tg_v0,
164+
.targetsize = sizeof(struct xt_secmark_target_info),
165+
.me = THIS_MODULE,
166+
},
167+
{
168+
.name = "SECMARK",
169+
.revision = 1,
170+
.family = NFPROTO_UNSPEC,
171+
.checkentry = secmark_tg_check_v1,
172+
.destroy = secmark_tg_destroy,
173+
.target = secmark_tg_v1,
174+
.targetsize = sizeof(struct xt_secmark_target_info_v1),
175+
.usersize = offsetof(struct xt_secmark_target_info_v1, secid),
176+
.me = THIS_MODULE,
177+
},
128178
};
129179

130180
static int __init secmark_tg_init(void)
131181
{
132-
return xt_register_target(&secmark_tg_reg);
182+
return xt_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
133183
}
134184

135185
static void __exit secmark_tg_exit(void)
136186
{
137-
xt_unregister_target(&secmark_tg_reg);
187+
xt_unregister_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
138188
}
139189

140190
module_init(secmark_tg_init);

0 commit comments

Comments
 (0)