Re: [netfilter-core] [PATCH net] netfilter: nf_tables: fix pointer math issue in nft_byteorder_eval()

From: Pablo Neira Ayuso
Date: Tue Feb 06 2024 - 06:36:27 EST


On Tue, Feb 06, 2024 at 12:29:51PM +0100, Pablo Neira Ayuso wrote:
> On Tue, Feb 06, 2024 at 12:11:12PM +0100, Florian Westphal wrote:
> > Michal Kubecek <mkubecek@xxxxxxx> wrote:
> > > I stumbled upon this when the issue got a CVE id (sigh) and I share
> > > Andrea's (Cc-ed) concern that the fix is incomplete. While the fix,
> > > commit c301f0981fdd ("netfilter: nf_tables: fix pointer math issue in
> > > nft_byteorder_eval()") now, fixes the destination side, src is still
> > > a pointer to u32, i.e. we are reading 64-bit values with relative
> > > offsets which are multiples of 32 bits.
> > >
> > > Shouldn't we fix this as well, e.g. like indicated below?
> >
> > No, please remove multi-elem support instead, nothing uses this feature.
>
> See attached patch.
>
> I posted this:
>
> https://patchwork.ozlabs.org/project/netfilter-devel/patch/20240202120602.5122-1-pablo@xxxxxxxxxxxxx/
>
> I can replace it by the attached patch if you prefer. This can only
> help in the future to microoptimize some set configurations, where
> several byteorder can be coalesced into one single expression.

I have to replace those index 'i' by simply dst instead, this is
obviosly incomplete.

> diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c
> index 8cf91e47fd7a..af3412602869 100644
> --- a/net/netfilter/nft_byteorder.c
> +++ b/net/netfilter/nft_byteorder.c
> @@ -43,18 +43,14 @@ void nft_byteorder_eval(const struct nft_expr *expr,
>
> switch (priv->op) {
> case NFT_BYTEORDER_NTOH:
> - for (i = 0; i < priv->len / 8; i++) {
> - src64 = nft_reg_load64(&src[i]);
> - nft_reg_store64(&dst64[i],
> - be64_to_cpu((__force __be64)src64));
> - }
> + src64 = nft_reg_load64(&src[i]);
> + nft_reg_store64(&dst64[i],
> + be64_to_cpu((__force __be64)src64));
> break;
> case NFT_BYTEORDER_HTON:
> - for (i = 0; i < priv->len / 8; i++) {
> - src64 = (__force __u64)
> - cpu_to_be64(nft_reg_load64(&src[i]));
> - nft_reg_store64(&dst64[i], src64);
> - }
> + src64 = (__force __u64)
> + cpu_to_be64(nft_reg_load64(&src[i]));
> + nft_reg_store64(&dst64[i], src64);
> break;
> }
> break;
> @@ -62,24 +58,20 @@ void nft_byteorder_eval(const struct nft_expr *expr,
> case 4:
> switch (priv->op) {
> case NFT_BYTEORDER_NTOH:
> - for (i = 0; i < priv->len / 4; i++)
> - dst[i] = ntohl((__force __be32)src[i]);
> + dst[i] = ntohl((__force __be32)src[i]);
> break;
> case NFT_BYTEORDER_HTON:
> - for (i = 0; i < priv->len / 4; i++)
> - dst[i] = (__force __u32)htonl(src[i]);
> + dst[i] = (__force __u32)htonl(src[i]);
> break;
> }
> break;
> case 2:
> switch (priv->op) {
> case NFT_BYTEORDER_NTOH:
> - for (i = 0; i < priv->len / 2; i++)
> - d16[i] = ntohs((__force __be16)s16[i]);
> + d16[i] = ntohs((__force __be16)s16[i]);
> break;
> case NFT_BYTEORDER_HTON:
> - for (i = 0; i < priv->len / 2; i++)
> - d16[i] = (__force __u16)htons(s16[i]);
> + d16[i] = (__force __u16)htons(s16[i]);
> break;
> }
> break;
> @@ -137,6 +129,9 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
> if (err < 0)
> return err;
>
> + if (priv->size != len)
> + return -EINVAL;
> +
> priv->len = len;
>
> if (len % size != 0)