Skip to content

Commit 5a5db99

Browse files
author
Paolo Abeni
committed
Merge tag 'nf-26-04-20' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says: ==================== Netfilter/IPVS fixes for net The following batch contains Netfilter/IPVS fixes for net: 1) nft_osf actually only supports IPv4, restrict it. 2) Address possible division by zero in nfnetlink_osf, from Xiang Mei. 3) Remove unsafe use of sprintf to fix possible buffer overflow in the SIP NAT helper, from Florian Westphal. 4) Restrict xt_mac, xt_owner and xt_physdev to inet families only; xt_realm is only for ipv4, otherwise null-pointer-deref is possible. 5) Use kfree_rcu() in nat core to release hooks, this can be an issue once nfnetlink_hook gets support to dump NAT hook information, not currently a real issue but better fix it now. From Florian Westphal. 6) Fix MTU checks in IPVS, from Yingnan Zhang. 7) Fix possible out-of-bounds when matching TCP options in nfnetlink_osf, from Fernando Fernandez Mancera. 8) Fix potential nul-ptr-deref in ttl check in nfnetlink_osf, remove useless loop to fix this, also from Fernando. This is a smaller batch, there are more patches pending in the queue to arm another pull request as soon as this is considered good enough. AI might complain again about one more issue regarding osf and big-endian arches in osf but this batch is targetting crash fixes for osf at this stage. netfilter pull request 26-04-20 * tag 'nf-26-04-20' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check netfilter: nfnetlink_osf: fix out-of-bounds read on option matching ipvs: fix MTU check for GSO packets in tunnel mode netfilter: nat: use kfree_rcu to release ops netfilter: xtables: restrict several matches to inet family netfilter: conntrack: remove sprintf usage netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO netfilter: nft_osf: restrict it to ipv4 ==================== Link: https://patch.msgid.link/20260420220215.111510-1-pablo@netfilter.org Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2 parents 0c07802 + 711987b commit 5a5db99

12 files changed

Lines changed: 136 additions & 89 deletions

File tree

net/ipv4/netfilter/iptable_nat.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ static int ipt_nat_register_lookups(struct net *net)
7979
while (i)
8080
nf_nat_ipv4_unregister_fn(net, &ops[--i]);
8181

82-
kfree(ops);
82+
kfree_rcu(ops, rcu);
8383
return ret;
8484
}
8585
}
@@ -100,7 +100,7 @@ static void ipt_nat_unregister_lookups(struct net *net)
100100
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++)
101101
nf_nat_ipv4_unregister_fn(net, &ops[i]);
102102

103-
kfree(ops);
103+
kfree_rcu(ops, rcu);
104104
}
105105

106106
static int iptable_nat_table_init(struct net *net)

net/ipv6/netfilter/ip6table_nat.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static int ip6t_nat_register_lookups(struct net *net)
8181
while (i)
8282
nf_nat_ipv6_unregister_fn(net, &ops[--i]);
8383

84-
kfree(ops);
84+
kfree_rcu(ops, rcu);
8585
return ret;
8686
}
8787
}
@@ -102,7 +102,7 @@ static void ip6t_nat_unregister_lookups(struct net *net)
102102
for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++)
103103
nf_nat_ipv6_unregister_fn(net, &ops[i]);
104104

105-
kfree(ops);
105+
kfree_rcu(ops, rcu);
106106
}
107107

108108
static int ip6table_nat_table_init(struct net *net)

net/netfilter/ipvs/ip_vs_xmit.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest)
102102
return dest_dst;
103103
}
104104

105+
/* Based on ip_exceeds_mtu(). */
106+
static bool ip_vs_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
107+
{
108+
if (skb->len <= mtu)
109+
return false;
110+
111+
if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
112+
return false;
113+
114+
return true;
115+
}
116+
105117
static inline bool
106118
__mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
107119
{
@@ -111,10 +123,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)
111123
*/
112124
if (IP6CB(skb)->frag_max_size > mtu)
113125
return true; /* largest fragment violate MTU */
114-
}
115-
else if (skb->len > mtu && !skb_is_gso(skb)) {
126+
} else if (ip_vs_exceeds_mtu(skb, mtu))
116127
return true; /* Packet size violate MTU size */
117-
}
128+
118129
return false;
119130
}
120131

@@ -232,7 +243,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af,
232243
return true;
233244

234245
if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) &&
235-
skb->len > mtu && !skb_is_gso(skb) &&
246+
ip_vs_exceeds_mtu(skb, mtu) &&
236247
!ip_vs_iph_icmp(ipvsh))) {
237248
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
238249
htonl(mtu));

net/netfilter/nf_nat_amanda.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb,
5050
return NF_DROP;
5151
}
5252

53-
sprintf(buffer, "%u", port);
53+
snprintf(buffer, sizeof(buffer), "%u", port);
5454
if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo,
5555
protoff, matchoff, matchlen,
5656
buffer, strlen(buffer))) {

net/netfilter/nf_nat_core.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,9 +1222,11 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
12221222
ret = nf_register_net_hooks(net, nat_ops, ops_count);
12231223
if (ret < 0) {
12241224
mutex_unlock(&nf_nat_proto_mutex);
1225-
for (i = 0; i < ops_count; i++)
1226-
kfree(nat_ops[i].priv);
1227-
kfree(nat_ops);
1225+
for (i = 0; i < ops_count; i++) {
1226+
priv = nat_ops[i].priv;
1227+
kfree_rcu(priv, rcu_head);
1228+
}
1229+
kfree_rcu(nat_ops, rcu);
12281230
return ret;
12291231
}
12301232

@@ -1288,7 +1290,7 @@ void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops,
12881290
}
12891291

12901292
nat_proto_net->nat_hook_ops = NULL;
1291-
kfree(nat_ops);
1293+
kfree_rcu(nat_ops, rcu);
12921294
}
12931295
unlock:
12941296
mutex_unlock(&nf_nat_proto_mutex);

net/netfilter/nf_nat_sip.c

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff,
6868
}
6969

7070
static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer,
71+
size_t size,
7172
const union nf_inet_addr *addr, bool delim)
7273
{
7374
if (nf_ct_l3num(ct) == NFPROTO_IPV4)
74-
return sprintf(buffer, "%pI4", &addr->ip);
75+
return scnprintf(buffer, size, "%pI4", &addr->ip);
7576
else {
7677
if (delim)
77-
return sprintf(buffer, "[%pI6c]", &addr->ip6);
78+
return scnprintf(buffer, size, "[%pI6c]", &addr->ip6);
7879
else
79-
return sprintf(buffer, "%pI6c", &addr->ip6);
80+
return scnprintf(buffer, size, "%pI6c", &addr->ip6);
8081
}
8182
}
8283

8384
static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer,
85+
size_t size,
8486
const union nf_inet_addr *addr, u16 port)
8587
{
8688
if (nf_ct_l3num(ct) == NFPROTO_IPV4)
87-
return sprintf(buffer, "%pI4:%u", &addr->ip, port);
89+
return scnprintf(buffer, size, "%pI4:%u", &addr->ip, port);
8890
else
89-
return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port);
91+
return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port);
9092
}
9193

9294
static int map_addr(struct sk_buff *skb, unsigned int protoff,
@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff,
119121
if (nf_inet_addr_cmp(&newaddr, addr) && newport == port)
120122
return 1;
121123

122-
buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport));
124+
buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport));
123125
return mangle_packet(skb, protoff, dataoff, dptr, datalen,
124126
matchoff, matchlen, buffer, buflen);
125127
}
@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
212214
&addr, true) > 0 &&
213215
nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) &&
214216
!nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) {
215-
buflen = sip_sprintf_addr(ct, buffer,
217+
buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer),
216218
&ct->tuplehash[!dir].tuple.dst.u3,
217219
true);
218220
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
229231
&addr, false) > 0 &&
230232
nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) &&
231233
!nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) {
232-
buflen = sip_sprintf_addr(ct, buffer,
234+
buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer),
233235
&ct->tuplehash[!dir].tuple.src.u3,
234236
false);
235237
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
247249
htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
248250
htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
249251
__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
250-
buflen = sprintf(buffer, "%u", ntohs(p));
252+
buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p));
251253
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
252254
poff, plen, buffer, buflen)) {
253255
nf_ct_helper_log(skb, ct, "cannot mangle rport");
@@ -418,7 +420,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
418420

419421
if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) ||
420422
exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
421-
buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port);
423+
buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer),
424+
&newaddr, port);
422425
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
423426
matchoff, matchlen, buffer, buflen)) {
424427
nf_ct_helper_log(skb, ct, "cannot mangle packet");
@@ -438,8 +441,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff,
438441
{
439442
enum ip_conntrack_info ctinfo;
440443
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
444+
char buffer[sizeof("4294967295")];
441445
unsigned int matchoff, matchlen;
442-
char buffer[sizeof("65536")];
443446
int buflen, c_len;
444447

445448
/* Get actual SDP length */
@@ -454,7 +457,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff,
454457
&matchoff, &matchlen) <= 0)
455458
return 0;
456459

457-
buflen = sprintf(buffer, "%u", c_len);
460+
buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len);
458461
return mangle_packet(skb, protoff, dataoff, dptr, datalen,
459462
matchoff, matchlen, buffer, buflen);
460463
}
@@ -491,7 +494,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,
491494
char buffer[INET6_ADDRSTRLEN];
492495
unsigned int buflen;
493496

494-
buflen = sip_sprintf_addr(ct, buffer, addr, false);
497+
buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false);
495498
if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen,
496499
sdpoff, type, term, buffer, buflen))
497500
return 0;
@@ -509,7 +512,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff,
509512
char buffer[sizeof("nnnnn")];
510513
unsigned int buflen;
511514

512-
buflen = sprintf(buffer, "%u", port);
515+
buflen = scnprintf(buffer, sizeof(buffer), "%u", port);
513516
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
514517
matchoff, matchlen, buffer, buflen))
515518
return 0;
@@ -529,7 +532,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff
529532
unsigned int buflen;
530533

531534
/* Mangle session description owner and contact addresses */
532-
buflen = sip_sprintf_addr(ct, buffer, addr, false);
535+
buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false);
533536
if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
534537
SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen))
535538
return 0;

net/netfilter/nfnetlink_osf.c

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers);
3131
static inline int nf_osf_ttl(const struct sk_buff *skb,
3232
int ttl_check, unsigned char f_ttl)
3333
{
34-
struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
3534
const struct iphdr *ip = ip_hdr(skb);
36-
const struct in_ifaddr *ifa;
37-
int ret = 0;
3835

39-
if (ttl_check == NF_OSF_TTL_TRUE)
36+
switch (ttl_check) {
37+
case NF_OSF_TTL_TRUE:
4038
return ip->ttl == f_ttl;
41-
if (ttl_check == NF_OSF_TTL_NOCHECK)
42-
return 1;
43-
else if (ip->ttl <= f_ttl)
39+
break;
40+
case NF_OSF_TTL_NOCHECK:
4441
return 1;
45-
46-
in_dev_for_each_ifa_rcu(ifa, in_dev) {
47-
if (inet_ifa_match(ip->saddr, ifa)) {
48-
ret = (ip->ttl == f_ttl);
49-
break;
50-
}
42+
case NF_OSF_TTL_LESS:
43+
default:
44+
return ip->ttl <= f_ttl;
5145
}
52-
53-
return ret;
5446
}
5547

5648
struct nf_osf_hdr_ctx {
@@ -64,9 +56,9 @@ struct nf_osf_hdr_ctx {
6456
static bool nf_osf_match_one(const struct sk_buff *skb,
6557
const struct nf_osf_user_finger *f,
6658
int ttl_check,
67-
struct nf_osf_hdr_ctx *ctx)
59+
const struct nf_osf_hdr_ctx *ctx)
6860
{
69-
const __u8 *optpinit = ctx->optp;
61+
const __u8 *optp = ctx->optp;
7062
unsigned int check_WSS = 0;
7163
int fmatch = FMATCH_WRONG;
7264
int foptsize, optnum;
@@ -95,25 +87,25 @@ static bool nf_osf_match_one(const struct sk_buff *skb,
9587
check_WSS = f->wss.wc;
9688

9789
for (optnum = 0; optnum < f->opt_num; ++optnum) {
98-
if (f->opt[optnum].kind == *ctx->optp) {
90+
if (f->opt[optnum].kind == *optp) {
9991
__u32 len = f->opt[optnum].length;
100-
const __u8 *optend = ctx->optp + len;
92+
const __u8 *optend = optp + len;
10193

10294
fmatch = FMATCH_OK;
10395

104-
switch (*ctx->optp) {
96+
switch (*optp) {
10597
case OSFOPT_MSS:
106-
mss = ctx->optp[3];
98+
mss = optp[3];
10799
mss <<= 8;
108-
mss |= ctx->optp[2];
100+
mss |= optp[2];
109101

110102
mss = ntohs((__force __be16)mss);
111103
break;
112104
case OSFOPT_TS:
113105
break;
114106
}
115107

116-
ctx->optp = optend;
108+
optp = optend;
117109
} else
118110
fmatch = FMATCH_OPT_WRONG;
119111

@@ -156,9 +148,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb,
156148
}
157149
}
158150

159-
if (fmatch != FMATCH_OK)
160-
ctx->optp = optpinit;
161-
162151
return fmatch == FMATCH_OK;
163152
}
164153

@@ -320,6 +309,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,
320309
if (f->opt_num > ARRAY_SIZE(f->opt))
321310
return -EINVAL;
322311

312+
if (f->wss.wc >= OSF_WSS_MAX ||
313+
(f->wss.wc == OSF_WSS_MODULO && f->wss.val == 0))
314+
return -EINVAL;
315+
323316
for (i = 0; i < f->opt_num; i++) {
324317
if (!f->opt[i].length || f->opt[i].length > MAX_IPOPTLEN)
325318
return -EINVAL;

net/netfilter/nft_osf.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,
2828
struct nf_osf_data data;
2929
struct tcphdr _tcph;
3030

31+
if (nft_pf(pkt) != NFPROTO_IPV4) {
32+
regs->verdict.code = NFT_BREAK;
33+
return;
34+
}
35+
3136
if (pkt->tprot != IPPROTO_TCP) {
3237
regs->verdict.code = NFT_BREAK;
3338
return;
@@ -114,7 +119,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx,
114119

115120
switch (ctx->family) {
116121
case NFPROTO_IPV4:
117-
case NFPROTO_IPV6:
118122
case NFPROTO_INET:
119123
hooks = (1 << NF_INET_LOCAL_IN) |
120124
(1 << NF_INET_PRE_ROUTING) |

0 commit comments

Comments
 (0)