]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
meta: stash context statement length when generating payload/meta dependency
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 18 Jul 2023 21:10:01 +0000 (23:10 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 19 Jul 2023 18:06:34 +0000 (20:06 +0200)
... meta mark set ip dscp

generates an implicit dependency from the inet family to match on meta
nfproto ip.

The length of this implicit expression is incorrectly adjusted to the
statement length, ie. relational to compare meta nfproto takes 4 bytes
instead of 1 byte. The evaluation of 'ip dscp' under the meta mark
statement triggers this implicit dependency which should not consider
the context statement length since it is added before the statement
itself.

This problem shows when listing the ruleset, since netlink_parse_cmp()
where left->len < right->len, hence handling the implicit dependency as
a concatenation, but it is actually a bug in the evaluation step that
leads to incorrect bytecode.

Fixes: 3c64ea7995cb ("evaluate: honor statement length in integer evaluation")
Fixes: edecd58755a8 ("evaluate: support shifts larger than the width of the left operand")
Tested-by: Brian Davidson <davidson.brian@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/payload.c
tests/py/inet/meta.t
tests/py/inet/meta.t.json
tests/py/inet/meta.t.payload

index f67b5407879244a0204fff5e0619430cb885d3ba..7862745b2035bba363dafd6e4a205f936125ff7a 100644 (file)
@@ -409,6 +409,7 @@ static int payload_add_dependency(struct eval_ctx *ctx,
        const struct proto_hdr_template *tmpl;
        struct expr *dep, *left, *right;
        struct proto_ctx *pctx;
+       unsigned int stmt_len;
        struct stmt *stmt;
        int protocol;
 
@@ -429,11 +430,16 @@ static int payload_add_dependency(struct eval_ctx *ctx,
                                    constant_data_ptr(protocol, tmpl->len));
 
        dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
+
+       stmt_len = ctx->stmt_len;
+       ctx->stmt_len = 0;
+
        stmt = expr_stmt_alloc(&dep->location, dep);
        if (stmt_evaluate(ctx, stmt) < 0) {
                return expr_error(ctx->msgs, expr,
                                          "dependency statement is invalid");
        }
+       ctx->stmt_len = stmt_len;
 
        if (ctx->inner_desc) {
                if (tmpl->meta_key)
@@ -543,6 +549,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
        const struct hook_proto_desc *h;
        const struct proto_desc *desc;
        struct proto_ctx *pctx;
+       unsigned int stmt_len;
        struct stmt *stmt;
        uint16_t type;
 
@@ -559,12 +566,18 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
                                          "protocol specification is invalid "
                                          "for this family");
 
+               stmt_len = ctx->stmt_len;
+               ctx->stmt_len = 0;
+
                stmt = meta_stmt_meta_iiftype(&expr->location, type);
                if (stmt_evaluate(ctx, stmt) < 0) {
                        return expr_error(ctx->msgs, expr,
                                          "dependency statement is invalid");
                }
                *res = stmt;
+
+               ctx->stmt_len = stmt_len;
+
                return 0;
        }
 
index 374738a701d642adf1732411bb1c6caa65bcb101..5c062b39b8a928f8cbba5e1a936a9062c2ffe454 100644 (file)
@@ -25,3 +25,8 @@ meta mark set ct mark >> 8;ok
 meta mark . tcp dport { 0x0000000a-0x00000014 . 80-90, 0x00100000-0x00100123 . 100-120 };ok
 ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 1.2.3.6-1.2.3.8 . 0x00000200-0x00000300 };ok
 ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 5.6.7.8 . 0x00000200 };ok
+
+meta mark set ip dscp;ok
+meta mark set ip dscp | 0x40;ok
+meta mark set ip6 dscp;ok
+meta mark set ip6 dscp | 0x40;ok
index 92a1f9bff37352887a85bbb360bee15b167aef1f..3ba0fd1dee2ad81b7738b8131fb147489cde6e6e 100644 (file)
     }
 ]
 
+# meta mark set ip dscp
+[
+    {
+        "mangle": {
+            "key": {
+                "meta": {
+                    "key": "mark"
+                }
+            },
+            "value": {
+                "payload": {
+                    "field": "dscp",
+                    "protocol": "ip"
+                }
+            }
+        }
+    }
+]
+
+# meta mark set ip dscp | 0x40
+[
+    {
+        "mangle": {
+            "key": {
+                "meta": {
+                    "key": "mark"
+                }
+            },
+            "value": {
+                "|": [
+                    {
+                        "payload": {
+                            "field": "dscp",
+                            "protocol": "ip"
+                        }
+                    },
+                    64
+                ]
+            }
+        }
+    }
+]
+
+# meta mark set ip6 dscp
+[
+    {
+        "mangle": {
+            "key": {
+                "meta": {
+                    "key": "mark"
+                }
+            },
+            "value": {
+                "payload": {
+                    "field": "dscp",
+                    "protocol": "ip6"
+                }
+            }
+        }
+    }
+]
+
+# meta mark set ip6 dscp | 0x40
+[
+    {
+        "mangle": {
+            "key": {
+                "meta": {
+                    "key": "mark"
+                }
+            },
+            "value": {
+                "|": [
+                    {
+                        "payload": {
+                            "field": "dscp",
+                            "protocol": "ip6"
+                        }
+                    },
+                    64
+                ]
+            }
+        }
+    }
+]
+
index ea54090727faa0f8d4821143466bf5c9abe8d579..c53b5077f9a61b89a1ef2ceedd6f6233f6cbd624 100644 (file)
@@ -133,3 +133,43 @@ inet test-inet input
   [ meta load mark => reg 9 ]
   [ lookup reg 1 set __set%d ]
 
+# meta mark set ip dscp
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x00000002 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+  [ meta set mark with reg 1 ]
+
+# meta mark set ip dscp | 0x40
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x00000002 ]
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+  [ bitwise reg 1 = ( reg 1 & 0xffffffbf ) ^ 0x00000040 ]
+  [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x0000000a ]
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+  [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp | 0x40
+inet test-inet input
+  [ meta load nfproto => reg 1 ]
+  [ cmp eq reg 1 0x0000000a ]
+  [ payload load 2b @ network header + 0 => reg 1 ]
+  [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+  [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+  [ bitwise reg 1 = ( reg 1 & 0xffffffbf ) ^ 0x00000040 ]
+  [ meta set mark with reg 1 ]
+