Message ID | 20220314140958.GE30883@kili (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | NFSD: prevent integer overflow on 32 bit systems | expand |
Hi Dan- > On Mar 14, 2022, at 10:09 AM, Dan Carpenter <dan.carpenter@oracle.com> wrote: > > On a 32 bit system, the "len * sizeof(*p)" operation can have an > integer overflow. > > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> > --- > It's hard to pick a Fixes tag for this... The temptation is to say: > Fixes: 37c88763def8 ("NFSv4; Clean up XDR encoding of type bitmap4") > But there were integer overflows in the code before that as well. > > include/linux/sunrpc/xdr.h | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h > index b519609af1d0..61b92e6b9813 100644 > --- a/include/linux/sunrpc/xdr.h > +++ b/include/linux/sunrpc/xdr.h > @@ -731,6 +731,8 @@ xdr_stream_decode_uint32_array(struct xdr_stream *xdr, > > if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) > return -EBADMSG; > + if (len > ULONG_MAX / sizeof(*p)) > + return -EBADMSG; IIUC xdr_inline_decode() returns NULL if the value of "len * sizeof(p)" is larger than the remaining XDR buffer size. I don't believe this extra check is necessary. > p = xdr_inline_decode(xdr, len * sizeof(*p)); > if (unlikely(!p)) > return -EBADMSG; > -- > 2.20.1 > -- Chuck Lever
On Mon, Mar 14, 2022 at 05:45:59PM +0300, Chuck Lever III wrote: > Hi Dan- > > > On Mar 14, 2022, at 10:09 AM, Dan Carpenter <dan.carpenter@oracle.com> wrote: > > > > On a 32 bit system, the "len * sizeof(*p)" operation can have an > > integer overflow. > > > > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> > > --- > > It's hard to pick a Fixes tag for this... The temptation is to say: > > Fixes: 37c88763def8 ("NFSv4; Clean up XDR encoding of type bitmap4") > > But there were integer overflows in the code before that as well. > > > > include/linux/sunrpc/xdr.h | 2 ++ > > 1 file changed, 2 insertions(+) > > > > diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h > > index b519609af1d0..61b92e6b9813 100644 > > --- a/include/linux/sunrpc/xdr.h > > +++ b/include/linux/sunrpc/xdr.h > > @@ -731,6 +731,8 @@ xdr_stream_decode_uint32_array(struct xdr_stream *xdr, > > > > if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) > > return -EBADMSG; > > + if (len > ULONG_MAX / sizeof(*p)) > > + return -EBADMSG; > > IIUC xdr_inline_decode() returns NULL if the value of > "len * sizeof(p)" is larger than the remaining XDR buffer > size. I don't believe this extra check is necessary. > Yes, but because of the integer overflow then "len * sizeof(*p))" will be a very reasonable small number. regards, dan carpenter > > > p = xdr_inline_decode(xdr, len * sizeof(*p)); > > if (unlikely(!p)) > > return -EBADMSG; > > -- > > 2.20.1 > > > > -- > Chuck Lever > >
> On Mar 14, 2022, at 1:03 PM, Dan Carpenter <dan.carpenter@oracle.com> wrote: > > On Mon, Mar 14, 2022 at 05:45:59PM +0300, Chuck Lever III wrote: >> Hi Dan- >> >>> On Mar 14, 2022, at 10:09 AM, Dan Carpenter <dan.carpenter@oracle.com> wrote: >>> >>> On a 32 bit system, the "len * sizeof(*p)" operation can have an >>> integer overflow. >>> >>> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> >>> --- >>> It's hard to pick a Fixes tag for this... The temptation is to say: >>> Fixes: 37c88763def8 ("NFSv4; Clean up XDR encoding of type bitmap4") >>> But there were integer overflows in the code before that as well. >>> >>> include/linux/sunrpc/xdr.h | 2 ++ >>> 1 file changed, 2 insertions(+) >>> >>> diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h >>> index b519609af1d0..61b92e6b9813 100644 >>> --- a/include/linux/sunrpc/xdr.h >>> +++ b/include/linux/sunrpc/xdr.h >>> @@ -731,6 +731,8 @@ xdr_stream_decode_uint32_array(struct xdr_stream *xdr, >>> >>> if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) >>> return -EBADMSG; >>> + if (len > ULONG_MAX / sizeof(*p)) >>> + return -EBADMSG; >> >> IIUC xdr_inline_decode() returns NULL if the value of >> "len * sizeof(p)" is larger than the remaining XDR buffer >> size. I don't believe this extra check is necessary. >> > > Yes, but because of the integer overflow then "len * sizeof(*p))" will > be a very reasonable small number. Got it. > regards, > dan carpenter > >> >>> p = xdr_inline_decode(xdr, len * sizeof(*p)); >>> if (unlikely(!p)) >>> return -EBADMSG; >>> -- >>> 2.20.1 >>> >> >> -- >> Chuck Lever -- Chuck Lever
On Mon, 2022-03-14 at 18:05 +0000, Chuck Lever III wrote: > > > > On Mar 14, 2022, at 1:03 PM, Dan Carpenter > > <dan.carpenter@oracle.com> wrote: > > > > On Mon, Mar 14, 2022 at 05:45:59PM +0300, Chuck Lever III wrote: > > > Hi Dan- > > > > > > > On Mar 14, 2022, at 10:09 AM, Dan Carpenter > > > > <dan.carpenter@oracle.com> wrote: > > > > > > > > On a 32 bit system, the "len * sizeof(*p)" operation can have > > > > an > > > > integer overflow. > > > > > > > > Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> > > > > --- > > > > It's hard to pick a Fixes tag for this... The temptation is to > > > > say: > > > > Fixes: 37c88763def8 ("NFSv4; Clean up XDR encoding of type > > > > bitmap4") > > > > But there were integer overflows in the code before that as > > > > well. > > > > > > > > include/linux/sunrpc/xdr.h | 2 ++ > > > > 1 file changed, 2 insertions(+) > > > > > > > > diff --git a/include/linux/sunrpc/xdr.h > > > > b/include/linux/sunrpc/xdr.h > > > > index b519609af1d0..61b92e6b9813 100644 > > > > --- a/include/linux/sunrpc/xdr.h > > > > +++ b/include/linux/sunrpc/xdr.h > > > > @@ -731,6 +731,8 @@ xdr_stream_decode_uint32_array(struct > > > > xdr_stream *xdr, > > > > > > > > if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) > > > > return -EBADMSG; > > > > + if (len > ULONG_MAX / sizeof(*p)) > > > > + return -EBADMSG; > > > > > > IIUC xdr_inline_decode() returns NULL if the value of > > > "len * sizeof(p)" is larger than the remaining XDR buffer > > > size. I don't believe this extra check is necessary. > > > > > > > Yes, but because of the integer overflow then "len * sizeof(*p))" > > will > > be a very reasonable small number. > > Got it. Shouldn't we technically rather specify SIZE_MAX instead of ULONG_MAX since xdr_inline_decode() takes a size_t?
Hi Dan, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on trondmy-nfs/linux-next] [also build test WARNING on linus/master v5.17-rc8 next-20220310] [cannot apply to cel-2.6/for-next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Dan-Carpenter/NFSD-prevent-integer-overflow-on-32-bit-systems/20220314-221126 base: git://git.linux-nfs.org/projects/trondmy/linux-nfs.git linux-next config: s390-randconfig-r044-20220314 (https://download.01.org/0day-ci/archive/20220315/202203150321.2NA8SWEv-lkp@intel.com/config) compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 3e4950d7fa78ac83f33bbf1658e2f49a73719236) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install s390 cross compiling tool for clang build # apt-get install binutils-s390x-linux-gnu # https://github.com/0day-ci/linux/commit/455f80f80ed34963bae40e552834c7483bcec80a git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Dan-Carpenter/NFSD-prevent-integer-overflow-on-32-bit-systems/20220314-221126 git checkout 455f80f80ed34963bae40e552834c7483bcec80a # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=s390 SHELL=/bin/bash net/ipv4/ If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): In file included from net/ipv4/ipconfig.c:45: In file included from include/linux/inet.h:42: In file included from include/net/net_namespace.h:40: In file included from include/linux/skbuff.h:31: In file included from include/linux/dma-mapping.h:10: In file included from include/linux/scatterlist.h:9: In file included from arch/s390/include/asm/io.h:75: include/asm-generic/io.h:464:31: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __raw_readb(PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:477:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __le16_to_cpu((__le16 __force)__raw_readw(PCI_IOBASE + addr)); ~~~~~~~~~~ ^ include/uapi/linux/byteorder/big_endian.h:37:59: note: expanded from macro '__le16_to_cpu' #define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x)) ^ include/uapi/linux/swab.h:102:54: note: expanded from macro '__swab16' #define __swab16(x) (__u16)__builtin_bswap16((__u16)(x)) ^ In file included from net/ipv4/ipconfig.c:45: In file included from include/linux/inet.h:42: In file included from include/net/net_namespace.h:40: In file included from include/linux/skbuff.h:31: In file included from include/linux/dma-mapping.h:10: In file included from include/linux/scatterlist.h:9: In file included from arch/s390/include/asm/io.h:75: include/asm-generic/io.h:490:61: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] val = __le32_to_cpu((__le32 __force)__raw_readl(PCI_IOBASE + addr)); ~~~~~~~~~~ ^ include/uapi/linux/byteorder/big_endian.h:35:59: note: expanded from macro '__le32_to_cpu' #define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x)) ^ include/uapi/linux/swab.h:115:54: note: expanded from macro '__swab32' #define __swab32(x) (__u32)__builtin_bswap32((__u32)(x)) ^ In file included from net/ipv4/ipconfig.c:45: In file included from include/linux/inet.h:42: In file included from include/net/net_namespace.h:40: In file included from include/linux/skbuff.h:31: In file included from include/linux/dma-mapping.h:10: In file included from include/linux/scatterlist.h:9: In file included from arch/s390/include/asm/io.h:75: include/asm-generic/io.h:501:33: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writeb(value, PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:511:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writew((u16 __force)cpu_to_le16(value), PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:521:59: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] __raw_writel((u32 __force)cpu_to_le32(value), PCI_IOBASE + addr); ~~~~~~~~~~ ^ include/asm-generic/io.h:609:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] readsb(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:617:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] readsw(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:625:20: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] readsl(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:634:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] writesb(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:643:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] writesw(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ include/asm-generic/io.h:652:21: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic] writesl(PCI_IOBASE + addr, buffer, count); ~~~~~~~~~~ ^ In file included from net/ipv4/ipconfig.c:59: In file included from include/linux/nfs_fs.h:31: In file included from include/linux/sunrpc/auth.h:13: In file included from include/linux/sunrpc/sched.h:19: >> include/linux/sunrpc/xdr.h:734:10: warning: result of comparison of constant 4611686018427387903 with expression of type '__u32' (aka 'unsigned int') is always false [-Wtautological-constant-out-of-range-compare] if (len > ULONG_MAX / sizeof(*p)) ~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~ 13 warnings generated. vim +734 include/linux/sunrpc/xdr.h 712 713 /** 714 * xdr_stream_decode_uint32_array - Decode variable length array of integers 715 * @xdr: pointer to xdr_stream 716 * @array: location to store the integer array or NULL 717 * @array_size: number of elements to store 718 * 719 * Return values: 720 * On success, returns number of elements stored in @array 721 * %-EBADMSG on XDR buffer overflow 722 * %-EMSGSIZE if the size of the array exceeds @array_size 723 */ 724 static inline ssize_t 725 xdr_stream_decode_uint32_array(struct xdr_stream *xdr, 726 __u32 *array, size_t array_size) 727 { 728 __be32 *p; 729 __u32 len; 730 ssize_t retval; 731 732 if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) 733 return -EBADMSG; > 734 if (len > ULONG_MAX / sizeof(*p)) 735 return -EBADMSG; 736 p = xdr_inline_decode(xdr, len * sizeof(*p)); 737 if (unlikely(!p)) 738 return -EBADMSG; 739 if (array == NULL) 740 return len; 741 if (len <= array_size) { 742 if (len < array_size) 743 memset(array+len, 0, (array_size-len)*sizeof(*array)); 744 array_size = len; 745 retval = len; 746 } else 747 retval = -EMSGSIZE; 748 for (; array_size > 0; p++, array++, array_size--) 749 *array = be32_to_cpup(p); 750 return retval; 751 } 752 --- 0-DAY CI Kernel Test Service https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
On Tue, Mar 15, 2022 at 03:57:36AM +0800, kernel test robot wrote: > In file included from net/ipv4/ipconfig.c:59: > In file included from include/linux/nfs_fs.h:31: > In file included from include/linux/sunrpc/auth.h:13: > In file included from include/linux/sunrpc/sched.h:19: > >> include/linux/sunrpc/xdr.h:734:10: warning: result of comparison of constant 4611686018427387903 with expression of type '__u32' (aka 'unsigned int') is always false [-Wtautological-constant-out-of-range-compare] > if (len > ULONG_MAX / sizeof(*p)) > ~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~ Smatch also wanted to send this warning. I am testing a fix to silence this warning in Smatch. It looks for an some_int > some_expression where some_expression has ULONG_MAX on the far left hand side of the binop. Because the some_expression always starts with ULONG_MAX and then divides it and/or subtracts from it to get the max. regards, dan carpenter
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h index b519609af1d0..61b92e6b9813 100644 --- a/include/linux/sunrpc/xdr.h +++ b/include/linux/sunrpc/xdr.h @@ -731,6 +731,8 @@ xdr_stream_decode_uint32_array(struct xdr_stream *xdr, if (unlikely(xdr_stream_decode_u32(xdr, &len) < 0)) return -EBADMSG; + if (len > ULONG_MAX / sizeof(*p)) + return -EBADMSG; p = xdr_inline_decode(xdr, len * sizeof(*p)); if (unlikely(!p)) return -EBADMSG;
On a 32 bit system, the "len * sizeof(*p)" operation can have an integer overflow. Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> --- It's hard to pick a Fixes tag for this... The temptation is to say: Fixes: 37c88763def8 ("NFSv4; Clean up XDR encoding of type bitmap4") But there were integer overflows in the code before that as well. include/linux/sunrpc/xdr.h | 2 ++ 1 file changed, 2 insertions(+)