Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
authorJakub Kicinski <kuba@kernel.org>
Wed, 27 Jul 2022 02:53:09 +0000 (19:53 -0700)
committerJakub Kicinski <kuba@kernel.org>
Wed, 27 Jul 2022 02:53:09 +0000 (19:53 -0700)
Florian Westphal says:

====================
netfilter updates for net

Three late fixes for netfilter:

1) If nf_queue user requests packet truncation below size of l3 header,
   we corrupt the skb, then crash.  Reject such requests.

2) add cond_resched() calls when doing cycle detection in the
   nf_tables graph.  This avoids softlockup warning with certain
   rulesets.

3) Reject rulesets that use nftables 'queue' expression in family/chain
   combinations other than those that are supported.  Currently the ruleset
   will load, but when userspace attempts to reinject you get WARN splat +
   packet drops.

* git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: nft_queue: only allow supported familes and hooks
  netfilter: nf_tables: add rescheduling points during loop detection walks
  netfilter: nf_queue: do not allow packet truncation below transport header offset
====================

Link: https://lore.kernel.org/r/20220726192056.13497-1-fw@strlen.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink_queue.c
net/netfilter/nft_queue.c

index 646d5fd..9f976b1 100644 (file)
@@ -3340,6 +3340,8 @@ int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain)
                        if (err < 0)
                                return err;
                }
+
+               cond_resched();
        }
 
        return 0;
@@ -9367,9 +9369,13 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
                                break;
                        }
                }
+
+               cond_resched();
        }
 
        list_for_each_entry(set, &ctx->table->sets, list) {
+               cond_resched();
+
                if (!nft_is_active_next(ctx->net, set))
                        continue;
                if (!(set->flags & NFT_SET_MAP) ||
index a364f8e..87a9009 100644 (file)
@@ -843,11 +843,16 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
 }
 
 static int
-nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e, int diff)
+nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int diff)
 {
        struct sk_buff *nskb;
 
        if (diff < 0) {
+               unsigned int min_len = skb_transport_offset(e->skb);
+
+               if (data_len < min_len)
+                       return -EINVAL;
+
                if (pskb_trim(e->skb, data_len))
                        return -ENOMEM;
        } else if (diff > 0) {
index 15e4b76..da29e92 100644 (file)
@@ -68,6 +68,31 @@ static void nft_queue_sreg_eval(const struct nft_expr *expr,
        regs->verdict.code = ret;
 }
 
+static int nft_queue_validate(const struct nft_ctx *ctx,
+                             const struct nft_expr *expr,
+                             const struct nft_data **data)
+{
+       static const unsigned int supported_hooks = ((1 << NF_INET_PRE_ROUTING) |
+                                                    (1 << NF_INET_LOCAL_IN) |
+                                                    (1 << NF_INET_FORWARD) |
+                                                    (1 << NF_INET_LOCAL_OUT) |
+                                                    (1 << NF_INET_POST_ROUTING));
+
+       switch (ctx->family) {
+       case NFPROTO_IPV4:
+       case NFPROTO_IPV6:
+       case NFPROTO_INET:
+       case NFPROTO_BRIDGE:
+               break;
+       case NFPROTO_NETDEV: /* lacks okfn */
+               fallthrough;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return nft_chain_validate_hooks(ctx->chain, supported_hooks);
+}
+
 static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = {
        [NFTA_QUEUE_NUM]        = { .type = NLA_U16 },
        [NFTA_QUEUE_TOTAL]      = { .type = NLA_U16 },
@@ -164,6 +189,7 @@ static const struct nft_expr_ops nft_queue_ops = {
        .eval           = nft_queue_eval,
        .init           = nft_queue_init,
        .dump           = nft_queue_dump,
+       .validate       = nft_queue_validate,
        .reduce         = NFT_REDUCE_READONLY,
 };
 
@@ -173,6 +199,7 @@ static const struct nft_expr_ops nft_queue_sreg_ops = {
        .eval           = nft_queue_sreg_eval,
        .init           = nft_queue_sreg_init,
        .dump           = nft_queue_sreg_dump,
+       .validate       = nft_queue_validate,
        .reduce         = NFT_REDUCE_READONLY,
 };