public inbox for netfilter-devel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] iptables: fix null dereference parsing bitwise operations
@ 2026-02-02 10:14 Remy D. Farley
  2026-02-11 21:36 ` Phil Sutter
  0 siblings, 1 reply; 5+ messages in thread
From: Remy D. Farley @ 2026-02-02 10:14 UTC (permalink / raw)
  To: Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
	Phil Sutter, netfilter-devel, coreteam
  Cc: Remy D. Farley

Iptables binary only understands NFT_BITWISE_MASK_XOR bitwise operation and
assumes its attributes are always present without actually checking, which
leads to a segfault in some cases.

This commit introduces this missing check.

| /**
|  * enum nft_bitwise_ops - nf_tables bitwise operations
|  *
|  * @NFT_BITWISE_MASK_XOR: mask-and-xor operation used to implement NOT, AND, OR
|  *                        and XOR boolean operations
|  * @NFT_BITWISE_LSHIFT: left-shift operation          \
|  * @NFT_BITWISE_RSHIFT: right-shift operation         |
|  * @NFT_BITWISE_AND: and operation                    | These all are affected
|  * @NFT_BITWISE_OR: or operation                      |
|  * @NFT_BITWISE_XOR: xor operation                    /
|  */

From iptables/nft-ruleparse.c:

| static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
| {
|   [...]
|
|   data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len); // <-- this attribute may not be present
|
|   if (len > sizeof(dreg->bitwise.xor)) {
|     ctx->errmsg = "bitwise xor too large";
|     return;
|   }
|
|   memcpy(dreg->bitwise.xor, data, len); // <-- zero dereference happens here
|
|   data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len);
|
|   if (len > sizeof(dreg->bitwise.mask)) {
|   	ctx->errmsg = "bitwise mask too large";
|   	return;
|   }
|
|   memcpy(dreg->bitwise.mask, data, len);
|
|   dreg->bitwise.set = true;
|
| }

The bug can be reproduced by creating a rule like this:

| # newrule.json
| {"chain": "example-chain",
|  "expressions": {"elem": [{"data": {"base": 1,
|                                     "dreg": 1,
|                                     "len": 4,
|                                     "offset": 12},
|                            "name": "payload"},
|                           {"data": {"data": {"value": [255, 255, 255, 0]},
|                                     "dreg": 1,
|                                     "len": 4,
|                                     "op": 3,
|                                     "sreg": 1},
|                            "name": "bitwise"},
|                           {"data": {"data": {"value": [1, 2, 3, 0]},
|                                     "op": 0,
|                                     "sreg": 1},
|                            "name": "cmp"},
|                           {"data": {"data": {"verdict": {"code": 1}},
|                                     "dreg": 0},
|                            "name": "immediate"}]},
|  "nfgen-family": 2,
|  "table": "filter"}

| # newrule.sh
| set -euo pipefail
|
| iptables -N example-chain || true
|
| genid="$(
|   ./tools/net/ynl/pyynl/cli.py --spec Documentation/netlink/specs/nftables.yaml \
|     --do getgen --json "{}" --output-json |
|     jq -r ".id"
| )"
|
| ./tools/net/ynl/pyynl/cli.py --spec Documentation/netlink/specs/nftables.yaml \
|   --multi batch-begin "{\"genid\": $genid, \"res-id\": 10}" \
|   --creat --append --multi newrule "$(cat ./newrule.json)" \
|   --creat --multi batch-end '{}' \
|   --output-json

Signed-off-by: Remy D. Farley <one-d-wide@protonmail.com>
---
 iptables/nft-ruleparse.c | 5 +++++
 iptables/nft.c           | 5 ++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c
index cdf1af4f..1a9084e3 100644
--- a/iptables/nft-ruleparse.c
+++ b/iptables/nft-ruleparse.c
@@ -232,6 +232,11 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
 	const void *data;
 	uint32_t len;
 
+	if (nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_OP) != 0 /* empty or MASK_XOR */) {
+		ctx->errmsg = "unsupported bitwise operation";
+		return;
+	}
+
 	if (!sreg)
 		return;
 
diff --git a/iptables/nft.c b/iptables/nft.c
index 85080a6d..661fac29 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -4029,7 +4029,6 @@ static const char *supported_exprs[] = {
 	"payload",
 	"meta",
 	"cmp",
-	"bitwise",
 	"counter",
 	"immediate",
 	"lookup",
@@ -4056,6 +4055,10 @@ static int nft_is_expr_compatible(struct nftnl_expr *expr, void *data)
 	    nftnl_expr_is_set(expr, NFTNL_EXPR_LOG_GROUP))
 		return 0;
 
+	if (!strcmp(name, "bitwise") &&
+	    nftnl_expr_get_u32(expr, NFTNL_EXPR_BITWISE_OP) == 0 /* empty or MASK_XOR */)
+		return 0;
+
 	return -1;
 }
 
-- 
2.51.2



^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-02-13 13:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-02 10:14 [PATCH] iptables: fix null dereference parsing bitwise operations Remy D. Farley
2026-02-11 21:36 ` Phil Sutter
2026-02-12 19:34   ` Remy D. Farley
2026-02-13 13:06     ` Phil Sutter
2026-02-13 13:17       ` Florian Westphal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox