On Tue, Aug 13, 2019 at 08:44:06PM +0200, Florian Westphal wrote: > table bla { > chain foo { } > chain bar { jump foo } > } > } > > Fails to restore on big-endian platforms: > jump.nft:5:2-9: Error: Could not process rule: No such file or directory > jump foo > > nft passes a 0-length name to the kernel. > > This is because when we export the value (the string), we provide > the size of the destination buffer. > > In earlier versions, the parser allocated the name with the same > fixed size and all was fine. > > After the fix, the export places the name in the wrong location > in the destination buffer. > > This makes tests/shell/testcases/chains/0001jumps_0 work on s390x. > > Fixes: 142350f154c78 ("src: invalid read when importing chain name") > Signed-off-by: Florian Westphal <fw@xxxxxxxxx> > --- > src/datatype.c | 26 +++++++++++++++++--------- > src/netlink.c | 16 +++++++++++++--- > 2 files changed, 30 insertions(+), 12 deletions(-) > > diff --git a/src/datatype.c b/src/datatype.c > index 28f726f4e84c..6908bc22d783 100644 > --- a/src/datatype.c > +++ b/src/datatype.c > @@ -244,10 +244,24 @@ const struct datatype invalid_type = { > .print = invalid_type_print, > }; > > -static void verdict_type_print(const struct expr *expr, struct output_ctx *octx) > +static void verdict_jump_chain_print(const char *what, const struct expr *e, > + struct output_ctx *octx) > { > char chain[NFT_CHAIN_MAXNAMELEN]; Probably: chat chain[NFT_CHAIN_MAXNAMELEN + 1] = {}; to ensure space for \0. > + unsigned int len; > + > + memset(chain, 0, sizeof(chain)); remove this memset then. > + len = e->len / BITS_PER_BYTE; div_round_up() ? > + if (len >= sizeof(chain)) > + len = sizeof(chain) - 1; Probably BUG() here instead if e->len > NFT_CHAIN_MAXNAMELEN? This should not happen. > + > + mpz_export_data(chain, e->value, BYTEORDER_HOST_ENDIAN, len); > + nft_print(octx, "%s %s", what, chain); > +} > + > +static void verdict_type_print(const struct expr *expr, struct output_ctx *octx) > +{ > switch (expr->verdict) { > case NFT_CONTINUE: > nft_print(octx, "continue"); > @@ -257,10 +271,7 @@ static void verdict_type_print(const struct expr *expr, struct output_ctx *octx) > break; > case NFT_JUMP: > if (expr->chain->etype == EXPR_VALUE) { > - mpz_export_data(chain, expr->chain->value, > - BYTEORDER_HOST_ENDIAN, > - NFT_CHAIN_MAXNAMELEN); > - nft_print(octx, "jump %s", chain); > + verdict_jump_chain_print("jump", expr->chain, octx); > } else { > nft_print(octx, "jump "); > expr_print(expr->chain, octx); > @@ -268,10 +279,7 @@ static void verdict_type_print(const struct expr *expr, struct output_ctx *octx) > break; > case NFT_GOTO: > if (expr->chain->etype == EXPR_VALUE) { > - mpz_export_data(chain, expr->chain->value, > - BYTEORDER_HOST_ENDIAN, > - NFT_CHAIN_MAXNAMELEN); > - nft_print(octx, "goto %s", chain); > + verdict_jump_chain_print("goto", expr->chain, octx); > } else { > nft_print(octx, "goto "); > expr_print(expr->chain, octx); > diff --git a/src/netlink.c b/src/netlink.c > index aeeb12eaca93..f8e1120447d9 100644 > --- a/src/netlink.c > +++ b/src/netlink.c > @@ -222,17 +222,27 @@ static void netlink_gen_verdict(const struct expr *expr, > struct nft_data_linearize *data) > { > char chain[NFT_CHAIN_MAXNAMELEN]; ...[NFT_CHAIN_MAXNAMELEN + 1] = {}; > + unsigned int len; > > data->verdict = expr->verdict; > > switch (expr->verdict) { > case NFT_JUMP: > case NFT_GOTO: > + len = expr->chain->len / BITS_PER_BYTE; div_round_up() > + > + if (!len) > + BUG("chain length is 0"); > + > + if (len > sizeof(chain)) > + BUG("chain is too large (%u, %u max)", > + len, (unsigned int)sizeof(chain)); > + > + memset(chain, 0, sizeof(chain)); > + > mpz_export_data(chain, expr->chain->value, > - BYTEORDER_HOST_ENDIAN, > - NFT_CHAIN_MAXNAMELEN); > + BYTEORDER_HOST_ENDIAN, len); > snprintf(data->chain, NFT_CHAIN_MAXNAMELEN, "%s", chain); > - data->chain[NFT_CHAIN_MAXNAMELEN-1] = '\0'; > break; > } > } > -- > 2.21.0 >