Module Name:    src
Committed By:   mlelstv
Date:           Sat Apr  4 07:07:20 UTC 2020

Modified Files:
        src/sys/nfs: nfs_serv.c nfs_subs.c nfsm_subs.h

Log Message:
NFSv2 is limited to use only 32bit in metadata. Prevent that larger
metadata values are simply truncated.

-> clamp filesystem block counts to signed 32bit.
-> clamp file sizes to signed 32bit (*)

Some NFSv2 clients also have problems to handle buffer sizes larger
than (signed) 16bit.
-> clamp buffer sizes to signed 16bit for better compatibility.

(*) This can lead to erroneous behaviour for files larger than 2GB
that NFSv2 cannot handle but it is still better than before.
An alternative would be to (partially) reject operations on files
larger than 2GB, but which causes other problems.


To generate a diff of this commit:
cvs rdiff -u -r1.179 -r1.180 src/sys/nfs/nfs_serv.c
cvs rdiff -u -r1.238 -r1.239 src/sys/nfs/nfs_subs.c
cvs rdiff -u -r1.53 -r1.54 src/sys/nfs/nfsm_subs.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/nfs/nfs_serv.c
diff -u src/sys/nfs/nfs_serv.c:1.179 src/sys/nfs/nfs_serv.c:1.180
--- src/sys/nfs/nfs_serv.c:1.179	Fri Jan 17 20:08:09 2020
+++ src/sys/nfs/nfs_serv.c	Sat Apr  4 07:07:20 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_serv.c,v 1.179 2020/01/17 20:08:09 ad Exp $	*/
+/*	$NetBSD: nfs_serv.c,v 1.180 2020/04/04 07:07:20 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -55,7 +55,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_serv.c,v 1.179 2020/01/17 20:08:09 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_serv.c,v 1.180 2020/04/04 07:07:20 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -3394,10 +3394,10 @@ nfsrv_statfs(struct nfsrv_descript *nfsd
 		sfp->sf_invarsec = 0;
 	} else {
 		sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
-		sfp->sf_bsize = txdr_unsigned(sf->f_frsize);
-		sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
-		sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
-		sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
+		sfp->sf_bsize = txdr_unsigned(NFS_V2CLAMP16(sf->f_frsize));
+		sfp->sf_blocks = txdr_unsigned(NFS_V2CLAMP32(sf->f_blocks));
+		sfp->sf_bfree = txdr_unsigned(NFS_V2CLAMP32(sf->f_bfree));
+		sfp->sf_bavail = txdr_unsigned(NFS_V2CLAMP32(sf->f_bavail));
 	}
 nfsmout:
 	if (sf)

Index: src/sys/nfs/nfs_subs.c
diff -u src/sys/nfs/nfs_subs.c:1.238 src/sys/nfs/nfs_subs.c:1.239
--- src/sys/nfs/nfs_subs.c:1.238	Sun Mar  8 22:12:42 2020
+++ src/sys/nfs/nfs_subs.c	Sat Apr  4 07:07:20 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfs_subs.c,v 1.238 2020/03/08 22:12:42 mgorny Exp $	*/
+/*	$NetBSD: nfs_subs.c,v 1.239 2020/04/04 07:07:20 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.238 2020/03/08 22:12:42 mgorny Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.239 2020/04/04 07:07:20 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_nfs.h"
@@ -1696,8 +1696,8 @@ nfsm_srvfattr(struct nfsrv_descript *nfs
 	} else {
 		fp->fa_type = vtonfsv2_type(vap->va_type);
 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
-		fp->fa2_size = txdr_unsigned(vap->va_size);
-		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
+		fp->fa2_size = txdr_unsigned(NFS_V2CLAMP32(vap->va_size));
+		fp->fa2_blocksize = txdr_unsigned(NFS_V2CLAMP16(vap->va_blocksize));
 		if (vap->va_type == VFIFO)
 			fp->fa2_rdev = 0xffffffff;
 		else

Index: src/sys/nfs/nfsm_subs.h
diff -u src/sys/nfs/nfsm_subs.h:1.53 src/sys/nfs/nfsm_subs.h:1.54
--- src/sys/nfs/nfsm_subs.h:1.53	Sat Sep 14 22:29:08 2013
+++ src/sys/nfs/nfsm_subs.h	Sat Apr  4 07:07:20 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: nfsm_subs.h,v 1.53 2013/09/14 22:29:08 martin Exp $	*/
+/*	$NetBSD: nfsm_subs.h,v 1.54 2020/04/04 07:07:20 mlelstv Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -55,6 +55,14 @@
 				(((m)->m_flags & M_PKTHDR) ? MHLEN : MLEN))
 
 /*
+ * NFSv2 can only handle signed 32bit quantities and some clients
+ * get confused by larger than 16bit block sizes. Limit values
+ * for better compatibility.
+ */
+#define NFS_V2CLAMP32(x) ((x) > INT32_MAX ? INT32_MAX : (int32_t)(x))
+#define NFS_V2CLAMP16(x) ((x) > INT16_MAX ? INT16_MAX : (int32_t)(x))
+
+/*
  * Now for the macros that do the simple stuff and call the functions
  * for the hard stuff.
  * These macros use several vars. declared in nfsm_reqhead and these

Reply via email to