kern/18874: 32bit NFS servers export wrong negative values to 64bit clients

Bruce Evans bde at zeta.org.au
Fri Apr 23 08:00:38 PDT 2004


The following reply was made to PR kern/18874; it has been noted by GNATS.

From: Bruce Evans <bde at zeta.org.au>
To: "Tim J. Robbins" <tjr at freebsd.org>
Cc: alex at big.endian.de, freebsd-gnats-submit at freebsd.org
Subject: Re: kern/18874: 32bit NFS servers export wrong negative values to
 64bit clients
Date: Sat, 24 Apr 2004 00:58:48 +1000 (EST)

 On Fri, 23 Apr 2004, Tim J. Robbins wrote:
 
 > Synopsis: 32bit NFS servers export wrong negative values to 64bit clients
 >
 > State-Changed-From-To: suspended->patched
 > State-Changed-By: tjr
 > State-Changed-When: Fri Apr 23 06:15:28 PDT 2004
 > State-Changed-Why:
 > Fixed in -current by mux at .
 
 The fix is wrong, since it breaks sending negative block counts to
 clients which understand them.  BSD clients have supported this since at
 least 4.4BSD, but the code is broken for the nfsv3 case.  This is fixed
 for small negative values in NetBSD by casting to a signed type as
 discussed in the followup to this PR.
 
 Sign extension bugs are closely related to overflow bugs here and
 elsewhere.  Overflow occurs for block counts that represent byte
 counts >= 1TB (PR 56606).  FreeBSD has wrong fixes for this.  See
 the PR followup for more details.
 
 The bugs have now mostly moved to cvtstatfs().  They now also affect
 callers of the old statfs() family.  Overflow problems in nfs_statfs()
 should have gone away, since 64-bit byte counts easily fit in 64-bit
 block counters after dividing by the 512.  However, nfs still thinks
 that block counters are longs and it makes messes trying to get the
 64-bit counts to fit in possibly-32-bit longs.  See the followup to
 PR 56606 for a hopefully working version.  This code needs to move
 to RELENG_4's nfs_statfs() and -current's cvtstatfs().  cvstatfs() is
 simple and broken.  It attempts to truncate large values but has some
 sign bugs:
 
 % static void
 % cvtstatfs(td, nsp, osp)
 % 	struct thread *td;
 % 	struct statfs *nsp;
 % 	struct ostatfs *osp;
 % {
 %
 % 	bzero(osp, sizeof(*osp));
 % 	osp->f_bsize = MIN(nsp->f_bsize, LONG_MAX);
 % 	osp->f_iosize = MIN(nsp->f_iosize, LONG_MAX);
 % 	osp->f_blocks = MIN(nsp->f_blocks, LONG_MAX);
 % 	osp->f_bfree = MIN(nsp->f_bfree, LONG_MAX);
 % 	osp->f_bavail = MIN(nsp->f_bavail, LONG_MAX);
 % 	osp->f_files = MIN(nsp->f_files, LONG_MAX);
 % 	osp->f_ffree = MIN(nsp->f_ffree, LONG_MAX);
 
 Mount of the fields in the new statfs struct are (bogusly) unsigned
 where they used to be signed.  The clamps work for these.  However,
 f_bavail and f_free are signed, so the above assignments to their "old"
 values overflow if their "new" values are < LONG_MIN.
 
 Bruce


More information about the freebsd-bugs mailing list