Module Name:    src
Committed By:   martin
Date:           Thu Apr  4 12:51:40 UTC 2013

Modified Files:
        src/sys/kern: sys_generic.c

Log Message:
Provide binary compatibility for architectures that (erroneously) had
a larger MAXPARTITIONS value (and thus larger struct disklabel).


To generate a diff of this commit:
cvs rdiff -u -r1.128 -r1.129 src/sys/kern/sys_generic.c

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

Modified files:

Index: src/sys/kern/sys_generic.c
diff -u src/sys/kern/sys_generic.c:1.128 src/sys/kern/sys_generic.c:1.129
--- src/sys/kern/sys_generic.c:1.128	Wed Jan 25 00:28:36 2012
+++ src/sys/kern/sys_generic.c	Thu Apr  4 12:51:39 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_generic.c,v 1.128 2012/01/25 00:28:36 christos Exp $	*/
+/*	$NetBSD: sys_generic.c,v 1.129 2013/04/04 12:51:39 martin Exp $	*/
 
 /*-
  * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_generic.c,v 1.128 2012/01/25 00:28:36 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_generic.c,v 1.129 2013/04/04 12:51:39 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -526,6 +526,12 @@ sys_ioctl(struct lwp *l, const struct sy
 	void 		*data, *memp;
 #define	STK_PARAMS	128
 	u_long		stkbuf[STK_PARAMS/sizeof(u_long)];
+#if  __TMPBIGMAXPARTITIONS > MAXPARTITIONS
+	size_t		zero_last = 0;
+#define	zero_size(SZ)	((SZ)+zero_last)
+#else
+#define	zero_size(SZ)	(SZ)
+#endif
 
 	memp = NULL;
 	alloc_size = 0;
@@ -563,7 +569,34 @@ sys_ioctl(struct lwp *l, const struct sy
 	 * but only copyin/out the smaller amount.
 	 */
 	if (IOCGROUP(com) == 'd') {
+#if  __TMPBIGMAXPARTITIONS > MAXPARTITIONS
+		u_long ocom = com;
+#endif
 		u_long ncom = com ^ (DIOCGDINFO ^ DIOCGDINFO32);
+
+#if  __TMPBIGMAXPARTITIONS > MAXPARTITIONS
+	/*
+	 * Userland might use struct disklabel that is bigger than the
+	 * the kernel version (historic accident) - alloc userland
+	 * size and zero unused part on copyout.
+	 */
+#define	DISKLABELLENDIFF	(sizeof(struct partition)	\
+				       *(__TMPBIGMAXPARTITIONS-MAXPARTITIONS))
+#define	IOCFIXUP(NIOC)	((NIOC&~(IOCPARM_MASK<<IOCPARM_SHIFT))	| \
+			   (IOCPARM_LEN(NIOC)-DISKLABELLENDIFF)<<IOCPARM_SHIFT)
+
+		switch (IOCFIXUP(ocom)) {
+		case DIOCGDINFO:
+		case DIOCWDINFO:
+		case DIOCSDINFO:
+		case DIOCGDEFLABEL:
+			com = ncom = IOCFIXUP(ocom);
+			zero_last = DISKLABELLENDIFF;
+			size -= DISKLABELLENDIFF;
+			goto done;
+		}
+#endif
+
 		switch (ncom) {
 		case DIOCGDINFO:
 		case DIOCWDINFO:
@@ -574,6 +607,9 @@ sys_ioctl(struct lwp *l, const struct sy
 				alloc_size = IOCPARM_LEN(DIOCGDINFO);
 			break;
 		}
+#if  __TMPBIGMAXPARTITIONS > MAXPARTITIONS
+		done: ;
+#endif
 	}
 	if (size > IOCPARM_MAX) {
 		error = ENOTTY;
@@ -615,7 +651,7 @@ sys_ioctl(struct lwp *l, const struct sy
 			 * Zero the buffer so the user always
 			 * gets back something deterministic.
 			 */
-			memset(data, 0, size);
+			memset(data, 0, zero_size(size));
 		} else if (com&IOC_VOID) {
 			*(void **)data = SCARG(uap, data);
 		}
@@ -648,7 +684,8 @@ sys_ioctl(struct lwp *l, const struct sy
 		 * already set and checked above.
 		 */
 		if (error == 0 && (com&IOC_OUT) && size) {
-			error = copyout(data, SCARG(uap, data), size);
+			error = copyout(data, SCARG(uap, data),
+			    zero_size(size));
 			ktrgenio(SCARG(uap, fd), UIO_READ, SCARG(uap, data),
 			    size, error);
 		}

Reply via email to