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

netfilter: remove nf_conntrack_helper sysctl and modparam toggles

__nf_ct_try_assign_helper() remains in place but it now requires a
template to configure the helper.

A toggle to disable automatic helper assignment was added by:

a9006892643a ("netfilter: nf_ct_helper: allow to disable automatic helper assignment")

in 2012 to address the issues described in "Secure use of iptables and
connection tracking helpers". Automatic conntrack helper assignment was
disabled by:

3bb398d925ec ("netfilter: nf_ct_helper: disable automatic helper assignment")

back in 2016.

This patch removes the sysctl and modparam toggles, users now have to
rely on explicit conntrack helper configuration via ruleset.

Update tools/testing/selftests/netfilter/nft_conntrack_helper.sh to
check that auto-assignment does not happen anymore.

Acked-by: Aaron Conole <aconole@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

+37 -107
-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
+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 {
-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
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