Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_tables: fix pointer math issue in nft_byteorder_eval()

The problem is in nft_byteorder_eval() where we are iterating through a
loop and writing to dst[0], dst[1], dst[2] and so on... On each
iteration we are writing 8 bytes. But dst[] is an array of u32 so each
element only has space for 4 bytes. That means that every iteration
overwrites part of the previous element.

I spotted this bug while reviewing commit caf3ef7468f7 ("netfilter:
nf_tables: prevent OOB access in nft_byteorder_eval") which is a related
issue. I think that the reason we have not detected this bug in testing
is that most of time we only write one element.

Fixes: ce1e7989d989 ("netfilter: nft_byteorder: provide 64bit le/be conversion")
Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Dan Carpenter and committed by
Pablo Neira Ayuso
c301f098 a44af08e

+6 -5
+2 -2
include/net/netfilter/nf_tables.h
··· 178 178 return *(__force __be32 *)sreg; 179 179 } 180 180 181 - static inline void nft_reg_store64(u32 *dreg, u64 val) 181 + static inline void nft_reg_store64(u64 *dreg, u64 val) 182 182 { 183 - put_unaligned(val, (u64 *)dreg); 183 + put_unaligned(val, dreg); 184 184 } 185 185 186 186 static inline u64 nft_reg_load64(const u32 *sreg)
+3 -2
net/netfilter/nft_byteorder.c
··· 38 38 39 39 switch (priv->size) { 40 40 case 8: { 41 + u64 *dst64 = (void *)dst; 41 42 u64 src64; 42 43 43 44 switch (priv->op) { 44 45 case NFT_BYTEORDER_NTOH: 45 46 for (i = 0; i < priv->len / 8; i++) { 46 47 src64 = nft_reg_load64(&src[i]); 47 - nft_reg_store64(&dst[i], 48 + nft_reg_store64(&dst64[i], 48 49 be64_to_cpu((__force __be64)src64)); 49 50 } 50 51 break; ··· 53 52 for (i = 0; i < priv->len / 8; i++) { 54 53 src64 = (__force __u64) 55 54 cpu_to_be64(nft_reg_load64(&src[i])); 56 - nft_reg_store64(&dst[i], src64); 55 + nft_reg_store64(&dst64[i], src64); 57 56 } 58 57 break; 59 58 }
+1 -1
net/netfilter/nft_meta.c
··· 63 63 { 64 64 switch (key) { 65 65 case NFT_META_TIME_NS: 66 - nft_reg_store64(dest, ktime_get_real_ns()); 66 + nft_reg_store64((u64 *)dest, ktime_get_real_ns()); 67 67 break; 68 68 case NFT_META_TIME_DAY: 69 69 nft_reg_store8(dest, nft_meta_weekday());