]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
monitor: Sanitize startup race condition
authorPhil Sutter <phil@nwl.cc>
Wed, 28 Sep 2022 21:26:42 +0000 (23:26 +0200)
committerPhil Sutter <phil@nwl.cc>
Fri, 30 Sep 2022 14:09:06 +0000 (16:09 +0200)
During startup, 'nft monitor' first fetches the current ruleset and then
keeps this cache up to date based on received events. This is racey, as
any ruleset changes in between the initial fetch and the socket opening
are not recognized.

This script demonstrates the problem:

| #!/bin/bash
|
| while true; do
|  nft flush ruleset
|  iptables-nft -A FORWARD
| done &
| maniploop=$!
|
| trap "kill $maniploop; kill \$!; wait" EXIT
|
| while true; do
|  nft monitor rules >/dev/null &
|  sleep 0.2
|  kill $!
| done

If the table add event is missed, the rule add event callback fails to
deserialize the rule and calls abort().

Avoid the inconvenient program exit by returning NULL from
netlink_delinearize_rule() instead of aborting and make callers check
the return value.

Signed-off-by: Phil Sutter <phil@nwl.cc>
src/cache.c
src/monitor.c
src/netlink_delinearize.c

index f790f995e07b048953445f7237fa8e3e4790a735..85de970f76448ff7e25657eafae07c4c4533a81f 100644 (file)
@@ -598,6 +598,7 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
 
        netlink_dump_rule(nlr, ctx);
        rule = netlink_delinearize_rule(ctx, nlr);
+       assert(rule);
        list_add_tail(&rule->list, &ctx->list);
 
        return 0;
index 7fa92ebfb0f3a47a84f8a54b631e94ef4ce5370f..a6b30a18cfd25c97f4807a46da5491575a6c055e 100644 (file)
@@ -551,6 +551,10 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
 
        nlr = netlink_rule_alloc(nlh);
        r = netlink_delinearize_rule(monh->ctx, nlr);
+       if (!r) {
+               fprintf(stderr, "W: Received event for an unknown table.\n");
+               goto out_free_nlr;
+       }
        nlr_for_each_set(nlr, rule_map_decompose_cb, NULL,
                         &monh->ctx->nft->cache);
        cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
@@ -587,6 +591,7 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
                break;
        }
        rule_free(r);
+out_free_nlr:
        nftnl_rule_free(nlr);
        return MNL_CB_OK;
 }
index 0da6cc78f94fac07d83bd9c99e4f41ea0f68d488..e8b9724cbac9430a7621bc20417ba6ada6f8c278 100644 (file)
@@ -3195,7 +3195,10 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
        pctx->rule = rule_alloc(&netlink_location, &h);
        pctx->table = table_cache_find(&ctx->nft->cache.table_cache,
                                       h.table.name, h.family);
-       assert(pctx->table != NULL);
+       if (!pctx->table) {
+               errno = ENOENT;
+               return NULL;
+       }
 
        pctx->rule->comment = nftnl_rule_get_comment(nlr);