All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tom Yan <tom.ty89@gmail.com>
To: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: netfilter-devel@vger.kernel.org
Subject: Re: [PATCH nft 2/3] netlink_linearize: incorrect netlink bytecode with binary operation and flags
Date: Wed, 28 Jul 2021 02:36:18 +0800	[thread overview]
Message-ID: <CAGnHSE=e-iYaz3KOMBq1JSVRd0HTL=TKQ_HHMadfyd2Nr8__yg@mail.gmail.com> (raw)
In-Reply-To: <20210727153741.14406-2-pablo@netfilter.org>

Hmm, that means `tcp flags & (fin | syn | rst | ack) syn` is now
equivalent to 'tcp flags & (fin | syn | rst | ack) == syn'. Does that
mean `tcp flags syn` (was supposed to be and) is now equivalent to
`tcp flags == syn` instead of `tcp flags & syn == syn` / `tcp flags &
syn != 0`?

Suppose `tcp flags & syn != 0` should then be translated to `tcp flags
syn / syn` instead, please note that while nft translates `tcp flags &
syn == syn` to `tcp flags syn / syn`, it does not accept the
translation as input (when the mask is not a comma-separated list):

# nft --debug=netlink add rule meh tcp_flags 'tcp flags syn / syn'
Error: syntax error, unexpected newline, expecting comma
add rule meh tcp_flags tcp flags syn / syn
                                          ^

Also, does that mean `tcp flags & (fin | syn | rst | ack) fin,syn,ack`
will now be equivalent to `tcp flags & (fin | syn | rst | ack) = (fin
| syn | ack)` instead of (ultimately) `tcp flags & (fin | syn | ack)
!= 0`? Which means `tcp flags & (fin | syn | ack) != 0` should not be
translated to `tcp flags fin,syn,ack`?


On Tue, 27 Jul 2021 at 23:37, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>
> nft generates incorrect bytecode when combining flag datatype and binary
> operations:
>
>   # nft --debug=netlink add rule meh tcp_flags 'tcp flags & (fin | syn | rst | ack) syn'
> ip
>   [ meta load l4proto => reg 1 ]
>   [ cmp eq reg 1 0x00000006 ]
>   [ payload load 1b @ transport header + 13 => reg 1 ]
>   [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
>   [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
>   [ cmp neq reg 1 0x00000000 ]
>
> Note the double bitwise expression. The last two expressions are not
> correct either since it should match on the syn flag, ie. 0x2.
>
> After this patch, netlink bytecode generation looks correct:
>
>  # nft --debug=netlink add rule meh tcp_flags 'tcp flags & (fin | syn | rst | ack) syn'
> ip
>   [ meta load l4proto => reg 1 ]
>   [ cmp eq reg 1 0x00000006 ]
>   [ payload load 1b @ transport header + 13 => reg 1 ]
>   [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
>   [ cmp eq reg 1 0x00000002 ]
>
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> ---
>  src/netlink_linearize.c     | 38 ++++++++++++++++-----------
>  tests/py/inet/tcp.t         |  2 ++
>  tests/py/inet/tcp.t.json    | 52 +++++++++++++++++++++++++++++++++++++
>  tests/py/inet/tcp.t.payload | 16 ++++++++++++
>  4 files changed, 93 insertions(+), 15 deletions(-)
>
> diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
> index 9ab3ec3ef2ff..eb53ccec1154 100644
> --- a/src/netlink_linearize.c
> +++ b/src/netlink_linearize.c
> @@ -481,23 +481,31 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
>         netlink_gen_raw_data(zero, expr->right->byteorder, len, &nld);
>         netlink_gen_data(expr->right, &nld2);
>
> -       nle = alloc_nft_expr("bitwise");
> -       netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
> -       netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
> -       nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
> -       nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld2.value, nld2.len);
> -       nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &nld.value, nld.len);
> -       nft_rule_add_expr(ctx, nle, &expr->location);
> -
> -       nle = alloc_nft_expr("cmp");
> -       netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
> -       if (expr->op == OP_NEG)
> +       if (expr->left->etype == EXPR_BINOP) {
> +               nle = alloc_nft_expr("cmp");
> +               netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
>                 nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
> -       else
> -               nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
> +               nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld2.value, nld2.len);
> +               nft_rule_add_expr(ctx, nle, &expr->location);
> +       } else {
> +               nle = alloc_nft_expr("bitwise");
> +               netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
> +               netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
> +               nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
> +               nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld2.value, nld2.len);
> +               nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &nld.value, nld.len);
> +               nft_rule_add_expr(ctx, nle, &expr->location);
>
> -       nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
> -       nft_rule_add_expr(ctx, nle, &expr->location);
> +               nle = alloc_nft_expr("cmp");
> +               netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
> +               if (expr->op == OP_NEG)
> +                       nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
> +               else
> +                       nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
> +
> +               nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
> +               nft_rule_add_expr(ctx, nle, &expr->location);
> +       }
>
>         mpz_clear(zero);
>         release_register(ctx, expr->left);
> diff --git a/tests/py/inet/tcp.t b/tests/py/inet/tcp.t
> index 16e15b9f76c1..983564ec5b75 100644
> --- a/tests/py/inet/tcp.t
> +++ b/tests/py/inet/tcp.t
> @@ -69,6 +69,8 @@ tcp flags != cwr;ok
>  tcp flags == syn;ok
>  tcp flags fin,syn / fin,syn;ok
>  tcp flags != syn / fin,syn;ok
> +tcp flags & (fin | syn | rst | ack) syn;ok;tcp flags syn / fin,syn,rst,ack
> +tcp flags & (fin | syn | rst | ack) != syn;ok;tcp flags != syn / fin,syn,rst,ack
>  tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr;ok;tcp flags == 0xff
>  tcp flags { syn, syn | ack };ok
>  tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack };ok
> diff --git a/tests/py/inet/tcp.t.json b/tests/py/inet/tcp.t.json
> index 590a3dee5d3f..033a4f22e0fd 100644
> --- a/tests/py/inet/tcp.t.json
> +++ b/tests/py/inet/tcp.t.json
> @@ -1521,3 +1521,55 @@
>      }
>  ]
>
> +# tcp flags & (fin | syn | rst | ack) syn
> +[
> +    {
> +        "match": {
> +            "left": {
> +                "&": [
> +                    {
> +                        "payload": {
> +                            "field": "flags",
> +                            "protocol": "tcp"
> +                        }
> +                    },
> +                    [
> +                        "fin",
> +                        "syn",
> +                        "rst",
> +                        "ack"
> +                    ]
> +                ]
> +            },
> +            "op": "==",
> +            "right": "syn"
> +        }
> +    }
> +]
> +
> +# tcp flags & (fin | syn | rst | ack) != syn
> +[
> +    {
> +        "match": {
> +            "left": {
> +                "&": [
> +                    {
> +                        "payload": {
> +                            "field": "flags",
> +                            "protocol": "tcp"
> +                        }
> +                    },
> +                    [
> +                        "fin",
> +                        "syn",
> +                        "rst",
> +                        "ack"
> +                    ]
> +                ]
> +            },
> +            "op": "!=",
> +            "right": "syn"
> +        }
> +    }
> +]
> +
> diff --git a/tests/py/inet/tcp.t.payload b/tests/py/inet/tcp.t.payload
> index 7f302080f02a..eaa7cd099bd6 100644
> --- a/tests/py/inet/tcp.t.payload
> +++ b/tests/py/inet/tcp.t.payload
> @@ -370,6 +370,22 @@ inet test-inet input
>    [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
>    [ cmp neq reg 1 0x00000002 ]
>
> +# tcp flags & (fin | syn | rst | ack) syn
> +inet test-inet input
> +  [ meta load l4proto => reg 1 ]
> +  [ cmp eq reg 1 0x00000006 ]
> +  [ payload load 1b @ transport header + 13 => reg 1 ]
> +  [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
> +  [ cmp eq reg 1 0x00000002 ]
> +
> +# tcp flags & (fin | syn | rst | ack) != syn
> +inet test-inet input
> +  [ meta load l4proto => reg 1 ]
> +  [ cmp eq reg 1 0x00000006 ]
> +  [ payload load 1b @ transport header + 13 => reg 1 ]
> +  [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
> +  [ cmp neq reg 1 0x00000002 ]
> +
>  # tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr
>  inet test-inet input
>    [ meta load l4proto => reg 1 ]
> --
> 2.20.1
>

  reply	other threads:[~2021-07-27 18:36 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-27 15:37 [PATCH nft 1/3] expression: missing != in flagcmp expression print function Pablo Neira Ayuso
2021-07-27 15:37 ` [PATCH nft 2/3] netlink_linearize: incorrect netlink bytecode with binary operation and flags Pablo Neira Ayuso
2021-07-27 18:36   ` Tom Yan [this message]
2021-07-27 21:05     ` Pablo Neira Ayuso
2021-07-29  1:48       ` Tom Yan
2021-07-29  7:03         ` Pablo Neira Ayuso
2021-07-29 10:41           ` Tom Yan
2021-07-29 10:58             ` Tom Yan
2021-07-29 15:16               ` Tom Yan
2021-07-30  4:53                 ` Tom Yan
2021-07-29  2:57       ` Tom Yan
2021-07-29  6:55         ` Pablo Neira Ayuso
2021-07-27 15:37 ` [PATCH nft 3/3] evaluate: disallow negation with binary operation Pablo Neira Ayuso

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAGnHSE=e-iYaz3KOMBq1JSVRd0HTL=TKQ_HHMadfyd2Nr8__yg@mail.gmail.com' \
    --to=tom.ty89@gmail.com \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pablo@netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.