payload expression might use more than one single register and clobber previous data, reset tracking for the remaining registers too. Fixes: a7c176bf9f0e ("netfilter: nft_payload: track register operations") Reported-by: Florian Westphal <fw@xxxxxxxxx> Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- net/netfilter/nft_payload.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c index 5cc06aef4345..431f70c8bc15 100644 --- a/net/netfilter/nft_payload.c +++ b/net/netfilter/nft_payload.c @@ -210,6 +210,23 @@ static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr) return -1; } +static void nft_update_reg_track(struct nft_regs_track *track, + const struct nft_expr *expr, u8 dreg, u8 len) +{ + unsigned int regcount; + int i; + + track->regs[dreg].selector = expr; + track->regs[dreg].bitwise = NULL; + + dreg++; + regcount = DIV_ROUND_UP(len, NFT_REG32_SIZE); + for (i = 1; i < regcount; i++, dreg++) { + track->regs[dreg].selector = NULL; + track->regs[dreg].bitwise = NULL; + } +} + static bool nft_payload_reduce(struct nft_regs_track *track, const struct nft_expr *expr) { @@ -218,8 +235,7 @@ static bool nft_payload_reduce(struct nft_regs_track *track, if (!track->regs[priv->dreg].selector || track->regs[priv->dreg].selector->ops != expr->ops) { - track->regs[priv->dreg].selector = expr; - track->regs[priv->dreg].bitwise = NULL; + nft_update_reg_track(track, expr, priv->dreg, priv->len); return false; } @@ -227,8 +243,7 @@ static bool nft_payload_reduce(struct nft_regs_track *track, if (priv->base != payload->base || priv->offset != payload->offset || priv->len != payload->len) { - track->regs[priv->dreg].selector = expr; - track->regs[priv->dreg].bitwise = NULL; + nft_update_reg_track(track, expr, priv->dreg, priv->len); return false; } -- 2.30.2