Module Name: src Committed By: matt Date: Tue Jan 18 19:52:24 UTC 2011
Modified Files: src/sys/compat/netbsd32: netbsd32_ioctl.c src/sys/kern: sys_generic.c src/sys/sys: disklabel.h dkio.h Log Message: Make struct disklabel 8 byte aligned. This increases its size by 4 bytes on IPL32 platforms so add code in sys_ioctl (and netbsd32_ioctl) to deal with the older/smaller diskabel size. This change makes disklabel the same for both IPL32 and LP64 platforms. To generate a diff of this commit: cvs rdiff -u -r1.51 -r1.52 src/sys/compat/netbsd32/netbsd32_ioctl.c cvs rdiff -u -r1.124 -r1.125 src/sys/kern/sys_generic.c cvs rdiff -u -r1.107 -r1.108 src/sys/sys/disklabel.h cvs rdiff -u -r1.16 -r1.17 src/sys/sys/dkio.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/compat/netbsd32/netbsd32_ioctl.c diff -u src/sys/compat/netbsd32/netbsd32_ioctl.c:1.51 src/sys/compat/netbsd32/netbsd32_ioctl.c:1.52 --- src/sys/compat/netbsd32/netbsd32_ioctl.c:1.51 Fri Sep 24 13:12:53 2010 +++ src/sys/compat/netbsd32/netbsd32_ioctl.c Tue Jan 18 19:52:24 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: netbsd32_ioctl.c,v 1.51 2010/09/24 13:12:53 njoly Exp $ */ +/* $NetBSD: netbsd32_ioctl.c,v 1.52 2011/01/18 19:52:24 matt Exp $ */ /* * Copyright (c) 1998, 2001 Matthew R. Green @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.51 2010/09/24 13:12:53 njoly Exp $"); +__KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.52 2011/01/18 19:52:24 matt Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -437,10 +437,11 @@ struct filedesc *fdp; u_long com; int error = 0; - u_int size, size32; + size_t size; + size_t alloc_size32, size32; void *data, *memp = NULL; void *data32, *memp32 = NULL; - unsigned fd; + unsigned int fd; fdfile_t *ff; int tmp; #define STK_PARAMS 128 @@ -453,17 +454,26 @@ */ #if 0 { -char *dirs[8] = { "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!", - "INOUT", "VOID|IN|OUT!" }; - -printf("netbsd32_ioctl(%d, %x, %x): %s group %c base %d len %d\n", - SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data), - dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)], - IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)), - IOCPARM_LEN(SCARG(uap, com))); + const char * const dirs[8] = { + "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!", + "INOUT", "VOID|IN|OUT!" + }; + + printf("netbsd32_ioctl(%d, %x, %x): " + "%s group %c base %d len %d\n", + SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data).i32, + dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)], + IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)), + IOCPARM_LEN(SCARG(uap, com))); } #endif + memp = NULL; + memp32 = NULL; + alloc_size32 = 0; + size32 = 0; + size = 0; + fdp = p->p_fd; fd = SCARG(uap, fd); if ((fp = fd_getfile(fd)) == NULL) @@ -489,37 +499,72 @@ * Interpret high order word to find amount of data to be * copied to/from the user's address space. */ - size = 0; size32 = IOCPARM_LEN(com); - if (size32 > IOCPARM_MAX) { + alloc_size32 = size32; + + /* + * The disklabel is now padded to a multiple of 8 bytes however the old + * disklabel on 32bit platforms wasn't. This leaves a difference in + * size of 4 bytes between the two but are otherwise identical. + * To deal with this, we allocate enough space for the new disklabel + * but only copyin/out the smaller amount. + */ + if (IOCGROUP(com) == 'd') { + u_long ncom = com ^ (DIOCGDINFO ^ DIOCGDINFO32); + switch (ncom) { + case DIOCGDINFO: + case DIOCWDINFO: + case DIOCSDINFO: + case DIOCGDEFLABEL: + com = ncom; + if (IOCPARM_LEN(DIOCGDINFO32) < IOCPARM_LEN(DIOCGDINFO)) + alloc_size32 = IOCPARM_LEN(DIOCGDINFO); + break; + } + } + if (alloc_size32 > IOCPARM_MAX) { error = ENOTTY; goto out; } - if (size32 > sizeof(stkbuf)) { - memp32 = kmem_alloc((size_t)size32, KM_SLEEP); + if (alloc_size32 > sizeof(stkbuf)) { + memp32 = kmem_alloc(alloc_size32, KM_SLEEP); data32 = memp32; } else data32 = (void *)stkbuf32; - if (com&IOC_IN) { - if (size32) { - error = copyin(SCARG_P32(uap, data), data32, size32); - if (error) { - if (memp32) - kmem_free(memp32, (size_t)size32); - goto out; - } - ktrgenio(fd, UIO_WRITE, SCARG_P32(uap, data), - size32, 0); - } else + if ((com >> IOCPARM_SHIFT) == 0) { + /* UNIX-style ioctl. */ + data32 = SCARG_P32(uap, data); + } else { + if (com&IOC_IN) { + if (size32) { + error = copyin(SCARG_P32(uap, data), data32, + size32); + if (error) { + goto out; + } + /* + * The data between size and alloc_size has + * not been overwritten. It shouldn't matter + * but let's clear that anyway. + */ + if (__predict_false(size32 < alloc_size32)) { + memset((char *)data32+size32, 0, + alloc_size32 - size32); + } + ktrgenio(fd, UIO_WRITE, SCARG_P32(uap, data), + size32, 0); + } else + *(void **)data32 = SCARG_P32(uap, data); + } else if ((com&IOC_OUT) && size32) { + /* + * Zero the buffer so the user always + * gets back something deterministic. + */ + memset(data32, 0, alloc_size32); + } else if (com&IOC_VOID) { *(void **)data32 = SCARG_P32(uap, data); - } else if ((com&IOC_OUT) && size32) - /* - * Zero the buffer so the user always - * gets back something deterministic. - */ - memset(data32, 0, size32); - else if (com&IOC_VOID) - *(void **)data32 = SCARG_P32(uap, data); + } + } /* * convert various structures, pointers, and other objects that @@ -690,12 +735,12 @@ size32, error); } + out: /* If we allocated data, free it here. */ if (memp32) - kmem_free(memp32, (size_t)size32); + kmem_free(memp32, alloc_size32); if (memp) - kmem_free(memp, (size_t)size); - out: + kmem_free(memp32, size); fd_putfile(fd); return (error); } Index: src/sys/kern/sys_generic.c diff -u src/sys/kern/sys_generic.c:1.124 src/sys/kern/sys_generic.c:1.125 --- src/sys/kern/sys_generic.c:1.124 Thu Aug 13 08:57:43 2009 +++ src/sys/kern/sys_generic.c Tue Jan 18 19:52:23 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_generic.c,v 1.124 2009/08/13 08:57:43 haad Exp $ */ +/* $NetBSD: sys_generic.c,v 1.125 2011/01/18 19:52:23 matt 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.124 2009/08/13 08:57:43 haad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_generic.c,v 1.125 2011/01/18 19:52:23 matt Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -90,6 +90,7 @@ #include <sys/syscallargs.h> #include <sys/ktrace.h> #include <sys/atomic.h> +#include <sys/disklabel.h> #include <uvm/uvm_extern.h> @@ -524,12 +525,14 @@ struct filedesc *fdp; u_long com; int error; - u_int size; + size_t size, alloc_size; void *data, *memp; #define STK_PARAMS 128 u_long stkbuf[STK_PARAMS/sizeof(u_long)]; fdfile_t *ff; + memp = NULL; + alloc_size = 0; error = 0; p = l->l_proc; fdp = p->p_fd; @@ -560,6 +563,28 @@ * copied to/from the user's address space. */ size = IOCPARM_LEN(com); + alloc_size = size; + + /* + * The disklabel is now padded to a multiple of 8 bytes however the old + * disklabel on 32bit platforms wasn't. This leaves a difference in + * size of 4 bytes between the two but are otherwise identical. + * To deal with this, we allocate enough space for the new disklabel + * but only copyin/out the smaller amount. + */ + if (IOCGROUP(com) == 'd') { + u_long ncom = com ^ (DIOCGDINFO ^ DIOCGDINFO32); + switch (ncom) { + case DIOCGDINFO: + case DIOCWDINFO: + case DIOCSDINFO: + case DIOCGDEFLABEL: + com = ncom; + if (IOCPARM_LEN(DIOCGDINFO32) < IOCPARM_LEN(DIOCGDINFO)) + alloc_size = IOCPARM_LEN(DIOCGDINFO); + break; + } + } if (size > IOCPARM_MAX) { error = ENOTTY; goto out; @@ -569,8 +594,8 @@ /* UNIX-style ioctl. */ data = SCARG(uap, data); } else { - if (size > sizeof(stkbuf)) { - memp = kmem_alloc(size, KM_SLEEP); + if (alloc_size > sizeof(stkbuf)) { + memp = kmem_alloc(alloc_size, KM_SLEEP); data = memp; } else { data = (void *)stkbuf; @@ -579,11 +604,17 @@ if (size) { error = copyin(SCARG(uap, data), data, size); if (error) { - if (memp) { - kmem_free(memp, size); - } goto out; } + /* + * The data between size and alloc_size has + * not been overwritten. It shouldn't matter + * but let's clear that anyway. + */ + if (__predict_false(size < alloc_size)) { + memset((char *)data+size, 0, + alloc_size - size); + } ktrgenio(SCARG(uap, fd), UIO_WRITE, SCARG(uap, data), size, 0); } else { @@ -633,9 +664,9 @@ } break; } - if (memp) - kmem_free(memp, size); out: + if (memp) + kmem_free(memp, alloc_size); fd_putfile(SCARG(uap, fd)); switch (error) { case -1: Index: src/sys/sys/disklabel.h diff -u src/sys/sys/disklabel.h:1.107 src/sys/sys/disklabel.h:1.108 --- src/sys/sys/disklabel.h:1.107 Tue Dec 22 18:55:25 2009 +++ src/sys/sys/disklabel.h Tue Jan 18 19:52:24 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: disklabel.h,v 1.107 2009/12/22 18:55:25 pooka Exp $ */ +/* $NetBSD: disklabel.h,v 1.108 2011/01/18 19:52:24 matt Exp $ */ /* * Copyright (c) 1987, 1988, 1993 @@ -117,6 +117,7 @@ char *un_d_boot0; /* primary bootstrap name */ char *un_d_boot1; /* secondary bootstrap name */ } un_b; + uint64_t un_d_pad; /* force 8 byte alignment */ } d_un; #define d_packname d_un.un_d_packname #define d_boot0 d_un.un_b.un_d_boot0 Index: src/sys/sys/dkio.h diff -u src/sys/sys/dkio.h:1.16 src/sys/sys/dkio.h:1.17 --- src/sys/sys/dkio.h:1.16 Mon Mar 22 16:49:41 2010 +++ src/sys/sys/dkio.h Tue Jan 18 19:52:24 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: dkio.h,v 1.16 2010/03/22 16:49:41 martin Exp $ */ +/* $NetBSD: dkio.h,v 1.17 2011/01/18 19:52:24 matt Exp $ */ /* * Copyright (c) 1987, 1988, 1993 @@ -44,6 +44,7 @@ #define DIOCWDINFO _IOW('d', 103, struct disklabel)/* set, update disk */ #ifdef _KERNEL +#define DIOCGDINFO32 (DIOCGDINFO - (sizeof(uint32_t) << IOCPARM_SHIFT)) #define DIOCGPART _IOW('d', 104, struct partinfo) /* get partition */ #endif