]> Git Repo - linux.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
authorJakub Kicinski <[email protected]>
Thu, 23 Feb 2023 05:25:23 +0000 (21:25 -0800)
committerJakub Kicinski <[email protected]>
Thu, 23 Feb 2023 05:25:23 +0000 (21:25 -0800)
Pablo Neira Ayuso says:

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

1) Fix broken listing of set elements when table has an owner.

2) Fix conntrack refcount leak in ctnetlink with related conntrack
   entries, from Hangyu Hua.

3) Fix use-after-free/double-free in ctnetlink conntrack insert path,
   from Florian Westphal.

4) Fix ip6t_rpfilter with VRF, from Phil Sutter.

5) Fix use-after-free in ebtables reported by syzbot, also from Florian.

6) Use skb->len in xt_length to deal with IPv6 jumbo packets,
   from Xin Long.

7) Fix NETLINK_LISTEN_ALL_NSID with ctnetlink, from Florian Westphal.

8) Fix memleak in {ip_,ip6_,arp_}tables in ENOMEM error case,
   from Pavel Tikhomirov.

* git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: x_tables: fix percpu counter block leak on error path when creating new netns
  netfilter: ctnetlink: make event listener tracking global
  netfilter: xt_length: use skb len to match in length_mt6
  netfilter: ebtables: fix table blob use-after-free
  netfilter: ip6t_rpfilter: Fix regression with VRF interfaces
  netfilter: conntrack: fix rmmod double-free race
  netfilter: ctnetlink: fix possible refcount leak in ctnetlink_create_conntrack()
  netfilter: nf_tables: allow to fetch set elements when table has an owner
====================

Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Jakub Kicinski <[email protected]>
1  2 
include/linux/netfilter.h
net/netfilter/core.c
net/netfilter/nf_conntrack_bpf.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_tables_api.c
net/netfilter/xt_length.c

index 6863e271a9deda135318f0b6b31b6b936bc84792,bef8db9d6c0859e3b96fca75fcac7c84b65e91e3..c8e03bcaecaaa8f4c12e89fe1ce40648681a6d3e
@@@ -437,13 -437,11 +437,13 @@@ nf_nat_decode_session(struct sk_buff *s
  #include <linux/netfilter/nf_conntrack_zones_common.h>
  
  void nf_ct_attach(struct sk_buff *, const struct sk_buff *);
 +void nf_ct_set_closing(struct nf_conntrack *nfct);
  struct nf_conntrack_tuple;
  bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
                         const struct sk_buff *skb);
  #else
  static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
 +static inline void nf_ct_set_closing(struct nf_conntrack *nfct) {}
  struct nf_conntrack_tuple;
  static inline bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
                                       const struct sk_buff *skb)
@@@ -461,7 -459,6 +461,7 @@@ struct nf_ct_hook 
        bool (*get_tuple_skb)(struct nf_conntrack_tuple *,
                              const struct sk_buff *);
        void (*attach)(struct sk_buff *nskb, const struct sk_buff *skb);
 +      void (*set_closing)(struct nf_conntrack *nfct);
  };
  extern const struct nf_ct_hook __rcu *nf_ct_hook;
  
@@@ -491,4 -488,9 +491,9 @@@ extern const struct nfnl_ct_hook __rcu 
   */
  DECLARE_PER_CPU(bool, nf_skb_duplicated);
  
+ /**
+  * Contains bitmask of ctnetlink event subscribers, if any.
+  * Can't be pernet due to NETLINK_LISTEN_ALL_NSID setsockopt flag.
+  */
+ extern u8 nf_ctnetlink_has_listener;
  #endif /*__LINUX_NETFILTER_H*/
diff --combined net/netfilter/core.c
index b2fdbbed2b4b7a4167400cc5538bba2650e99cb0,6e80f0f6149ea2b38822449c2603975352a67b96..358220b585215109ead54f198589bc4ae92f2d3d
@@@ -669,6 -669,9 +669,9 @@@ const struct nf_ct_hook __rcu *nf_ct_ho
  EXPORT_SYMBOL_GPL(nf_ct_hook);
  
  #if IS_ENABLED(CONFIG_NF_CONNTRACK)
+ u8 nf_ctnetlink_has_listener;
+ EXPORT_SYMBOL_GPL(nf_ctnetlink_has_listener);
  const struct nf_nat_hook __rcu *nf_nat_hook __read_mostly;
  EXPORT_SYMBOL_GPL(nf_nat_hook);
  
@@@ -702,22 -705,6 +705,22 @@@ void nf_conntrack_destroy(struct nf_con
  }
  EXPORT_SYMBOL(nf_conntrack_destroy);
  
 +void nf_ct_set_closing(struct nf_conntrack *nfct)
 +{
 +      const struct nf_ct_hook *ct_hook;
 +
 +      if (!nfct)
 +              return;
 +
 +      rcu_read_lock();
 +      ct_hook = rcu_dereference(nf_ct_hook);
 +      if (ct_hook)
 +              ct_hook->set_closing(nfct);
 +
 +      rcu_read_unlock();
 +}
 +EXPORT_SYMBOL_GPL(nf_ct_set_closing);
 +
  bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
                         const struct sk_buff *skb)
  {
index 34913521c385ab683d3c442daa32f46236d1e576,e1af14e3b63c50f7795f4512c41dfd7be4890f71..cd99e6dc1f35c2767d5166eb13849935838ee413
@@@ -249,7 -249,7 +249,7 @@@ __diag_ignore_all("-Wmissing-prototypes
   * @opts__sz  - Length of the bpf_ct_opts structure
   *                Must be NF_BPF_CT_OPTS_SZ (12)
   */
 -struct nf_conn___init *
 +__bpf_kfunc struct nf_conn___init *
  bpf_xdp_ct_alloc(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple,
                 u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz)
  {
   * @opts__sz  - Length of the bpf_ct_opts structure
   *                Must be NF_BPF_CT_OPTS_SZ (12)
   */
 -struct nf_conn *
 +__bpf_kfunc struct nf_conn *
  bpf_xdp_ct_lookup(struct xdp_md *xdp_ctx, struct bpf_sock_tuple *bpf_tuple,
                  u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz)
  {
   * @opts__sz  - Length of the bpf_ct_opts structure
   *                Must be NF_BPF_CT_OPTS_SZ (12)
   */
 -struct nf_conn___init *
 +__bpf_kfunc struct nf_conn___init *
  bpf_skb_ct_alloc(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple,
                 u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz)
  {
   * @opts__sz  - Length of the bpf_ct_opts structure
   *                Must be NF_BPF_CT_OPTS_SZ (12)
   */
 -struct nf_conn *
 +__bpf_kfunc struct nf_conn *
  bpf_skb_ct_lookup(struct __sk_buff *skb_ctx, struct bpf_sock_tuple *bpf_tuple,
                  u32 tuple__sz, struct bpf_ct_opts *opts, u32 opts__sz)
  {
   * @nfct       - Pointer to referenced nf_conn___init object, obtained
   *               using bpf_xdp_ct_alloc or bpf_skb_ct_alloc.
   */
 -struct nf_conn *bpf_ct_insert_entry(struct nf_conn___init *nfct_i)
 +__bpf_kfunc struct nf_conn *bpf_ct_insert_entry(struct nf_conn___init *nfct_i)
  {
        struct nf_conn *nfct = (struct nf_conn *)nfct_i;
        int err;
  
-       nfct->status |= IPS_CONFIRMED;
        err = nf_conntrack_hash_check_insert(nfct);
        if (err < 0) {
                nf_conntrack_free(nfct);
   * @nf_conn    - Pointer to referenced nf_conn object, obtained using
   *               bpf_xdp_ct_lookup or bpf_skb_ct_lookup.
   */
 -void bpf_ct_release(struct nf_conn *nfct)
 +__bpf_kfunc void bpf_ct_release(struct nf_conn *nfct)
  {
        if (!nfct)
                return;
   *                 bpf_xdp_ct_alloc or bpf_skb_ct_alloc.
   * @timeout      - Timeout in msecs.
   */
 -void bpf_ct_set_timeout(struct nf_conn___init *nfct, u32 timeout)
 +__bpf_kfunc void bpf_ct_set_timeout(struct nf_conn___init *nfct, u32 timeout)
  {
        __nf_ct_set_timeout((struct nf_conn *)nfct, msecs_to_jiffies(timeout));
  }
   *               bpf_ct_insert_entry, bpf_xdp_ct_lookup, or bpf_skb_ct_lookup.
   * @timeout      - New timeout in msecs.
   */
 -int bpf_ct_change_timeout(struct nf_conn *nfct, u32 timeout)
 +__bpf_kfunc int bpf_ct_change_timeout(struct nf_conn *nfct, u32 timeout)
  {
        return __nf_ct_change_timeout(nfct, msecs_to_jiffies(timeout));
  }
   *               bpf_xdp_ct_alloc or bpf_skb_ct_alloc.
   * @status       - New status value.
   */
 -int bpf_ct_set_status(const struct nf_conn___init *nfct, u32 status)
 +__bpf_kfunc int bpf_ct_set_status(const struct nf_conn___init *nfct, u32 status)
  {
        return nf_ct_change_status_common((struct nf_conn *)nfct, status);
  }
   *               bpf_ct_insert_entry, bpf_xdp_ct_lookup or bpf_skb_ct_lookup.
   * @status       - New status value.
   */
 -int bpf_ct_change_status(struct nf_conn *nfct, u32 status)
 +__bpf_kfunc int bpf_ct_change_status(struct nf_conn *nfct, u32 status)
  {
        return nf_ct_change_status_common(nfct, status);
  }
index 70c4f892174ed87b9c5df26e3e9d5fcea8b2fef7,ead11a9c261f38856ff47b47aa31fa6ad33cff15..7250082e7de56c77298b0d3b62c4f0dff95b77cc
@@@ -514,6 -514,7 +514,6 @@@ EXPORT_SYMBOL_GPL(nf_ct_get_id)
  static void
  clean_from_lists(struct nf_conn *ct)
  {
 -      pr_debug("clean_from_lists(%p)\n", ct);
        hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode);
        hlist_nulls_del_rcu(&ct->tuplehash[IP_CT_DIR_REPLY].hnnode);
  
@@@ -581,6 -582,7 +581,6 @@@ void nf_ct_destroy(struct nf_conntrack 
  {
        struct nf_conn *ct = (struct nf_conn *)nfct;
  
 -      pr_debug("%s(%p)\n", __func__, ct);
        WARN_ON(refcount_read(&nfct->use) != 0);
  
        if (unlikely(nf_ct_is_template(ct))) {
        if (ct->master)
                nf_ct_put(ct->master);
  
 -      pr_debug("%s: returning ct=%p to slab\n", __func__, ct);
        nf_conntrack_free(ct);
  }
  EXPORT_SYMBOL(nf_ct_destroy);
@@@ -783,6 -786,8 +783,6 @@@ __nf_conntrack_find_get(struct net *net
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct;
  
 -      rcu_read_lock();
 -
        h = ____nf_conntrack_find(net, zone, tuple, hash);
        if (h) {
                /* We have a candidate that matches the tuple we're interested
                        smp_acquire__after_ctrl_dep();
  
                        if (likely(nf_ct_key_equal(h, tuple, zone, net)))
 -                              goto found;
 +                              return h;
  
                        /* TYPESAFE_BY_RCU recycled the candidate */
                        nf_ct_put(ct);
  
                h = NULL;
        }
 -found:
 -      rcu_read_unlock();
  
        return h;
  }
@@@ -813,21 -820,16 +813,21 @@@ nf_conntrack_find_get(struct net *net, 
        unsigned int rid, zone_id = nf_ct_zone_id(zone, IP_CT_DIR_ORIGINAL);
        struct nf_conntrack_tuple_hash *thash;
  
 +      rcu_read_lock();
 +
        thash = __nf_conntrack_find_get(net, zone, tuple,
                                        hash_conntrack_raw(tuple, zone_id, net));
  
        if (thash)
 -              return thash;
 +              goto out_unlock;
  
        rid = nf_ct_zone_id(zone, IP_CT_DIR_REPLY);
        if (rid != zone_id)
 -              return __nf_conntrack_find_get(net, zone, tuple,
 -                                             hash_conntrack_raw(tuple, rid, net));
 +              thash = __nf_conntrack_find_get(net, zone, tuple,
 +                                              hash_conntrack_raw(tuple, rid, net));
 +
 +out_unlock:
 +      rcu_read_unlock();
        return thash;
  }
  EXPORT_SYMBOL_GPL(nf_conntrack_find_get);
@@@ -884,10 -886,8 +884,8 @@@ nf_conntrack_hash_check_insert(struct n
  
        zone = nf_ct_zone(ct);
  
-       if (!nf_ct_ext_valid_pre(ct->ext)) {
-               NF_CT_STAT_INC_ATOMIC(net, insert_failed);
-               return -ETIMEDOUT;
-       }
+       if (!nf_ct_ext_valid_pre(ct->ext))
+               return -EAGAIN;
  
        local_bh_disable();
        do {
                        goto chaintoolong;
        }
  
+       /* If genid has changed, we can't insert anymore because ct
+        * extensions could have stale pointers and nf_ct_iterate_destroy
+        * might have completed its table scan already.
+        *
+        * Increment of the ext genid right after this check is fine:
+        * nf_ct_iterate_destroy blocks until locks are released.
+        */
+       if (!nf_ct_ext_valid_post(ct->ext)) {
+               err = -EAGAIN;
+               goto out;
+       }
+       ct->status |= IPS_CONFIRMED;
        smp_wmb();
        /* The caller holds a reference to this object */
        refcount_set(&ct->ct_general.use, 2);
        NF_CT_STAT_INC(net, insert);
        local_bh_enable();
  
-       if (!nf_ct_ext_valid_post(ct->ext)) {
-               nf_ct_kill(ct);
-               NF_CT_STAT_INC_ATOMIC(net, drop);
-               return -ETIMEDOUT;
-       }
        return 0;
  chaintoolong:
        NF_CT_STAT_INC(net, chaintoolong);
@@@ -1208,6 -1215,7 +1213,6 @@@ __nf_conntrack_confirm(struct sk_buff *
                goto dying;
        }
  
 -      pr_debug("Confirming conntrack %p\n", ct);
        /* We have to check the DYING flag after unlink to prevent
         * a race against nf_ct_get_next_corpse() possibly called from
         * user context, else we insert an already 'dead' hash, blocking
@@@ -1371,6 -1379,9 +1376,6 @@@ static unsigned int early_drop_list(str
        hlist_nulls_for_each_entry_rcu(h, n, head, hnnode) {
                tmp = nf_ct_tuplehash_to_ctrack(h);
  
 -              if (test_bit(IPS_OFFLOAD_BIT, &tmp->status))
 -                      continue;
 -
                if (nf_ct_is_expired(tmp)) {
                        nf_ct_gc_expired(tmp);
                        continue;
@@@ -1440,14 -1451,11 +1445,14 @@@ static bool gc_worker_skip_ct(const str
  static bool gc_worker_can_early_drop(const struct nf_conn *ct)
  {
        const struct nf_conntrack_l4proto *l4proto;
 +      u8 protonum = nf_ct_protonum(ct);
  
 +      if (test_bit(IPS_OFFLOAD_BIT, &ct->status) && protonum != IPPROTO_UDP)
 +              return false;
        if (!test_bit(IPS_ASSURED_BIT, &ct->status))
                return true;
  
 -      l4proto = nf_ct_l4proto_find(nf_ct_protonum(ct));
 +      l4proto = nf_ct_l4proto_find(protonum);
        if (l4proto->can_early_drop && l4proto->can_early_drop(ct))
                return true;
  
@@@ -1504,8 -1512,7 +1509,8 @@@ static void gc_worker(struct work_struc
  
                        if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) {
                                nf_ct_offload_timeout(tmp);
 -                              continue;
 +                              if (!nf_conntrack_max95)
 +                                      continue;
                        }
  
                        if (expired_count > GC_SCAN_EXPIRED_MAX) {
@@@ -1719,8 -1726,10 +1724,8 @@@ init_conntrack(struct net *net, struct 
        struct nf_conntrack_zone tmp;
        struct nf_conntrack_net *cnet;
  
 -      if (!nf_ct_invert_tuple(&repl_tuple, tuple)) {
 -              pr_debug("Can't invert tuple.\n");
 +      if (!nf_ct_invert_tuple(&repl_tuple, tuple))
                return NULL;
 -      }
  
        zone = nf_ct_zone_tmpl(tmpl, skb, &tmp);
        ct = __nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC,
                spin_lock_bh(&nf_conntrack_expect_lock);
                exp = nf_ct_find_expectation(net, zone, tuple);
                if (exp) {
 -                      pr_debug("expectation arrives ct=%p exp=%p\n",
 -                               ct, exp);
                        /* Welcome, Mr. Bond.  We've been expecting you... */
                        __set_bit(IPS_EXPECTED_BIT, &ct->status);
                        /* exp->master safe, refcnt bumped in nf_ct_find_expectation */
@@@ -1823,8 -1834,10 +1828,8 @@@ resolve_normal_ct(struct nf_conn *tmpl
  
        if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
                             dataoff, state->pf, protonum, state->net,
 -                           &tuple)) {
 -              pr_debug("Can't get tuple\n");
 +                           &tuple))
                return 0;
 -      }
  
        /* look for tuple match */
        zone = nf_ct_zone_tmpl(tmpl, skb, &tmp);
        if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) {
                ctinfo = IP_CT_ESTABLISHED_REPLY;
        } else {
 +              unsigned long status = READ_ONCE(ct->status);
 +
                /* Once we've had two way comms, always ESTABLISHED. */
 -              if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
 -                      pr_debug("normal packet for %p\n", ct);
 +              if (likely(status & IPS_SEEN_REPLY))
                        ctinfo = IP_CT_ESTABLISHED;
 -              } else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
 -                      pr_debug("related packet for %p\n", ct);
 +              else if (status & IPS_EXPECTED)
                        ctinfo = IP_CT_RELATED;
 -              } else {
 -                      pr_debug("new packet for %p\n", ct);
 +              else
                        ctinfo = IP_CT_NEW;
 -              }
        }
        nf_ct_set(skb, ct, ctinfo);
        return 0;
@@@ -1978,6 -1993,7 +1983,6 @@@ nf_conntrack_in(struct sk_buff *skb, co
        /* rcu_read_lock()ed by nf_hook_thresh */
        dataoff = get_l4proto(skb, skb_network_offset(skb), state->pf, &protonum);
        if (dataoff <= 0) {
 -              pr_debug("not prepared to track yet or error occurred\n");
                NF_CT_STAT_INC_ATOMIC(state->net, invalid);
                ret = NF_ACCEPT;
                goto out;
@@@ -2016,6 -2032,7 +2021,6 @@@ repeat
        if (ret <= 0) {
                /* Invalid: inverse of the return code tells
                 * the netfilter core what to do */
 -              pr_debug("nf_conntrack_in: Can't track with proto module\n");
                nf_ct_put(ct);
                skb->_nfct = 0;
                /* Special case: TCP tracker reports an attempt to reopen a
@@@ -2054,6 -2071,7 +2059,6 @@@ void nf_conntrack_alter_reply(struct nf
        /* Should be unconfirmed, so not in hash table yet */
        WARN_ON(nf_ct_is_confirmed(ct));
  
 -      pr_debug("Altering reply tuple of %p to ", ct);
        nf_ct_dump_tuple(newreply);
  
        ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
@@@ -2748,23 -2766,11 +2753,23 @@@ err_cachep
        return ret;
  }
  
 +static void nf_conntrack_set_closing(struct nf_conntrack *nfct)
 +{
 +      struct nf_conn *ct = nf_ct_to_nf_conn(nfct);
 +
 +      switch (nf_ct_protonum(ct)) {
 +      case IPPROTO_TCP:
 +              nf_conntrack_tcp_set_closing(ct);
 +              break;
 +      }
 +}
 +
  static const struct nf_ct_hook nf_conntrack_hook = {
        .update         = nf_conntrack_update,
        .destroy        = nf_ct_destroy,
        .get_tuple_skb  = nf_conntrack_get_tuple_skb,
        .attach         = nf_conntrack_attach,
 +      .set_closing    = nf_conntrack_set_closing,
  };
  
  void nf_conntrack_init_end(void)
index 308fc0023c7ea83f3c95e5a03390f96ba3787b1b,733bb56950c1422da3d7ca272f25082dfd07f710..c11dff91d52d2795f72dbc628259275489b1b1a2
@@@ -2316,9 -2316,6 +2316,6 @@@ ctnetlink_create_conntrack(struct net *
        nfct_seqadj_ext_add(ct);
        nfct_synproxy_ext_add(ct);
  
-       /* we must add conntrack extensions before confirmation. */
-       ct->status |= IPS_CONFIRMED;
        if (cda[CTA_STATUS]) {
                err = ctnetlink_change_status(ct, cda);
                if (err < 0)
  
        err = nf_conntrack_hash_check_insert(ct);
        if (err < 0)
-               goto err2;
+               goto err3;
  
        rcu_read_unlock();
  
        return ct;
  
+ err3:
+       if (ct->master)
+               nf_ct_put(ct->master);
  err2:
        rcu_read_unlock();
  err1:
@@@ -3866,7 -3866,7 +3866,7 @@@ static int __init ctnetlink_init(void
  {
        int ret;
  
 -      BUILD_BUG_ON(sizeof(struct ctnetlink_list_dump_ctx) > sizeof_field(struct netlink_callback, ctx));
 +      NL_ASSERT_DUMP_CTX_FITS(struct ctnetlink_list_dump_ctx);
  
        ret = nfnetlink_subsys_register(&ctnl_subsys);
        if (ret < 0) {
index d73edbd4eec450451a134a94678e278b86fda700,820c602d655e73e25070038075f1922cf8263dcf..6004d4b244518b540302ca48264068a507c2306b
@@@ -1401,10 -1401,6 +1401,10 @@@ static int nf_tables_deltable(struct sk
        }
  
        if (IS_ERR(table)) {
 +              if (PTR_ERR(table) == -ENOENT &&
 +                  NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYTABLE)
 +                      return 0;
 +
                NL_SET_BAD_ATTR(extack, attr);
                return PTR_ERR(table);
        }
@@@ -2643,10 -2639,6 +2643,10 @@@ static int nf_tables_delchain(struct sk
                chain = nft_chain_lookup(net, table, attr, genmask);
        }
        if (IS_ERR(chain)) {
 +              if (PTR_ERR(chain) == -ENOENT &&
 +                  NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYCHAIN)
 +                      return 0;
 +
                NL_SET_BAD_ATTR(extack, attr);
                return PTR_ERR(chain);
        }
@@@ -3724,10 -3716,6 +3724,10 @@@ static int nf_tables_delrule(struct sk_
                chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
                                         genmask);
                if (IS_ERR(chain)) {
 +                      if (PTR_ERR(chain) == -ENOENT &&
 +                          NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
 +                              return 0;
 +
                        NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
                        return PTR_ERR(chain);
                }
                if (nla[NFTA_RULE_HANDLE]) {
                        rule = nft_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
                        if (IS_ERR(rule)) {
 +                              if (PTR_ERR(rule) == -ENOENT &&
 +                                  NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
 +                                      return 0;
 +
                                NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_HANDLE]);
                                return PTR_ERR(rule);
                        }
@@@ -4824,10 -4808,6 +4824,10 @@@ static int nf_tables_delset(struct sk_b
        }
  
        if (IS_ERR(set)) {
 +              if (PTR_ERR(set) == -ENOENT &&
 +                  NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSET)
 +                      return 0;
 +
                NL_SET_BAD_ATTR(extack, attr);
                return PTR_ERR(set);
        }
@@@ -5507,7 -5487,7 +5507,7 @@@ static int nf_tables_getsetelem(struct 
        int rem, err = 0;
  
        table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
-                                genmask, NETLINK_CB(skb).portid);
+                                genmask, 0);
        if (IS_ERR(table)) {
                NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]);
                return PTR_ERR(table);
@@@ -6710,10 -6690,6 +6710,10 @@@ static int nf_tables_delsetelem(struct 
  
        nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
                err = nft_del_setelem(&ctx, set, attr);
 +              if (err == -ENOENT &&
 +                  NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYSETELEM)
 +                      continue;
 +
                if (err < 0) {
                        NL_SET_BAD_ATTR(extack, attr);
                        break;
@@@ -7023,9 -6999,6 +7023,9 @@@ static int nf_tables_newobj(struct sk_b
                        return -EOPNOTSUPP;
  
                type = __nft_obj_type_get(objtype);
 +              if (WARN_ON_ONCE(!type))
 +                      return -ENOENT;
 +
                nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
  
                return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj);
@@@ -7361,10 -7334,6 +7361,10 @@@ static int nf_tables_delobj(struct sk_b
        }
  
        if (IS_ERR(obj)) {
 +              if (PTR_ERR(obj) == -ENOENT &&
 +                  NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYOBJ)
 +                      return 0;
 +
                NL_SET_BAD_ATTR(extack, attr);
                return PTR_ERR(obj);
        }
@@@ -7995,10 -7964,6 +7995,10 @@@ static int nf_tables_delflowtable(struc
        }
  
        if (IS_ERR(flowtable)) {
 +              if (PTR_ERR(flowtable) == -ENOENT &&
 +                  NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYFLOWTABLE)
 +                      return 0;
 +
                NL_SET_BAD_ATTR(extack, attr);
                return PTR_ERR(flowtable);
        }
@@@ -8408,12 -8373,6 +8408,12 @@@ static const struct nfnl_callback nf_ta
                .attr_count     = NFTA_TABLE_MAX,
                .policy         = nft_table_policy,
        },
 +      [NFT_MSG_DESTROYTABLE] = {
 +              .call           = nf_tables_deltable,
 +              .type           = NFNL_CB_BATCH,
 +              .attr_count     = NFTA_TABLE_MAX,
 +              .policy         = nft_table_policy,
 +      },
        [NFT_MSG_NEWCHAIN] = {
                .call           = nf_tables_newchain,
                .type           = NFNL_CB_BATCH,
                .attr_count     = NFTA_CHAIN_MAX,
                .policy         = nft_chain_policy,
        },
 +      [NFT_MSG_DESTROYCHAIN] = {
 +              .call           = nf_tables_delchain,
 +              .type           = NFNL_CB_BATCH,
 +              .attr_count     = NFTA_CHAIN_MAX,
 +              .policy         = nft_chain_policy,
 +      },
        [NFT_MSG_NEWRULE] = {
                .call           = nf_tables_newrule,
                .type           = NFNL_CB_BATCH,
                .attr_count     = NFTA_RULE_MAX,
                .policy         = nft_rule_policy,
        },
 +      [NFT_MSG_DESTROYRULE] = {
 +              .call           = nf_tables_delrule,
 +              .type           = NFNL_CB_BATCH,
 +              .attr_count     = NFTA_RULE_MAX,
 +              .policy         = nft_rule_policy,
 +      },
        [NFT_MSG_NEWSET] = {
                .call           = nf_tables_newset,
                .type           = NFNL_CB_BATCH,
                .attr_count     = NFTA_SET_MAX,
                .policy         = nft_set_policy,
        },
 +      [NFT_MSG_DESTROYSET] = {
 +              .call           = nf_tables_delset,
 +              .type           = NFNL_CB_BATCH,
 +              .attr_count     = NFTA_SET_MAX,
 +              .policy         = nft_set_policy,
 +      },
        [NFT_MSG_NEWSETELEM] = {
                .call           = nf_tables_newsetelem,
                .type           = NFNL_CB_BATCH,
                .attr_count     = NFTA_SET_ELEM_LIST_MAX,
                .policy         = nft_set_elem_list_policy,
        },
 +      [NFT_MSG_DESTROYSETELEM] = {
 +              .call           = nf_tables_delsetelem,
 +              .type           = NFNL_CB_BATCH,
 +              .attr_count     = NFTA_SET_ELEM_LIST_MAX,
 +              .policy         = nft_set_elem_list_policy,
 +      },
        [NFT_MSG_GETGEN] = {
                .call           = nf_tables_getgen,
                .type           = NFNL_CB_RCU,
                .attr_count     = NFTA_OBJ_MAX,
                .policy         = nft_obj_policy,
        },
 +      [NFT_MSG_DESTROYOBJ] = {
 +              .call           = nf_tables_delobj,
 +              .type           = NFNL_CB_BATCH,
 +              .attr_count     = NFTA_OBJ_MAX,
 +              .policy         = nft_obj_policy,
 +      },
        [NFT_MSG_GETOBJ_RESET] = {
                .call           = nf_tables_getobj,
                .type           = NFNL_CB_RCU,
                .attr_count     = NFTA_FLOWTABLE_MAX,
                .policy         = nft_flowtable_policy,
        },
 +      [NFT_MSG_DESTROYFLOWTABLE] = {
 +              .call           = nf_tables_delflowtable,
 +              .type           = NFNL_CB_BATCH,
 +              .attr_count     = NFTA_FLOWTABLE_MAX,
 +              .policy         = nft_flowtable_policy,
 +      },
  };
  
  static int nf_tables_validate(struct net *net)
@@@ -8667,7 -8590,6 +8667,7 @@@ static void nft_commit_release(struct n
  {
        switch (trans->msg_type) {
        case NFT_MSG_DELTABLE:
 +      case NFT_MSG_DESTROYTABLE:
                nf_tables_table_destroy(&trans->ctx);
                break;
        case NFT_MSG_NEWCHAIN:
                kfree(nft_trans_chain_name(trans));
                break;
        case NFT_MSG_DELCHAIN:
 +      case NFT_MSG_DESTROYCHAIN:
                nf_tables_chain_destroy(&trans->ctx);
                break;
        case NFT_MSG_DELRULE:
 +      case NFT_MSG_DESTROYRULE:
                nf_tables_rule_destroy(&trans->ctx, nft_trans_rule(trans));
                break;
        case NFT_MSG_DELSET:
 +      case NFT_MSG_DESTROYSET:
                nft_set_destroy(&trans->ctx, nft_trans_set(trans));
                break;
        case NFT_MSG_DELSETELEM:
 +      case NFT_MSG_DESTROYSETELEM:
                nf_tables_set_elem_destroy(&trans->ctx,
                                           nft_trans_elem_set(trans),
                                           nft_trans_elem(trans).priv);
                break;
        case NFT_MSG_DELOBJ:
 +      case NFT_MSG_DESTROYOBJ:
                nft_obj_destroy(&trans->ctx, nft_trans_obj(trans));
                break;
        case NFT_MSG_DELFLOWTABLE:
 +      case NFT_MSG_DESTROYFLOWTABLE:
                if (nft_trans_flowtable_update(trans))
                        nft_flowtable_hooks_destroy(&nft_trans_flowtable_hooks(trans));
                else
@@@ -9149,9 -9065,8 +9149,9 @@@ static int nf_tables_commit(struct net 
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELTABLE:
 +              case NFT_MSG_DESTROYTABLE:
                        list_del_rcu(&trans->ctx.table->list);
 -                      nf_tables_table_notify(&trans->ctx, NFT_MSG_DELTABLE);
 +                      nf_tables_table_notify(&trans->ctx, trans->msg_type);
                        break;
                case NFT_MSG_NEWCHAIN:
                        if (nft_trans_chain_update(trans)) {
                        }
                        break;
                case NFT_MSG_DELCHAIN:
 +              case NFT_MSG_DESTROYCHAIN:
                        nft_chain_del(trans->ctx.chain);
 -                      nf_tables_chain_notify(&trans->ctx, NFT_MSG_DELCHAIN);
 +                      nf_tables_chain_notify(&trans->ctx, trans->msg_type);
                        nf_tables_unregister_hook(trans->ctx.net,
                                                  trans->ctx.table,
                                                  trans->ctx.chain);
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELRULE:
 +              case NFT_MSG_DESTROYRULE:
                        list_del_rcu(&nft_trans_rule(trans)->list);
                        nf_tables_rule_notify(&trans->ctx,
                                              nft_trans_rule(trans),
 -                                            NFT_MSG_DELRULE);
 +                                            trans->msg_type);
                        nft_rule_expr_deactivate(&trans->ctx,
                                                 nft_trans_rule(trans),
                                                 NFT_TRANS_COMMIT);
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELSET:
 +              case NFT_MSG_DESTROYSET:
                        list_del_rcu(&nft_trans_set(trans)->list);
                        nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
 -                                           NFT_MSG_DELSET, GFP_KERNEL);
 +                                           trans->msg_type, GFP_KERNEL);
                        break;
                case NFT_MSG_NEWSETELEM:
                        te = (struct nft_trans_elem *)trans->data;
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELSETELEM:
 +              case NFT_MSG_DESTROYSETELEM:
                        te = (struct nft_trans_elem *)trans->data;
  
                        nf_tables_setelem_notify(&trans->ctx, te->set,
                                                 &te->elem,
 -                                               NFT_MSG_DELSETELEM);
 +                                               trans->msg_type);
                        nft_setelem_remove(net, te->set, &te->elem);
                        if (!nft_setelem_is_catchall(te->set, &te->elem)) {
                                atomic_dec(&te->set->nelems);
                        }
                        break;
                case NFT_MSG_DELOBJ:
 +              case NFT_MSG_DESTROYOBJ:
                        nft_obj_del(nft_trans_obj(trans));
                        nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans),
 -                                           NFT_MSG_DELOBJ);
 +                                           trans->msg_type);
                        break;
                case NFT_MSG_NEWFLOWTABLE:
                        if (nft_trans_flowtable_update(trans)) {
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELFLOWTABLE:
 +              case NFT_MSG_DESTROYFLOWTABLE:
                        if (nft_trans_flowtable_update(trans)) {
                                nf_tables_flowtable_notify(&trans->ctx,
                                                           nft_trans_flowtable(trans),
                                                           &nft_trans_flowtable_hooks(trans),
 -                                                         NFT_MSG_DELFLOWTABLE);
 +                                                         trans->msg_type);
                                nft_unregister_flowtable_net_hooks(net,
                                                                   &nft_trans_flowtable_hooks(trans));
                        } else {
                                nf_tables_flowtable_notify(&trans->ctx,
                                                           nft_trans_flowtable(trans),
                                                           &nft_trans_flowtable(trans)->hook_list,
 -                                                         NFT_MSG_DELFLOWTABLE);
 +                                                         trans->msg_type);
                                nft_unregister_flowtable_net_hooks(net,
                                                &nft_trans_flowtable(trans)->hook_list);
                        }
@@@ -9392,7 -9301,6 +9392,7 @@@ static int __nf_tables_abort(struct ne
                        }
                        break;
                case NFT_MSG_DELTABLE:
 +              case NFT_MSG_DESTROYTABLE:
                        nft_clear(trans->ctx.net, trans->ctx.table);
                        nft_trans_destroy(trans);
                        break;
                        }
                        break;
                case NFT_MSG_DELCHAIN:
 +              case NFT_MSG_DESTROYCHAIN:
                        trans->ctx.table->use++;
                        nft_clear(trans->ctx.net, trans->ctx.chain);
                        nft_trans_destroy(trans);
                                nft_flow_rule_destroy(nft_trans_flow_rule(trans));
                        break;
                case NFT_MSG_DELRULE:
 +              case NFT_MSG_DESTROYRULE:
                        trans->ctx.chain->use++;
                        nft_clear(trans->ctx.net, nft_trans_rule(trans));
                        nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
                        list_del_rcu(&nft_trans_set(trans)->list);
                        break;
                case NFT_MSG_DELSET:
 +              case NFT_MSG_DESTROYSET:
                        trans->ctx.table->use++;
                        nft_clear(trans->ctx.net, nft_trans_set(trans));
                        nft_trans_destroy(trans);
                                atomic_dec(&te->set->nelems);
                        break;
                case NFT_MSG_DELSETELEM:
 +              case NFT_MSG_DESTROYSETELEM:
                        te = (struct nft_trans_elem *)trans->data;
  
                        nft_setelem_data_activate(net, te->set, &te->elem);
                        }
                        break;
                case NFT_MSG_DELOBJ:
 +              case NFT_MSG_DESTROYOBJ:
                        trans->ctx.table->use++;
                        nft_clear(trans->ctx.net, nft_trans_obj(trans));
                        nft_trans_destroy(trans);
                        }
                        break;
                case NFT_MSG_DELFLOWTABLE:
 +              case NFT_MSG_DESTROYFLOWTABLE:
                        if (nft_trans_flowtable_update(trans)) {
                                list_splice(&nft_trans_flowtable_hooks(trans),
                                            &nft_trans_flowtable(trans)->hook_list);
index b3d623a52885ba3a3434ff2649cc17055d4d9ee6,9fbfad13176f080c34bcde72bc10c7db238c240b..ca730cedb5d41d28634d197ef90499866fb194d6
@@@ -21,7 -21,7 +21,7 @@@ static boo
  length_mt(const struct sk_buff *skb, struct xt_action_param *par)
  {
        const struct xt_length_info *info = par->matchinfo;
 -      u_int16_t pktlen = ntohs(ip_hdr(skb)->tot_len);
 +      u32 pktlen = skb_ip_totlen(skb);
  
        return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
  }
@@@ -30,8 -30,7 +30,7 @@@ static boo
  length_mt6(const struct sk_buff *skb, struct xt_action_param *par)
  {
        const struct xt_length_info *info = par->matchinfo;
-       const u_int16_t pktlen = ntohs(ipv6_hdr(skb)->payload_len) +
-                                sizeof(struct ipv6hdr);
+       u32 pktlen = skb->len;
  
        return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
  }
This page took 0.135226 seconds and 4 git commands to generate.