Blame SOURCES/0021-monitor-Sanitize-startup-race-condition.patch

1d03cd
From ef0f28bc8efdc5292ceb593c9c5a646f030e0994 Mon Sep 17 00:00:00 2001
1d03cd
From: Phil Sutter <psutter@redhat.com>
1d03cd
Date: Thu, 9 Feb 2023 15:25:37 +0100
1d03cd
Subject: [PATCH] monitor: Sanitize startup race condition
1d03cd
1d03cd
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2130721
1d03cd
Upstream Status: nftables commit 545edb7a8ef0a
1d03cd
1d03cd
commit 545edb7a8ef0a8acf991b1b7857fddc24d7b151a
1d03cd
Author: Phil Sutter <phil@nwl.cc>
1d03cd
Date:   Wed Sep 28 23:26:42 2022 +0200
1d03cd
1d03cd
    monitor: Sanitize startup race condition
1d03cd
1d03cd
    During startup, 'nft monitor' first fetches the current ruleset and then
1d03cd
    keeps this cache up to date based on received events. This is racey, as
1d03cd
    any ruleset changes in between the initial fetch and the socket opening
1d03cd
    are not recognized.
1d03cd
1d03cd
    This script demonstrates the problem:
1d03cd
1d03cd
    | #!/bin/bash
1d03cd
    |
1d03cd
    | while true; do
1d03cd
    |       nft flush ruleset
1d03cd
    |       iptables-nft -A FORWARD
1d03cd
    | done &
1d03cd
    | maniploop=$!
1d03cd
    |
1d03cd
    | trap "kill $maniploop; kill \$!; wait" EXIT
1d03cd
    |
1d03cd
    | while true; do
1d03cd
    |       nft monitor rules >/dev/null &
1d03cd
    |       sleep 0.2
1d03cd
    |       kill $!
1d03cd
    | done
1d03cd
1d03cd
    If the table add event is missed, the rule add event callback fails to
1d03cd
    deserialize the rule and calls abort().
1d03cd
1d03cd
    Avoid the inconvenient program exit by returning NULL from
1d03cd
    netlink_delinearize_rule() instead of aborting and make callers check
1d03cd
    the return value.
1d03cd
1d03cd
    Signed-off-by: Phil Sutter <phil@nwl.cc>
1d03cd
1d03cd
Signed-off-by: Phil Sutter <psutter@redhat.com>
1d03cd
---
1d03cd
 src/cache.c               | 1 +
1d03cd
 src/monitor.c             | 5 +++++
1d03cd
 src/netlink_delinearize.c | 5 ++++-
1d03cd
 3 files changed, 10 insertions(+), 1 deletion(-)
1d03cd
1d03cd
diff --git a/src/cache.c b/src/cache.c
1d03cd
index fd8df88..701aec6 100644
1d03cd
--- a/src/cache.c
1d03cd
+++ b/src/cache.c
1d03cd
@@ -490,6 +490,7 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
1d03cd
 
1d03cd
 	netlink_dump_rule(nlr, ctx);
1d03cd
 	rule = netlink_delinearize_rule(ctx, nlr);
1d03cd
+	assert(rule);
1d03cd
 	list_add_tail(&rule->list, &ctx->list);
1d03cd
 
1d03cd
 	return 0;
1d03cd
diff --git a/src/monitor.c b/src/monitor.c
1d03cd
index 7fa92eb..a6b30a1 100644
1d03cd
--- a/src/monitor.c
1d03cd
+++ b/src/monitor.c
1d03cd
@@ -551,6 +551,10 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
1d03cd
 
1d03cd
 	nlr = netlink_rule_alloc(nlh);
1d03cd
 	r = netlink_delinearize_rule(monh->ctx, nlr);
1d03cd
+	if (!r) {
1d03cd
+		fprintf(stderr, "W: Received event for an unknown table.\n");
1d03cd
+		goto out_free_nlr;
1d03cd
+	}
1d03cd
 	nlr_for_each_set(nlr, rule_map_decompose_cb, NULL,
1d03cd
 			 &monh->ctx->nft->cache);
1d03cd
 	cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
1d03cd
@@ -587,6 +591,7 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
1d03cd
 		break;
1d03cd
 	}
1d03cd
 	rule_free(r);
1d03cd
+out_free_nlr:
1d03cd
 	nftnl_rule_free(nlr);
1d03cd
 	return MNL_CB_OK;
1d03cd
 }
1d03cd
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
1d03cd
index c6ad84d..1d47c74 100644
1d03cd
--- a/src/netlink_delinearize.c
1d03cd
+++ b/src/netlink_delinearize.c
1d03cd
@@ -3194,7 +3194,10 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
1d03cd
 	pctx->rule = rule_alloc(&netlink_location, &h);
1d03cd
 	pctx->table = table_cache_find(&ctx->nft->cache.table_cache,
1d03cd
 				       h.table.name, h.family);
1d03cd
-	assert(pctx->table != NULL);
1d03cd
+	if (!pctx->table) {
1d03cd
+		errno = ENOENT;
1d03cd
+		return NULL;
1d03cd
+	}
1d03cd
 
1d03cd
 	pctx->rule->comment = nftnl_rule_get_comment(nlr);
1d03cd
 
1d03cd
-- 
1d03cd
2.39.1
1d03cd