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

Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf

Florian Westphal says:

====================
netfilter: bug fixes for net

1. Fix IP address check in irc DCC conntrack helper, this should check
the opposite direction rather than the destination address of the
packets' direction, from David Leadbeater.

2. bridge netfilter needs to drop dst references, from Harsh Modi.
This was fine back in the day the code was originally written,
but nowadays various tunnels can pre-set metadata dsts on packets.

3. Remove nf_conntrack_helper sysctl and the modparam toggle, users
need to explicitily assign the helpers to use via nftables or
iptables. Conntrack helpers, by design, may be used to add dynamic
port redirections to internal machines, so its necessary to restrict
which hosts/peers are allowed to use them.
It was discovered that improper checking in the irc DCC helper makes
it possible to trigger the 'please do dynamic port forward'
from outside by embedding a 'DCC' in a PING request; if the client
echos that back a expectation/port forward gets added.
The auto-assign-for-everything mechanism has been in "please don't do this"
territory since 2012. From Pablo.

4. Fix a memory leak in the netdev hook error unwind path, also from Pablo.

* git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
netfilter: nf_conntrack_irc: Fix forged IP logic
netfilter: nf_tables: clean up hook list when offload flags check fails
netfilter: br_netfilter: Drop dst references before setting.
netfilter: remove nf_conntrack_helper sysctl and modparam toggles
====================

Link: https://lore.kernel.org/r/20220901071238.3044-1-fw@strlen.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+46 -110
-2
include/net/netfilter/nf_conntrack.h
··· 53 53 /* only used when new connection is allocated: */ 54 54 atomic_t count; 55 55 unsigned int expect_count; 56 - u8 sysctl_auto_assign_helper; 57 - bool auto_assign_helper_warned; 58 56 59 57 /* only used from work queues, configuration plane, and so on: */ 60 58 unsigned int users4;
-1
include/net/netns/conntrack.h
··· 101 101 u8 sysctl_log_invalid; /* Log invalid packets */ 102 102 u8 sysctl_events; 103 103 u8 sysctl_acct; 104 - u8 sysctl_auto_assign_helper; 105 104 u8 sysctl_tstamp; 106 105 u8 sysctl_checksum; 107 106
+2
net/bridge/br_netfilter_hooks.c
··· 384 384 /* - Bridged-and-DNAT'ed traffic doesn't 385 385 * require ip_forwarding. */ 386 386 if (rt->dst.dev == dev) { 387 + skb_dst_drop(skb); 387 388 skb_dst_set(skb, &rt->dst); 388 389 goto bridged_dnat; 389 390 } ··· 414 413 kfree_skb(skb); 415 414 return 0; 416 415 } 416 + skb_dst_drop(skb); 417 417 skb_dst_set_noref(skb, &rt->dst); 418 418 } 419 419
+1
net/bridge/br_netfilter_ipv6.c
··· 197 197 kfree_skb(skb); 198 198 return 0; 199 199 } 200 + skb_dst_drop(skb); 200 201 skb_dst_set_noref(skb, &rt->dst); 201 202 } 202 203
+1 -6
net/netfilter/nf_conntrack_core.c
··· 1782 1782 } 1783 1783 spin_unlock_bh(&nf_conntrack_expect_lock); 1784 1784 } 1785 - if (!exp) 1785 + if (!exp && tmpl) 1786 1786 __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC); 1787 1787 1788 1788 /* Other CPU might have obtained a pointer to this object before it was ··· 2068 2068 ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; 2069 2069 if (ct->master || (help && !hlist_empty(&help->expectations))) 2070 2070 return; 2071 - 2072 - rcu_read_lock(); 2073 - __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC); 2074 - rcu_read_unlock(); 2075 2071 } 2076 2072 EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); 2077 2073 ··· 2793 2797 nf_conntrack_acct_pernet_init(net); 2794 2798 nf_conntrack_tstamp_pernet_init(net); 2795 2799 nf_conntrack_ecache_pernet_init(net); 2796 - nf_conntrack_helper_pernet_init(net); 2797 2800 nf_conntrack_proto_pernet_init(net); 2798 2801 2799 2802 return 0;
+10 -70
net/netfilter/nf_conntrack_helper.c
··· 35 35 EXPORT_SYMBOL_GPL(nf_ct_helper_hsize); 36 36 static unsigned int nf_ct_helper_count __read_mostly; 37 37 38 - static bool nf_ct_auto_assign_helper __read_mostly = false; 39 - module_param_named(nf_conntrack_helper, nf_ct_auto_assign_helper, bool, 0644); 40 - MODULE_PARM_DESC(nf_conntrack_helper, 41 - "Enable automatic conntrack helper assignment (default 0)"); 42 - 43 38 static DEFINE_MUTEX(nf_ct_nat_helpers_mutex); 44 39 static struct list_head nf_ct_nat_helpers __read_mostly; 45 40 ··· 44 49 { 45 50 return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^ 46 51 (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize; 47 - } 48 - 49 - static struct nf_conntrack_helper * 50 - __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) 51 - { 52 - struct nf_conntrack_helper *helper; 53 - struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) }; 54 - unsigned int h; 55 - 56 - if (!nf_ct_helper_count) 57 - return NULL; 58 - 59 - h = helper_hash(tuple); 60 - hlist_for_each_entry_rcu(helper, &nf_ct_helper_hash[h], hnode) { 61 - if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask)) 62 - return helper; 63 - } 64 - return NULL; 65 52 } 66 53 67 54 struct nf_conntrack_helper * ··· 186 209 } 187 210 EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); 188 211 189 - static struct nf_conntrack_helper * 190 - nf_ct_lookup_helper(struct nf_conn *ct, struct net *net) 191 - { 192 - struct nf_conntrack_net *cnet = nf_ct_pernet(net); 193 - 194 - if (!cnet->sysctl_auto_assign_helper) { 195 - if (cnet->auto_assign_helper_warned) 196 - return NULL; 197 - if (!__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple)) 198 - return NULL; 199 - pr_info("nf_conntrack: default automatic helper assignment " 200 - "has been turned off for security reasons and CT-based " 201 - "firewall rule not found. Use the iptables CT target " 202 - "to attach helpers instead.\n"); 203 - cnet->auto_assign_helper_warned = true; 204 - return NULL; 205 - } 206 - 207 - return __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); 208 - } 209 - 210 212 int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, 211 213 gfp_t flags) 212 214 { 213 215 struct nf_conntrack_helper *helper = NULL; 214 216 struct nf_conn_help *help; 215 - struct net *net = nf_ct_net(ct); 216 217 217 218 /* We already got a helper explicitly attached. The function 218 219 * nf_conntrack_alter_reply - in case NAT is in use - asks for looking ··· 201 246 if (test_bit(IPS_HELPER_BIT, &ct->status)) 202 247 return 0; 203 248 204 - if (tmpl != NULL) { 205 - help = nfct_help(tmpl); 206 - if (help != NULL) { 207 - helper = rcu_dereference(help->helper); 208 - set_bit(IPS_HELPER_BIT, &ct->status); 209 - } 249 + if (WARN_ON_ONCE(!tmpl)) 250 + return 0; 251 + 252 + help = nfct_help(tmpl); 253 + if (help != NULL) { 254 + helper = rcu_dereference(help->helper); 255 + set_bit(IPS_HELPER_BIT, &ct->status); 210 256 } 211 257 212 258 help = nfct_help(ct); 213 259 214 260 if (helper == NULL) { 215 - helper = nf_ct_lookup_helper(ct, net); 216 - if (helper == NULL) { 217 - if (help) 218 - RCU_INIT_POINTER(help->helper, NULL); 219 - return 0; 220 - } 261 + if (help) 262 + RCU_INIT_POINTER(help->helper, NULL); 263 + return 0; 221 264 } 222 265 223 266 if (help == NULL) { ··· 497 544 mutex_unlock(&nf_ct_nat_helpers_mutex); 498 545 } 499 546 EXPORT_SYMBOL_GPL(nf_nat_helper_unregister); 500 - 501 - void nf_ct_set_auto_assign_helper_warned(struct net *net) 502 - { 503 - nf_ct_pernet(net)->auto_assign_helper_warned = true; 504 - } 505 - EXPORT_SYMBOL_GPL(nf_ct_set_auto_assign_helper_warned); 506 - 507 - void nf_conntrack_helper_pernet_init(struct net *net) 508 - { 509 - struct nf_conntrack_net *cnet = nf_ct_pernet(net); 510 - 511 - cnet->sysctl_auto_assign_helper = nf_ct_auto_assign_helper; 512 - } 513 547 514 548 int nf_conntrack_helper_init(void) 515 549 {
+3 -2
net/netfilter/nf_conntrack_irc.c
··· 194 194 195 195 /* dcc_ip can be the internal OR external (NAT'ed) IP */ 196 196 tuple = &ct->tuplehash[dir].tuple; 197 - if (tuple->src.u3.ip != dcc_ip && 198 - tuple->dst.u3.ip != dcc_ip) { 197 + if ((tuple->src.u3.ip != dcc_ip && 198 + ct->tuplehash[!dir].tuple.dst.u3.ip != dcc_ip) || 199 + dcc_port == 0) { 199 200 net_warn_ratelimited("Forged DCC command from %pI4: %pI4:%u\n", 200 201 &tuple->src.u3.ip, 201 202 &dcc_ip, dcc_port);
-5
net/netfilter/nf_conntrack_netlink.c
··· 2298 2298 ct->status |= IPS_HELPER; 2299 2299 RCU_INIT_POINTER(help->helper, helper); 2300 2300 } 2301 - } else { 2302 - /* try an implicit helper assignation */ 2303 - err = __nf_ct_try_assign_helper(ct, NULL, GFP_ATOMIC); 2304 - if (err < 0) 2305 - goto err2; 2306 2301 } 2307 2302 2308 2303 err = ctnetlink_setup_nat(ct, cda);
-10
net/netfilter/nf_conntrack_standalone.c
··· 561 561 NF_SYSCTL_CT_LOG_INVALID, 562 562 NF_SYSCTL_CT_EXPECT_MAX, 563 563 NF_SYSCTL_CT_ACCT, 564 - NF_SYSCTL_CT_HELPER, 565 564 #ifdef CONFIG_NF_CONNTRACK_EVENTS 566 565 NF_SYSCTL_CT_EVENTS, 567 566 #endif ··· 673 674 [NF_SYSCTL_CT_ACCT] = { 674 675 .procname = "nf_conntrack_acct", 675 676 .data = &init_net.ct.sysctl_acct, 676 - .maxlen = sizeof(u8), 677 - .mode = 0644, 678 - .proc_handler = proc_dou8vec_minmax, 679 - .extra1 = SYSCTL_ZERO, 680 - .extra2 = SYSCTL_ONE, 681 - }, 682 - [NF_SYSCTL_CT_HELPER] = { 683 - .procname = "nf_conntrack_helper", 684 677 .maxlen = sizeof(u8), 685 678 .mode = 0644, 686 679 .proc_handler = proc_dou8vec_minmax, ··· 1091 1100 table[NF_SYSCTL_CT_CHECKSUM].data = &net->ct.sysctl_checksum; 1092 1101 table[NF_SYSCTL_CT_LOG_INVALID].data = &net->ct.sysctl_log_invalid; 1093 1102 table[NF_SYSCTL_CT_ACCT].data = &net->ct.sysctl_acct; 1094 - table[NF_SYSCTL_CT_HELPER].data = &cnet->sysctl_auto_assign_helper; 1095 1103 #ifdef CONFIG_NF_CONNTRACK_EVENTS 1096 1104 table[NF_SYSCTL_CT_EVENTS].data = &net->ct.sysctl_events; 1097 1105 #endif
+3 -1
net/netfilter/nf_tables_api.c
··· 2166 2166 chain->flags |= NFT_CHAIN_BASE | flags; 2167 2167 basechain->policy = NF_ACCEPT; 2168 2168 if (chain->flags & NFT_CHAIN_HW_OFFLOAD && 2169 - !nft_chain_offload_support(basechain)) 2169 + !nft_chain_offload_support(basechain)) { 2170 + list_splice_init(&basechain->hook_list, &hook->list); 2170 2171 return -EOPNOTSUPP; 2172 + } 2171 2173 2172 2174 flow_block_init(&basechain->flow_block); 2173 2175
-3
net/netfilter/nft_ct.c
··· 1089 1089 if (err < 0) 1090 1090 goto err_put_helper; 1091 1091 1092 - /* Avoid the bogus warning, helper will be assigned after CT init */ 1093 - nf_ct_set_auto_assign_helper_warned(ctx->net); 1094 - 1095 1092 return 0; 1096 1093 1097 1094 err_put_helper:
+26 -10
tools/testing/selftests/netfilter/nft_conntrack_helper.sh
··· 102 102 103 103 ip netns exec ${netns} conntrack -L -f $family -p tcp --dport $port 2> /dev/null |grep -q 'helper=ftp' 104 104 if [ $? -ne 0 ] ; then 105 - echo "FAIL: ${netns} did not show attached helper $message" 1>&2 106 - ret=1 105 + if [ $autoassign -eq 0 ] ;then 106 + echo "FAIL: ${netns} did not show attached helper $message" 1>&2 107 + ret=1 108 + else 109 + echo "PASS: ${netns} did not show attached helper $message" 1>&2 110 + fi 111 + else 112 + if [ $autoassign -eq 0 ] ;then 113 + echo "PASS: ${netns} connection on port $port has ftp helper attached" 1>&2 114 + else 115 + echo "FAIL: ${netns} connection on port $port has ftp helper attached" 1>&2 116 + ret=1 117 + fi 107 118 fi 108 119 109 - echo "PASS: ${netns} connection on port $port has ftp helper attached" 1>&2 110 120 return 0 111 121 } 112 122 113 123 test_helper() 114 124 { 115 125 local port=$1 116 - local msg=$2 126 + local autoassign=$2 127 + 128 + if [ $autoassign -eq 0 ] ;then 129 + msg="set via ruleset" 130 + else 131 + msg="auto-assign" 132 + fi 117 133 118 134 sleep 3 | ip netns exec ${ns2} nc -w 2 -l -p $port > /dev/null & 119 135 120 136 sleep 1 | ip netns exec ${ns1} nc -w 2 10.0.1.2 $port > /dev/null & 121 137 sleep 1 122 138 123 - check_for_helper "$ns1" "ip $msg" $port 124 - check_for_helper "$ns2" "ip $msg" $port 139 + check_for_helper "$ns1" "ip $msg" $port $autoassign 140 + check_for_helper "$ns2" "ip $msg" $port $autoassign 125 141 126 142 wait 127 143 ··· 189 173 fi 190 174 fi 191 175 192 - test_helper 2121 "set via ruleset" 193 - ip netns exec ${ns1} sysctl -q 'net.netfilter.nf_conntrack_helper=1' 194 - ip netns exec ${ns2} sysctl -q 'net.netfilter.nf_conntrack_helper=1' 195 - test_helper 21 "auto-assign" 176 + test_helper 2121 0 177 + ip netns exec ${ns1} sysctl -qe 'net.netfilter.nf_conntrack_helper=1' 178 + ip netns exec ${ns2} sysctl -qe 'net.netfilter.nf_conntrack_helper=1' 179 + test_helper 21 1 196 180 197 181 exit $ret