Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+136 -89
+2 -2
net/ipv4/netfilter/iptable_nat.c
··· 79 79 while (i) 80 80 nf_nat_ipv4_unregister_fn(net, &ops[--i]); 81 81 82 - kfree(ops); 82 + kfree_rcu(ops, rcu); 83 83 return ret; 84 84 } 85 85 } ··· 100 100 for (i = 0; i < ARRAY_SIZE(nf_nat_ipv4_ops); i++) 101 101 nf_nat_ipv4_unregister_fn(net, &ops[i]); 102 102 103 - kfree(ops); 103 + kfree_rcu(ops, rcu); 104 104 } 105 105 106 106 static int iptable_nat_table_init(struct net *net)
+2 -2
net/ipv6/netfilter/ip6table_nat.c
··· 81 81 while (i) 82 82 nf_nat_ipv6_unregister_fn(net, &ops[--i]); 83 83 84 - kfree(ops); 84 + kfree_rcu(ops, rcu); 85 85 return ret; 86 86 } 87 87 } ··· 102 102 for (i = 0; i < ARRAY_SIZE(nf_nat_ipv6_ops); i++) 103 103 nf_nat_ipv6_unregister_fn(net, &ops[i]); 104 104 105 - kfree(ops); 105 + kfree_rcu(ops, rcu); 106 106 } 107 107 108 108 static int ip6table_nat_table_init(struct net *net)
+15 -4
net/netfilter/ipvs/ip_vs_xmit.c
··· 102 102 return dest_dst; 103 103 } 104 104 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 + 105 117 static inline bool 106 118 __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu) 107 119 { ··· 123 111 */ 124 112 if (IP6CB(skb)->frag_max_size > mtu) 125 113 return true; /* largest fragment violate MTU */ 126 - } 127 - else if (skb->len > mtu && !skb_is_gso(skb)) { 114 + } else if (ip_vs_exceeds_mtu(skb, mtu)) 128 115 return true; /* Packet size violate MTU size */ 129 - } 116 + 130 117 return false; 131 118 } 132 119 ··· 243 232 return true; 244 233 245 234 if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && 246 - skb->len > mtu && !skb_is_gso(skb) && 235 + ip_vs_exceeds_mtu(skb, mtu) && 247 236 !ip_vs_iph_icmp(ipvsh))) { 248 237 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, 249 238 htonl(mtu));
+1 -1
net/netfilter/nf_nat_amanda.c
··· 50 50 return NF_DROP; 51 51 } 52 52 53 - sprintf(buffer, "%u", port); 53 + snprintf(buffer, sizeof(buffer), "%u", port); 54 54 if (!nf_nat_mangle_udp_packet(skb, exp->master, ctinfo, 55 55 protoff, matchoff, matchlen, 56 56 buffer, strlen(buffer))) {
+6 -4
net/netfilter/nf_nat_core.c
··· 1222 1222 ret = nf_register_net_hooks(net, nat_ops, ops_count); 1223 1223 if (ret < 0) { 1224 1224 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); 1228 1230 return ret; 1229 1231 } 1230 1232 ··· 1290 1288 } 1291 1289 1292 1290 nat_proto_net->nat_hook_ops = NULL; 1293 - kfree(nat_ops); 1291 + kfree_rcu(nat_ops, rcu); 1294 1292 } 1295 1293 unlock: 1296 1294 mutex_unlock(&nf_nat_proto_mutex);
+18 -15
net/netfilter/nf_nat_sip.c
··· 68 68 } 69 69 70 70 static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, 71 + size_t size, 71 72 const union nf_inet_addr *addr, bool delim) 72 73 { 73 74 if (nf_ct_l3num(ct) == NFPROTO_IPV4) 74 - return sprintf(buffer, "%pI4", &addr->ip); 75 + return scnprintf(buffer, size, "%pI4", &addr->ip); 75 76 else { 76 77 if (delim) 77 - return sprintf(buffer, "[%pI6c]", &addr->ip6); 78 + return scnprintf(buffer, size, "[%pI6c]", &addr->ip6); 78 79 else 79 - return sprintf(buffer, "%pI6c", &addr->ip6); 80 + return scnprintf(buffer, size, "%pI6c", &addr->ip6); 80 81 } 81 82 } 82 83 83 84 static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, 85 + size_t size, 84 86 const union nf_inet_addr *addr, u16 port) 85 87 { 86 88 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); 88 90 else 89 - return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); 91 + return scnprintf(buffer, size, "[%pI6c]:%u", &addr->ip6, port); 90 92 } 91 93 92 94 static int map_addr(struct sk_buff *skb, unsigned int protoff, ··· 121 119 if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) 122 120 return 1; 123 121 124 - buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); 122 + buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), &newaddr, ntohs(newport)); 125 123 return mangle_packet(skb, protoff, dataoff, dptr, datalen, 126 124 matchoff, matchlen, buffer, buflen); 127 125 } ··· 214 212 &addr, true) > 0 && 215 213 nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && 216 214 !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { 217 - buflen = sip_sprintf_addr(ct, buffer, 215 + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), 218 216 &ct->tuplehash[!dir].tuple.dst.u3, 219 217 true); 220 218 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, ··· 231 229 &addr, false) > 0 && 232 230 nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && 233 231 !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { 234 - buflen = sip_sprintf_addr(ct, buffer, 232 + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), 235 233 &ct->tuplehash[!dir].tuple.src.u3, 236 234 false); 237 235 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, ··· 249 247 htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && 250 248 htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { 251 249 __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; 252 - buflen = sprintf(buffer, "%u", ntohs(p)); 250 + buflen = scnprintf(buffer, sizeof(buffer), "%u", ntohs(p)); 253 251 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, 254 252 poff, plen, buffer, buflen)) { 255 253 nf_ct_helper_log(skb, ct, "cannot mangle rport"); ··· 420 418 421 419 if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || 422 420 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { 423 - buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); 421 + buflen = sip_sprintf_addr_port(ct, buffer, sizeof(buffer), 422 + &newaddr, port); 424 423 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, 425 424 matchoff, matchlen, buffer, buflen)) { 426 425 nf_ct_helper_log(skb, ct, "cannot mangle packet"); ··· 441 438 { 442 439 enum ip_conntrack_info ctinfo; 443 440 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 441 + char buffer[sizeof("4294967295")]; 444 442 unsigned int matchoff, matchlen; 445 - char buffer[sizeof("65536")]; 446 443 int buflen, c_len; 447 444 448 445 /* Get actual SDP length */ ··· 457 454 &matchoff, &matchlen) <= 0) 458 455 return 0; 459 456 460 - buflen = sprintf(buffer, "%u", c_len); 457 + buflen = scnprintf(buffer, sizeof(buffer), "%u", c_len); 461 458 return mangle_packet(skb, protoff, dataoff, dptr, datalen, 462 459 matchoff, matchlen, buffer, buflen); 463 460 } ··· 494 491 char buffer[INET6_ADDRSTRLEN]; 495 492 unsigned int buflen; 496 493 497 - buflen = sip_sprintf_addr(ct, buffer, addr, false); 494 + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); 498 495 if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, 499 496 sdpoff, type, term, buffer, buflen)) 500 497 return 0; ··· 512 509 char buffer[sizeof("nnnnn")]; 513 510 unsigned int buflen; 514 511 515 - buflen = sprintf(buffer, "%u", port); 512 + buflen = scnprintf(buffer, sizeof(buffer), "%u", port); 516 513 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, 517 514 matchoff, matchlen, buffer, buflen)) 518 515 return 0; ··· 532 529 unsigned int buflen; 533 530 534 531 /* Mangle session description owner and contact addresses */ 535 - buflen = sip_sprintf_addr(ct, buffer, addr, false); 532 + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), addr, false); 536 533 if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, 537 534 SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) 538 535 return 0;
+5 -1
net/netfilter/nft_osf.c
··· 28 28 struct nf_osf_data data; 29 29 struct tcphdr _tcph; 30 30 31 + if (nft_pf(pkt) != NFPROTO_IPV4) { 32 + regs->verdict.code = NFT_BREAK; 33 + return; 34 + } 35 + 31 36 if (pkt->tprot != IPPROTO_TCP) { 32 37 regs->verdict.code = NFT_BREAK; 33 38 return; ··· 119 114 120 115 switch (ctx->family) { 121 116 case NFPROTO_IPV4: 122 - case NFPROTO_IPV6: 123 117 case NFPROTO_INET: 124 118 hooks = (1 << NF_INET_LOCAL_IN) | 125 119 (1 << NF_INET_PRE_ROUTING) |
+23 -11
net/netfilter/xt_mac.c
··· 36 36 return ret; 37 37 } 38 38 39 - static struct xt_match mac_mt_reg __read_mostly = { 40 - .name = "mac", 41 - .revision = 0, 42 - .family = NFPROTO_UNSPEC, 43 - .match = mac_mt, 44 - .matchsize = sizeof(struct xt_mac_info), 45 - .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | 46 - (1 << NF_INET_FORWARD), 47 - .me = THIS_MODULE, 39 + static struct xt_match mac_mt_reg[] __read_mostly = { 40 + { 41 + .name = "mac", 42 + .family = NFPROTO_IPV4, 43 + .match = mac_mt, 44 + .matchsize = sizeof(struct xt_mac_info), 45 + .hooks = (1 << NF_INET_PRE_ROUTING) | 46 + (1 << NF_INET_LOCAL_IN) | 47 + (1 << NF_INET_FORWARD), 48 + .me = THIS_MODULE, 49 + }, 50 + { 51 + .name = "mac", 52 + .family = NFPROTO_IPV6, 53 + .match = mac_mt, 54 + .matchsize = sizeof(struct xt_mac_info), 55 + .hooks = (1 << NF_INET_PRE_ROUTING) | 56 + (1 << NF_INET_LOCAL_IN) | 57 + (1 << NF_INET_FORWARD), 58 + .me = THIS_MODULE, 59 + }, 48 60 }; 49 61 50 62 static int __init mac_mt_init(void) 51 63 { 52 - return xt_register_match(&mac_mt_reg); 64 + return xt_register_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); 53 65 } 54 66 55 67 static void __exit mac_mt_exit(void) 56 68 { 57 - xt_unregister_match(&mac_mt_reg); 69 + xt_unregister_matches(mac_mt_reg, ARRAY_SIZE(mac_mt_reg)); 58 70 } 59 71 60 72 module_init(mac_mt_init);
+25 -12
net/netfilter/xt_owner.c
··· 127 127 return true; 128 128 } 129 129 130 - static struct xt_match owner_mt_reg __read_mostly = { 131 - .name = "owner", 132 - .revision = 1, 133 - .family = NFPROTO_UNSPEC, 134 - .checkentry = owner_check, 135 - .match = owner_mt, 136 - .matchsize = sizeof(struct xt_owner_match_info), 137 - .hooks = (1 << NF_INET_LOCAL_OUT) | 138 - (1 << NF_INET_POST_ROUTING), 139 - .me = THIS_MODULE, 130 + static struct xt_match owner_mt_reg[] __read_mostly = { 131 + { 132 + .name = "owner", 133 + .revision = 1, 134 + .family = NFPROTO_IPV4, 135 + .checkentry = owner_check, 136 + .match = owner_mt, 137 + .matchsize = sizeof(struct xt_owner_match_info), 138 + .hooks = (1 << NF_INET_LOCAL_OUT) | 139 + (1 << NF_INET_POST_ROUTING), 140 + .me = THIS_MODULE, 141 + }, 142 + { 143 + .name = "owner", 144 + .revision = 1, 145 + .family = NFPROTO_IPV6, 146 + .checkentry = owner_check, 147 + .match = owner_mt, 148 + .matchsize = sizeof(struct xt_owner_match_info), 149 + .hooks = (1 << NF_INET_LOCAL_OUT) | 150 + (1 << NF_INET_POST_ROUTING), 151 + .me = THIS_MODULE, 152 + } 140 153 }; 141 154 142 155 static int __init owner_mt_init(void) 143 156 { 144 - return xt_register_match(&owner_mt_reg); 157 + return xt_register_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); 145 158 } 146 159 147 160 static void __exit owner_mt_exit(void) 148 161 { 149 - xt_unregister_match(&owner_mt_reg); 162 + xt_unregister_matches(owner_mt_reg, ARRAY_SIZE(owner_mt_reg)); 150 163 } 151 164 152 165 module_init(owner_mt_init);
+19 -10
net/netfilter/xt_physdev.c
··· 137 137 return 0; 138 138 } 139 139 140 - static struct xt_match physdev_mt_reg __read_mostly = { 141 - .name = "physdev", 142 - .revision = 0, 143 - .family = NFPROTO_UNSPEC, 144 - .checkentry = physdev_mt_check, 145 - .match = physdev_mt, 146 - .matchsize = sizeof(struct xt_physdev_info), 147 - .me = THIS_MODULE, 140 + static struct xt_match physdev_mt_reg[] __read_mostly = { 141 + { 142 + .name = "physdev", 143 + .family = NFPROTO_IPV4, 144 + .checkentry = physdev_mt_check, 145 + .match = physdev_mt, 146 + .matchsize = sizeof(struct xt_physdev_info), 147 + .me = THIS_MODULE, 148 + }, 149 + { 150 + .name = "physdev", 151 + .family = NFPROTO_IPV6, 152 + .checkentry = physdev_mt_check, 153 + .match = physdev_mt, 154 + .matchsize = sizeof(struct xt_physdev_info), 155 + .me = THIS_MODULE, 156 + }, 148 157 }; 149 158 150 159 static int __init physdev_mt_init(void) 151 160 { 152 - return xt_register_match(&physdev_mt_reg); 161 + return xt_register_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); 153 162 } 154 163 155 164 static void __exit physdev_mt_exit(void) 156 165 { 157 - xt_unregister_match(&physdev_mt_reg); 166 + xt_unregister_matches(physdev_mt_reg, ARRAY_SIZE(physdev_mt_reg)); 158 167 } 159 168 160 169 module_init(physdev_mt_init);
+1 -1
net/netfilter/xt_realm.c
··· 33 33 .matchsize = sizeof(struct xt_realm_info), 34 34 .hooks = (1 << NF_INET_POST_ROUTING) | (1 << NF_INET_FORWARD) | 35 35 (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), 36 - .family = NFPROTO_UNSPEC, 36 + .family = NFPROTO_IPV4, 37 37 .me = THIS_MODULE 38 38 }; 39 39