From 83241d3f173dd57c3fdc347490213776a070fa40 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 23 Nov 2022 14:44:22 +0100 Subject: iptables-nft: exit nonzero when iptables-save cannot decode all expressions We always return 0, even if we printed some error message half-way. Increment an error counter whenever an error message was printed so that the chain-loop can exit with an error if this counter is nonzero. Another effect is that iptables-save will no longer print the COMMIT line anmore. Reported-by: Phil Sutter Signed-off-by: Florian Westphal Acked-by: Phil Sutter --- iptables/nft-bridge.c | 4 ++-- iptables/nft-shared.c | 10 +++++++--- iptables/nft-shared.h | 4 ++-- iptables/nft.c | 26 ++++++++++++++++++++------ iptables/nft.h | 2 +- 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c index e8ac7a36..4367d072 100644 --- a/iptables/nft-bridge.c +++ b/iptables/nft-bridge.c @@ -563,12 +563,12 @@ static void nft_bridge_parse_target(struct xtables_target *t, cs->jumpto = t->name; } -static void nft_rule_to_ebtables_command_state(struct nft_handle *h, +static bool nft_rule_to_ebtables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs) { cs->eb.bitmask = EBT_NOPROTO; - nft_rule_to_iptables_command_state(h, r, cs); + return nft_rule_to_iptables_command_state(h, r, cs); } static void print_iface(const char *option, const char *name, bool invert) diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c index 97512e3f..63d25198 100644 --- a/iptables/nft-shared.c +++ b/iptables/nft-shared.c @@ -1199,7 +1199,7 @@ static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e) } } -void nft_rule_to_iptables_command_state(struct nft_handle *h, +bool nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs) { @@ -1210,10 +1210,11 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, .h = h, .table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE), }; + bool ret = true; iter = nftnl_expr_iter_create(r); if (iter == NULL) - return; + return false; ctx.iter = iter; expr = nftnl_expr_iter_next(iter); @@ -1249,6 +1250,7 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, if (ctx.errmsg) { fprintf(stderr, "%s", ctx.errmsg); ctx.errmsg = NULL; + ret = false; } expr = nftnl_expr_iter_next(iter); @@ -1270,7 +1272,7 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, match = xtables_find_match("comment", XTF_TRY_LOAD, &cs->matches); if (match == NULL) - return; + return false; size = XT_ALIGN(sizeof(struct xt_entry_match)) + match->size; @@ -1287,6 +1289,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h, if (!cs->jumpto) cs->jumpto = ""; + + return ret; } void nft_clear_iptables_command_state(struct iptables_command_state *cs) diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h index 3d935d53..e2c3ac7b 100644 --- a/iptables/nft-shared.h +++ b/iptables/nft-shared.h @@ -159,7 +159,7 @@ struct nft_family_ops { void (*parse_target)(struct xtables_target *t, struct iptables_command_state *cs); void (*init_cs)(struct iptables_command_state *cs); - void (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r, + bool (*rule_to_cs)(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); void (*clear_cs)(struct iptables_command_state *cs); int (*xlate)(const struct iptables_command_state *cs, @@ -213,7 +213,7 @@ int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key, unsigned char *outiface_mask, uint8_t *invflags); void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op); void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv); -void nft_rule_to_iptables_command_state(struct nft_handle *h, +bool nft_rule_to_iptables_command_state(struct nft_handle *h, const struct nftnl_rule *r, struct iptables_command_state *cs); void nft_clear_iptables_command_state(struct iptables_command_state *cs); diff --git a/iptables/nft.c b/iptables/nft.c index 4c0110bb..67c5877c 100644 --- a/iptables/nft.c +++ b/iptables/nft.c @@ -1748,15 +1748,16 @@ nft_rule_append(struct nft_handle *h, const char *chain, const char *table, return 1; } -void +bool nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, enum nft_rule_print type, unsigned int format) { const char *chain = nftnl_rule_get_str(r, NFTNL_RULE_CHAIN); struct iptables_command_state cs = {}; struct nft_family_ops *ops = h->ops; + bool ret; - ops->rule_to_cs(h, r, &cs); + ret = ops->rule_to_cs(h, r, &cs); if (!(format & (FMT_NOCOUNTS | FMT_C_COUNTS))) printf("[%llu:%llu] ", (unsigned long long)cs.counters.pcnt, @@ -1777,6 +1778,8 @@ nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, if (ops->clear_cs) ops->clear_cs(&cs); + + return ret; } static bool nft_rule_is_policy_rule(struct nftnl_rule *r) @@ -1887,6 +1890,7 @@ int nft_chain_save(struct nft_chain *nc, void *data) struct nft_rule_save_data { struct nft_handle *h; unsigned int format; + unsigned int errors; }; static int nft_rule_save_cb(struct nft_chain *c, void *data) @@ -1901,7 +1905,11 @@ static int nft_rule_save_cb(struct nft_chain *c, void *data) r = nftnl_rule_iter_next(iter); while (r != NULL) { - nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format); + bool ret = nft_rule_print_save(d->h, r, NFT_RULE_APPEND, d->format); + + if (!ret) + d->errors++; + r = nftnl_rule_iter_next(iter); } @@ -1919,6 +1927,9 @@ int nft_rule_save(struct nft_handle *h, const char *table, unsigned int format) ret = nft_chain_foreach(h, table, nft_rule_save_cb, &d); + if (ret == 0 && d.errors) + xtables_error(VERSION_PROBLEM, "Cannot decode all rules provided by kernel"); + /* the core expects 1 for success and 0 for error */ return ret == 0 ? 1 : 0; } @@ -2341,15 +2352,18 @@ static bool nft_rule_cmp(struct nft_handle *h, struct nftnl_rule *r, struct nftnl_rule *rule) { struct iptables_command_state _cs = {}, this = {}, *cs = &_cs; - bool ret = false; + bool ret = false, ret_this, ret_that; - h->ops->rule_to_cs(h, r, &this); - h->ops->rule_to_cs(h, rule, cs); + ret_this = h->ops->rule_to_cs(h, r, &this); + ret_that = h->ops->rule_to_cs(h, rule, cs); DEBUGP("comparing with... "); #ifdef DEBUG_DEL nft_rule_print_save(h, r, NFT_RULE_APPEND, 0); #endif + if (!ret_this || !ret_that) + DEBUGP("Cannot convert rules: %d %d\n", ret_this, ret_that); + if (!h->ops->is_same(cs, &this)) goto out; diff --git a/iptables/nft.h b/iptables/nft.h index 68b0910c..caff1fde 100644 --- a/iptables/nft.h +++ b/iptables/nft.h @@ -203,7 +203,7 @@ enum nft_rule_print { NFT_RULE_DEL, }; -void nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, +bool nft_rule_print_save(struct nft_handle *h, const struct nftnl_rule *r, enum nft_rule_print type, unsigned int format); uint32_t nft_invflags2cmp(uint32_t invflags, uint32_t flag); -- cgit v1.2.3