On Wed, 2018-07-11 at 12:05 -0400, Steve Dickson wrote: > Hey Trond, > > On 07/11/2018 11:25 AM, Steve Dickson wrote: > > The cause is that the xdr_putlong uses a long to store the > > converted value, then passes it to fwrite as a byte buffer. > > Only the first 4 bytes are written, which is okay for a LE > > system after byteswapping, but writes all zeroes on BE systems. > > > > Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1261738 > > > > Reviewed-by: Chuck Lever <chuck.lever@xxxxxxxxxx> > > Signed-off-by: Steve Dickson <steved@xxxxxxxxxx> > > --- > > v4: Use UINT32_MAX instead of INT32_MAX in boundary check. > > Talking with some old crusty types ;-) they pointed out > that all these routines use a signed arguments and > always have... So again why is using an unsigned max > the right thing to do? As I said earlier, you are casting from a larger type to a smaller type, and you want it to work for both signed and unsigned 32-bit values. Consider this kind of code: int32_t foo = 0xFFFF0000; ret = xdrstdio_putlong(xdr, foo); Since foo is signed, then (long)foo ends up getting cast to 0xFFFFFFFFFFFF0000L, which is negative, but is > (long)INT32_MIN. So ret == TRUE; Now try: uint32_t bar = 0xFFFF0000U; ret = xdrstdio_putlong(xdr, bar); Since bar is unsigned, then (long)bar gets cast to 0xFFFF0000L. That is clearly > (long)INT32_MAX == 0x7FFFFFFFL, and so the above fails with ret == FALSE. BTW: The above is pretty much exactly how xdr_int32_t() and xdr_uint32_t() work. The former does a signed cast to long, while the latter does an unsigned cast to long. > > steved. > > > > > v3: Reworked the bounds checking > > > > v2: Added bounds checking > > Changed from unsigned to signed > > > > src/xdr_stdio.c | 15 ++++++++++++--- > > 1 file changed, 12 insertions(+), 3 deletions(-) > > > > diff --git a/src/xdr_stdio.c b/src/xdr_stdio.c > > index 4410262..846c7bf 100644 > > --- a/src/xdr_stdio.c > > +++ b/src/xdr_stdio.c > > @@ -38,6 +38,7 @@ > > */ > > > > #include <stdio.h> > > +#include <stdint.h> > > > > #include <arpa/inet.h> > > #include <rpc/types.h> > > @@ -103,10 +104,12 @@ xdrstdio_getlong(xdrs, lp) > > XDR *xdrs; > > long *lp; > > { > > + int32_t mycopy; > > > > - if (fread(lp, sizeof(int32_t), 1, (FILE *)xdrs->x_private) > > != 1) > > + if (fread(&mycopy, sizeof(int32_t), 1, (FILE *)xdrs- > > >x_private) != 1) > > return (FALSE); > > - *lp = (long)ntohl((u_int32_t)*lp); > > + > > + *lp = (long)ntohl(mycopy); > > return (TRUE); > > } > > > > @@ -115,8 +118,14 @@ xdrstdio_putlong(xdrs, lp) > > XDR *xdrs; > > const long *lp; > > { > > - long mycopy = (long)htonl((u_int32_t)*lp); > > + int32_t mycopy; > > + > > +#if defined(_LP64) > > + if ((*lp > UINT32_MAX) || (*lp < INT32_MIN)) > > + return (FALSE); > > +#endif > > > > + mycopy = (int32_t)htonl((int32_t)*lp); > > if (fwrite(&mycopy, sizeof(int32_t), 1, (FILE *)xdrs- > > >x_private) != 1) > > return (FALSE); > > return (TRUE); > > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-nfs" > in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Trond Myklebust Linux NFS client maintainer, Hammerspace trond.myklebust@xxxxxxxxxxxxxxx ��.n��������+%������w��{.n�����{��w���jg��������ݢj����G�������j:+v���w�m������w�������h�����٥