netfilter: ipset: fix hash:net,port,net hang with /0 subnet
[platform/kernel/linux-rpi.git] / net / netfilter / nf_tables_core.c
index 866cfba..2ab4216 100644 (file)
@@ -67,6 +67,50 @@ static void nft_cmp_fast_eval(const struct nft_expr *expr,
        regs->verdict.code = NFT_BREAK;
 }
 
+static void nft_cmp16_fast_eval(const struct nft_expr *expr,
+                               struct nft_regs *regs)
+{
+       const struct nft_cmp16_fast_expr *priv = nft_expr_priv(expr);
+       const u64 *reg_data = (const u64 *)&regs->data[priv->sreg];
+       const u64 *mask = (const u64 *)&priv->mask;
+       const u64 *data = (const u64 *)&priv->data;
+
+       if (((reg_data[0] & mask[0]) == data[0] &&
+           ((reg_data[1] & mask[1]) == data[1])) ^ priv->inv)
+               return;
+       regs->verdict.code = NFT_BREAK;
+}
+
+static noinline void __nft_trace_verdict(struct nft_traceinfo *info,
+                                        const struct nft_chain *chain,
+                                        const struct nft_regs *regs)
+{
+       enum nft_trace_types type;
+
+       switch (regs->verdict.code) {
+       case NFT_CONTINUE:
+       case NFT_RETURN:
+               type = NFT_TRACETYPE_RETURN;
+               break;
+       default:
+               type = NFT_TRACETYPE_RULE;
+               break;
+       }
+
+       __nft_trace_packet(info, chain, type);
+}
+
+static inline void nft_trace_verdict(struct nft_traceinfo *info,
+                                    const struct nft_chain *chain,
+                                    const struct nft_rule *rule,
+                                    const struct nft_regs *regs)
+{
+       if (static_branch_unlikely(&nft_trace_enabled)) {
+               info->rule = rule;
+               __nft_trace_verdict(info, chain, regs);
+       }
+}
+
 static bool nft_payload_fast_eval(const struct nft_expr *expr,
                                  struct nft_regs *regs,
                                  const struct nft_pktinfo *pkt)
@@ -79,7 +123,7 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
        if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
                ptr = skb_network_header(skb);
        else {
-               if (!pkt->tprot_set)
+               if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
                        return false;
                ptr = skb_network_header(skb) + nft_thoff(pkt);
        }
@@ -162,7 +206,7 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv)
        struct nft_rule *const *rules;
        const struct nft_rule *rule;
        const struct nft_expr *expr, *last;
-       struct nft_regs regs;
+       struct nft_regs regs = {};
        unsigned int stackptr = 0;
        struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
        bool genbit = READ_ONCE(net->nft.gencursor);
@@ -185,6 +229,8 @@ next_rule:
                nft_rule_for_each_expr(expr, last, rule) {
                        if (expr->ops == &nft_cmp_fast_ops)
                                nft_cmp_fast_eval(expr, &regs);
+                       else if (expr->ops == &nft_cmp16_fast_ops)
+                               nft_cmp16_fast_eval(expr, &regs);
                        else if (expr->ops == &nft_bitwise_fast_ops)
                                nft_bitwise_fast_eval(expr, &regs);
                        else if (expr->ops != &nft_payload_fast_ops ||
@@ -207,13 +253,13 @@ next_rule:
                break;
        }
 
+       nft_trace_verdict(&info, chain, rule, &regs);
+
        switch (regs.verdict.code & NF_VERDICT_MASK) {
        case NF_ACCEPT:
        case NF_DROP:
        case NF_QUEUE:
        case NF_STOLEN:
-               nft_trace_packet(&info, chain, rule,
-                                NFT_TRACETYPE_RULE);
                return regs.verdict.code;
        }
 
@@ -226,15 +272,10 @@ next_rule:
                stackptr++;
                fallthrough;
        case NFT_GOTO:
-               nft_trace_packet(&info, chain, rule,
-                                NFT_TRACETYPE_RULE);
-
                chain = regs.verdict.chain;
                goto do_chain;
        case NFT_CONTINUE:
        case NFT_RETURN:
-               nft_trace_packet(&info, chain, rule,
-                                NFT_TRACETYPE_RETURN);
                break;
        default:
                WARN_ON(1);