]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: fix a crash if we specify ether type or meta nfproto in reject
authorAlvaro Neira <alvaroneay@gmail.com>
Sat, 11 Oct 2014 14:11:10 +0000 (16:11 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 11 Oct 2014 20:06:09 +0000 (22:06 +0200)
If we use a rule:
nft add rule bridge filter input \
ether type ip reject with icmp type host-unreachable

or this:

nft add rule inet filter input \
meta nfproto ipv4 reject with icmp type host-unreachable

we have a segfault because we add a network dependency when we already have
network context.

Signed-off-by: Alvaro Neira Ayuso <alvaroneay@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c

index 108248a7c12efd262b8e3e5c47a3e66f0c109f1a..d61d76babc11e5280bd7c294cfe5114e69065da4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/netfilter/nf_tables.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp6.h>
+#include <net/ethernet.h>
 
 #include <expression.h>
 #include <statement.h>
@@ -1204,6 +1205,9 @@ static int stmt_reject_gen_dependency(struct eval_ctx *ctx, struct stmt *stmt,
 static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
                                       struct expr *expr)
 {
+       const struct proto_desc *desc, *base;
+       int protocol;
+
        switch (ctx->pctx.family) {
        case NFPROTO_ARP:
                return stmt_error(ctx, stmt, "cannot use reject with arp");
@@ -1224,8 +1228,53 @@ static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
                        break;
                }
                break;
-       case NFPROTO_INET:
        case NFPROTO_BRIDGE:
+               base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+               desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+               if (desc != NULL) {
+                       protocol = proto_find_num(base, desc);
+                       switch (protocol) {
+                       case __constant_htons(ETH_P_IP):
+                               if (NFPROTO_IPV4 == stmt->reject.family)
+                                       break;
+                       case __constant_htons(ETH_P_IPV6):
+                               if (NFPROTO_IPV6 == stmt->reject.family)
+                                       break;
+                               return stmt_error(ctx, stmt,
+                                 "conflicting protocols specified: ip vs ip6");
+                       default:
+                               return stmt_error(ctx, stmt,
+                                               "cannot reject this ether type");
+                       }
+                       break;
+               }
+               if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
+                       break;
+               if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)
+                       return -1;
+               break;
+       case NFPROTO_INET:
+               base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+               desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+               if (desc != NULL) {
+                       protocol = proto_find_num(base, desc);
+                       switch (protocol) {
+                       case NFPROTO_IPV4:
+                               if (stmt->reject.family == NFPROTO_IPV4)
+                                       break;
+                               return stmt_error(ctx, stmt,
+                                 "conflicting protocols specified: ip vs ip6");
+                               break;
+                       case NFPROTO_IPV6:
+                               if (stmt->reject.family == NFPROTO_IPV6)
+                                       break;
+                               return stmt_error(ctx, stmt,
+                                 "conflicting protocols specified: ip vs ip6");
+                       default:
+                               BUG("unsupported family");
+                       }
+                       break;
+               }
                if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH)
                        break;
                if (stmt_reject_gen_dependency(ctx, stmt, expr) < 0)