Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
authorJakub Kicinski <kuba@kernel.org>
Fri, 3 Sep 2021 23:20:36 +0000 (16:20 -0700)
committerJakub Kicinski <kuba@kernel.org>
Fri, 3 Sep 2021 23:20:37 +0000 (16:20 -0700)
Pablo Neira Ayuso says:

====================
Netfilter fixes for net

1) Protect nft_ct template with global mutex, from Pavel Skripkin.

2) Two recent commits switched inet rt and nexthop exception hashes
   from jhash to siphash. If those two spots are problematic then
   conntrack is affected as well, so switch voer to siphash too.
   While at it, add a hard upper limit on chain lengths and reject
   insertion if this is hit. Patches from Florian Westphal.

3) Fix use-after-scope in nf_socket_ipv6 reported by KASAN,
   from Benjamin Hesmans.

* git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf:
  netfilter: socket: icmp6: fix use-after-scope
  netfilter: refuse insertion if chain has grown too large
  netfilter: conntrack: switch to siphash
  netfilter: conntrack: sanitize table size default settings
  netfilter: nft_ct: protect nft_ct_pcpu_template_refcnt with mutex
====================

Link: https://lore.kernel.org/r/20210903163020.13741-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1  2 
Documentation/networking/nf_conntrack-sysctl.rst
include/uapi/linux/netfilter/nfnetlink_conntrack.h
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c

@@@ -17,9 -17,8 +17,8 @@@ nf_conntrack_acct - BOOLEA
  nf_conntrack_buckets - INTEGER
        Size of hash table. If not specified as parameter during module
        loading, the default size is calculated by dividing total memory
-       by 16384 to determine the number of buckets but the hash table will
-       never have fewer than 32 and limited to 16384 buckets. For systems
-       with more than 4GB of memory it will be 65536 buckets.
+       by 16384 to determine the number of buckets. The hash table will
+       never have fewer than 1024 and never more than 262144 buckets.
        This sysctl is only writeable in the initial net namespace.
  
  nf_conntrack_checksum - BOOLEAN
@@@ -100,8 -99,12 +99,12 @@@ nf_conntrack_log_invalid - INTEGE
        Log invalid packets of a type specified by value.
  
  nf_conntrack_max - INTEGER
-       Size of connection tracking table.  Default value is
-       nf_conntrack_buckets value * 4.
+         Maximum number of allowed connection tracking entries. This value is set
+         to nf_conntrack_buckets by default.
+         Note that connection tracking entries are added to the table twice -- once
+         for the original direction and once for the reply direction (i.e., with
+         the reversed address). This means that with default settings a maxed-out
+         table will have a average hash chain length of 2, not 1.
  
  nf_conntrack_tcp_be_liberal - BOOLEAN
        - 0 - disabled (default)
@@@ -184,13 -187,6 +187,13 @@@ nf_conntrack_gre_timeout_stream - INTEG
        This extended timeout will be used in case there is an GRE stream
        detected.
  
 +nf_hooks_lwtunnel - BOOLEAN
 +      - 0 - disabled (default)
 +      - not 0 - enabled
 +
 +      If this option is enabled, the lightweight tunnel netfilter hooks are
 +      enabled. This option cannot be disabled once it is enabled.
 +
  nf_flowtable_tcp_timeout - INTEGER (seconds)
          default 30
  
@@@ -56,7 -56,6 +56,7 @@@ enum ctattr_type 
        CTA_LABELS_MASK,
        CTA_SYNPROXY,
        CTA_FILTER,
 +      CTA_STATUS_MASK,
        __CTA_MAX
  };
  #define CTA_MAX (__CTA_MAX - 1)
@@@ -258,6 -257,7 +258,7 @@@ enum ctattr_stats_cpu 
        CTA_STATS_ERROR,
        CTA_STATS_SEARCH_RESTART,
        CTA_STATS_CLASH_RESOLVE,
+       CTA_STATS_CHAIN_TOOLONG,
        __CTA_STATS_MAX,
  };
  #define CTA_STATS_MAX (__CTA_STATS_MAX - 1)
@@@ -706,7 -706,7 +706,7 @@@ static size_t ctnetlink_nlmsg_size(cons
  }
  
  static int
 -ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
 +ctnetlink_conntrack_event(unsigned int events, const struct nf_ct_event *item)
  {
        const struct nf_conntrack_zone *zone;
        struct net *net;
@@@ -852,11 -852,6 +852,11 @@@ static int ctnetlink_done(struct netlin
        return 0;
  }
  
 +struct ctnetlink_filter_u32 {
 +      u32 val;
 +      u32 mask;
 +};
 +
  struct ctnetlink_filter {
        u8 family;
  
        struct nf_conntrack_tuple reply;
        struct nf_conntrack_zone zone;
  
 -      struct {
 -              u_int32_t val;
 -              u_int32_t mask;
 -      } mark;
 +      struct ctnetlink_filter_u32 mark;
 +      struct ctnetlink_filter_u32 status;
  };
  
  static const struct nla_policy cta_filter_nla_policy[CTA_FILTER_MAX + 1] = {
@@@ -910,46 -907,6 +910,46 @@@ static int ctnetlink_parse_tuple_filter
                                         struct nf_conntrack_zone *zone,
                                         u_int32_t flags);
  
 +static int ctnetlink_filter_parse_mark(struct ctnetlink_filter_u32 *mark,
 +                                     const struct nlattr * const cda[])
 +{
 +#ifdef CONFIG_NF_CONNTRACK_MARK
 +      if (cda[CTA_MARK]) {
 +              mark->val = ntohl(nla_get_be32(cda[CTA_MARK]));
 +
 +              if (cda[CTA_MARK_MASK])
 +                      mark->mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
 +              else
 +                      mark->mask = 0xffffffff;
 +      } else if (cda[CTA_MARK_MASK]) {
 +              return -EINVAL;
 +      }
 +#endif
 +      return 0;
 +}
 +
 +static int ctnetlink_filter_parse_status(struct ctnetlink_filter_u32 *status,
 +                                       const struct nlattr * const cda[])
 +{
 +      if (cda[CTA_STATUS]) {
 +              status->val = ntohl(nla_get_be32(cda[CTA_STATUS]));
 +              if (cda[CTA_STATUS_MASK])
 +                      status->mask = ntohl(nla_get_be32(cda[CTA_STATUS_MASK]));
 +              else
 +                      status->mask = status->val;
 +
 +              /* status->val == 0? always true, else always false. */
 +              if (status->mask == 0)
 +                      return -EINVAL;
 +      } else if (cda[CTA_STATUS_MASK]) {
 +              return -EINVAL;
 +      }
 +
 +      /* CTA_STATUS is NLA_U32, if this fires UAPI needs to be extended */
 +      BUILD_BUG_ON(__IPS_MAX_BIT >= 32);
 +      return 0;
 +}
 +
  static struct ctnetlink_filter *
  ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
  {
  
        filter->family = family;
  
 -#ifdef CONFIG_NF_CONNTRACK_MARK
 -      if (cda[CTA_MARK]) {
 -              filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
 -              if (cda[CTA_MARK_MASK])
 -                      filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
 -              else
 -                      filter->mark.mask = 0xffffffff;
 -      } else if (cda[CTA_MARK_MASK]) {
 -              err = -EINVAL;
 +      err = ctnetlink_filter_parse_mark(&filter->mark, cda);
 +      if (err)
                goto err_filter;
 -      }
 -#endif
 +
 +      err = ctnetlink_filter_parse_status(&filter->status, cda);
 +      if (err)
 +              goto err_filter;
 +
        if (!cda[CTA_FILTER])
                return filter;
  
@@@ -1028,7 -989,7 +1028,7 @@@ err_filter
  
  static bool ctnetlink_needs_filter(u8 family, const struct nlattr * const *cda)
  {
 -      return family || cda[CTA_MARK] || cda[CTA_FILTER];
 +      return family || cda[CTA_MARK] || cda[CTA_FILTER] || cda[CTA_STATUS];
  }
  
  static int ctnetlink_start(struct netlink_callback *cb)
@@@ -1121,7 -1082,6 +1121,7 @@@ static int ctnetlink_filter_match(struc
  {
        struct ctnetlink_filter *filter = data;
        struct nf_conntrack_tuple *tuple;
 +      u32 status;
  
        if (filter == NULL)
                goto out;
        if ((ct->mark & filter->mark.mask) != filter->mark.val)
                goto ignore_entry;
  #endif
 +      status = (u32)READ_ONCE(ct->status);
 +      if ((status & filter->status.mask) != filter->status.val)
 +              goto ignore_entry;
  
  out:
        return 1;
@@@ -1538,7 -1495,6 +1538,7 @@@ static const struct nla_policy ct_nla_p
        [CTA_LABELS_MASK]       = { .type = NLA_BINARY,
                                    .len = NF_CT_LABELS_MAX_SIZE },
        [CTA_FILTER]            = { .type = NLA_NESTED },
 +      [CTA_STATUS_MASK]       = { .type = NLA_U32 },
  };
  
  static int ctnetlink_flush_iterate(struct nf_conn *ct, void *data)
@@@ -2528,7 -2484,9 +2528,9 @@@ ctnetlink_ct_stat_cpu_fill_info(struct 
            nla_put_be32(skb, CTA_STATS_SEARCH_RESTART,
                                htonl(st->search_restart)) ||
            nla_put_be32(skb, CTA_STATS_CLASH_RESOLVE,
-                               htonl(st->clash_resolve)))
+                               htonl(st->clash_resolve)) ||
+           nla_put_be32(skb, CTA_STATS_CHAIN_TOOLONG,
+                        htonl(st->chaintoolong)))
                goto nla_put_failure;
  
        nlmsg_end(skb, nlh);
@@@ -2669,8 -2627,6 +2671,8 @@@ ctnetlink_glue_build_size(const struct 
               + nla_total_size(0) /* CTA_HELP */
               + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
               + ctnetlink_secctx_size(ct)
 +             + ctnetlink_acct_size(ct)
 +             + ctnetlink_timestamp_size(ct)
  #if IS_ENABLED(CONFIG_NF_NAT)
               + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
               + 6 * nla_total_size(sizeof(u_int32_t)) /* CTA_NAT_SEQ_OFFSET */
@@@ -2728,10 -2684,6 +2730,10 @@@ static int __ctnetlink_glue_build(struc
        if (ctnetlink_dump_protoinfo(skb, ct, false) < 0)
                goto nla_put_failure;
  
 +      if (ctnetlink_dump_acct(skb, ct, IPCTNL_MSG_CT_GET) < 0 ||
 +          ctnetlink_dump_timestamp(skb, ct) < 0)
 +              goto nla_put_failure;
 +
        if (ctnetlink_dump_helpinfo(skb, ct) < 0)
                goto nla_put_failure;
  
@@@ -3110,7 -3062,7 +3112,7 @@@ nla_put_failure
  
  #ifdef CONFIG_NF_CONNTRACK_EVENTS
  static int
 -ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
 +ctnetlink_expect_event(unsigned int events, const struct nf_exp_event *item)
  {
        struct nf_conntrack_expect *exp = item->exp;
        struct net *net = nf_ct_exp_net(exp);
@@@ -3761,8 -3713,11 +3763,8 @@@ static int ctnetlink_stat_exp_cpu(struc
  
  #ifdef CONFIG_NF_CONNTRACK_EVENTS
  static struct nf_ct_event_notifier ctnl_notifier = {
 -      .fcn = ctnetlink_conntrack_event,
 -};
 -
 -static struct nf_exp_event_notifier ctnl_notifier_exp = {
 -      .fcn = ctnetlink_expect_event,
 +      .ct_event = ctnetlink_conntrack_event,
 +      .exp_event = ctnetlink_expect_event,
  };
  #endif
  
@@@ -3855,21 -3810,52 +3857,21 @@@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CT
  static int __net_init ctnetlink_net_init(struct net *net)
  {
  #ifdef CONFIG_NF_CONNTRACK_EVENTS
 -      int ret;
 -
 -      ret = nf_conntrack_register_notifier(net, &ctnl_notifier);
 -      if (ret < 0) {
 -              pr_err("ctnetlink_init: cannot register notifier.\n");
 -              goto err_out;
 -      }
 -
 -      ret = nf_ct_expect_register_notifier(net, &ctnl_notifier_exp);
 -      if (ret < 0) {
 -              pr_err("ctnetlink_init: cannot expect register notifier.\n");
 -              goto err_unreg_notifier;
 -      }
 +      nf_conntrack_register_notifier(net, &ctnl_notifier);
  #endif
        return 0;
 -
 -#ifdef CONFIG_NF_CONNTRACK_EVENTS
 -err_unreg_notifier:
 -      nf_conntrack_unregister_notifier(net, &ctnl_notifier);
 -err_out:
 -      return ret;
 -#endif
  }
  
 -static void ctnetlink_net_exit(struct net *net)
 +static void ctnetlink_net_pre_exit(struct net *net)
  {
  #ifdef CONFIG_NF_CONNTRACK_EVENTS
 -      nf_ct_expect_unregister_notifier(net, &ctnl_notifier_exp);
 -      nf_conntrack_unregister_notifier(net, &ctnl_notifier);
 +      nf_conntrack_unregister_notifier(net);
  #endif
  }
  
 -static void __net_exit ctnetlink_net_exit_batch(struct list_head *net_exit_list)
 -{
 -      struct net *net;
 -
 -      list_for_each_entry(net, net_exit_list, exit_list)
 -              ctnetlink_net_exit(net);
 -
 -      /* wait for other cpus until they are done with ctnl_notifiers */
 -      synchronize_rcu();
 -}
 -
  static struct pernet_operations ctnetlink_net_ops = {
        .init           = ctnetlink_net_init,
 -      .exit_batch     = ctnetlink_net_exit_batch,
 +      .pre_exit       = ctnetlink_net_pre_exit,
  };
  
  static int __init ctnetlink_init(void)
@@@ -22,9 -22,6 +22,9 @@@
  #include <net/netfilter/nf_conntrack_acct.h>
  #include <net/netfilter/nf_conntrack_zones.h>
  #include <net/netfilter/nf_conntrack_timestamp.h>
 +#ifdef CONFIG_LWTUNNEL
 +#include <net/netfilter/nf_hooks_lwtunnel.h>
 +#endif
  #include <linux/rculist_nulls.h>
  
  static bool enable_hooks __read_mostly;
@@@ -432,7 -429,7 +432,7 @@@ static int ct_cpu_seq_show(struct seq_f
        unsigned int nr_conntracks;
  
        if (v == SEQ_START_TOKEN) {
-               seq_puts(seq, "entries  clashres found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete search_restart\n");
+               seq_puts(seq, "entries  clashres found new invalid ignore delete chainlength insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete search_restart\n");
                return 0;
        }
  
                   st->invalid,
                   0,
                   0,
-                  0,
+                  st->chaintoolong,
                   st->insert,
                   st->insert_failed,
                   st->drop,
@@@ -615,9 -612,6 +615,9 @@@ enum nf_ct_sysctl_index 
        NF_SYSCTL_CT_PROTO_TIMEOUT_GRE,
        NF_SYSCTL_CT_PROTO_TIMEOUT_GRE_STREAM,
  #endif
 +#ifdef CONFIG_LWTUNNEL
 +      NF_SYSCTL_CT_LWTUNNEL,
 +#endif
  
        __NF_SYSCTL_CT_LAST_SYSCTL,
  };
@@@ -965,15 -959,6 +965,15 @@@ static struct ctl_table nf_ct_sysctl_ta
                .proc_handler   = proc_dointvec_jiffies,
        },
  #endif
 +#ifdef CONFIG_LWTUNNEL
 +      [NF_SYSCTL_CT_LWTUNNEL] = {
 +              .procname       = "nf_hooks_lwtunnel",
 +              .data           = NULL,
 +              .maxlen         = sizeof(int),
 +              .mode           = 0644,
 +              .proc_handler   = nf_hooks_lwtunnel_sysctl_handler,
 +      },
 +#endif
        {}
  };