1*0616c1c3SMichael Corcoran /* 2*0616c1c3SMichael Corcoran * CDDL HEADER START 3*0616c1c3SMichael Corcoran * 4*0616c1c3SMichael Corcoran * The contents of this file are subject to the terms of the 5*0616c1c3SMichael Corcoran * Common Development and Distribution License (the "License"). 6*0616c1c3SMichael Corcoran * You may not use this file except in compliance with the License. 7*0616c1c3SMichael Corcoran * 8*0616c1c3SMichael Corcoran * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*0616c1c3SMichael Corcoran * or http://www.opensolaris.org/os/licensing. 10*0616c1c3SMichael Corcoran * See the License for the specific language governing permissions 11*0616c1c3SMichael Corcoran * and limitations under the License. 12*0616c1c3SMichael Corcoran * 13*0616c1c3SMichael Corcoran * When distributing Covered Code, include this CDDL HEADER in each 14*0616c1c3SMichael Corcoran * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*0616c1c3SMichael Corcoran * If applicable, add the following below this CDDL HEADER, with the 16*0616c1c3SMichael Corcoran * fields enclosed by brackets "[]" replaced with your own identifying 17*0616c1c3SMichael Corcoran * information: Portions Copyright [yyyy] [name of copyright owner] 18*0616c1c3SMichael Corcoran * 19*0616c1c3SMichael Corcoran * CDDL HEADER END 20*0616c1c3SMichael Corcoran */ 21*0616c1c3SMichael Corcoran /* 22*0616c1c3SMichael Corcoran * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*0616c1c3SMichael Corcoran * Use is subject to license terms. 24*0616c1c3SMichael Corcoran */ 25*0616c1c3SMichael Corcoran 26*0616c1c3SMichael Corcoran #include <sys/types.h> 27*0616c1c3SMichael Corcoran #include <sys/errno.h> 28*0616c1c3SMichael Corcoran #include <sys/mman.h> 29*0616c1c3SMichael Corcoran #include <sys/cred.h> 30*0616c1c3SMichael Corcoran #include <sys/model.h> 31*0616c1c3SMichael Corcoran #include <sys/vnode.h> 32*0616c1c3SMichael Corcoran #include <sys/systm.h> 33*0616c1c3SMichael Corcoran #include <sys/kmem.h> 34*0616c1c3SMichael Corcoran #include <sys/file.h> 35*0616c1c3SMichael Corcoran #include <sys/vfs.h> 36*0616c1c3SMichael Corcoran #include <sys/sysmacros.h> 37*0616c1c3SMichael Corcoran #include <sys/mmapobj.h> 38*0616c1c3SMichael Corcoran 39*0616c1c3SMichael Corcoran /* 40*0616c1c3SMichael Corcoran * We will "allocate" this many mmapobj_result_t segments on the stack 41*0616c1c3SMichael Corcoran * in an attempt to avoid the need to call kmem_alloc. This value should 42*0616c1c3SMichael Corcoran * cover 99% of the known ELF libraries as well as AOUT (4.x) libraries. 43*0616c1c3SMichael Corcoran */ 44*0616c1c3SMichael Corcoran #define MOBJ_STACK_SEGS 6 45*0616c1c3SMichael Corcoran 46*0616c1c3SMichael Corcoran static void 47*0616c1c3SMichael Corcoran mmapobj_copy_64to32(mmapobj_result_t *source, mmapobj_result32_t *dest, int num) 48*0616c1c3SMichael Corcoran { 49*0616c1c3SMichael Corcoran int i; 50*0616c1c3SMichael Corcoran 51*0616c1c3SMichael Corcoran for (i = 0; i < num; i++) { 52*0616c1c3SMichael Corcoran dest[i].mr_addr = (caddr32_t)(uintptr_t)source[i].mr_addr; 53*0616c1c3SMichael Corcoran dest[i].mr_msize = (size32_t)source[i].mr_msize; 54*0616c1c3SMichael Corcoran dest[i].mr_fsize = (size32_t)source[i].mr_fsize; 55*0616c1c3SMichael Corcoran dest[i].mr_offset = (size32_t)source[i].mr_offset; 56*0616c1c3SMichael Corcoran dest[i].mr_prot = source[i].mr_prot; 57*0616c1c3SMichael Corcoran dest[i].mr_flags = source[i].mr_flags; 58*0616c1c3SMichael Corcoran } 59*0616c1c3SMichael Corcoran } 60*0616c1c3SMichael Corcoran 61*0616c1c3SMichael Corcoran int 62*0616c1c3SMichael Corcoran mmapobjsys(int fd, uint_t flags, mmapobj_result_t *storage, 63*0616c1c3SMichael Corcoran uint_t *elements, void *arg) 64*0616c1c3SMichael Corcoran { 65*0616c1c3SMichael Corcoran uint_t num_mapped; 66*0616c1c3SMichael Corcoran uint_t num_in; 67*0616c1c3SMichael Corcoran int error; 68*0616c1c3SMichael Corcoran int old_error; 69*0616c1c3SMichael Corcoran size_t padding = 0; 70*0616c1c3SMichael Corcoran mmapobj_result_t stack_mr[MOBJ_STACK_SEGS]; 71*0616c1c3SMichael Corcoran mmapobj_result_t *mrp = stack_mr; 72*0616c1c3SMichael Corcoran struct file *fp; 73*0616c1c3SMichael Corcoran struct vnode *vp; 74*0616c1c3SMichael Corcoran model_t model; 75*0616c1c3SMichael Corcoran int convert_64to32 = 0; 76*0616c1c3SMichael Corcoran uint_t alloc_num = 0; 77*0616c1c3SMichael Corcoran 78*0616c1c3SMichael Corcoran 79*0616c1c3SMichael Corcoran /* Verify flags */ 80*0616c1c3SMichael Corcoran if ((flags & ~MMOBJ_ALL_FLAGS) != 0) { 81*0616c1c3SMichael Corcoran return (set_errno(EINVAL)); 82*0616c1c3SMichael Corcoran } 83*0616c1c3SMichael Corcoran 84*0616c1c3SMichael Corcoran if (((flags & MMOBJ_PADDING) == 0) && arg != NULL) { 85*0616c1c3SMichael Corcoran return (set_errno(EINVAL)); 86*0616c1c3SMichael Corcoran } 87*0616c1c3SMichael Corcoran 88*0616c1c3SMichael Corcoran fp = getf(fd); 89*0616c1c3SMichael Corcoran if (fp == NULL) { 90*0616c1c3SMichael Corcoran return (set_errno(EBADF)); 91*0616c1c3SMichael Corcoran } 92*0616c1c3SMichael Corcoran vp = fp->f_vnode; 93*0616c1c3SMichael Corcoran 94*0616c1c3SMichael Corcoran if ((fp->f_flag & FREAD) == 0) { 95*0616c1c3SMichael Corcoran error = EACCES; 96*0616c1c3SMichael Corcoran goto out; 97*0616c1c3SMichael Corcoran } 98*0616c1c3SMichael Corcoran 99*0616c1c3SMichael Corcoran error = copyin(elements, &num_mapped, sizeof (uint_t)); 100*0616c1c3SMichael Corcoran if (error) { 101*0616c1c3SMichael Corcoran error = EFAULT; 102*0616c1c3SMichael Corcoran goto out; 103*0616c1c3SMichael Corcoran } 104*0616c1c3SMichael Corcoran 105*0616c1c3SMichael Corcoran num_in = num_mapped; 106*0616c1c3SMichael Corcoran model = get_udatamodel(); 107*0616c1c3SMichael Corcoran if (model != DATAMODEL_NATIVE) { 108*0616c1c3SMichael Corcoran ASSERT(model == DATAMODEL_ILP32); 109*0616c1c3SMichael Corcoran convert_64to32 = 1; 110*0616c1c3SMichael Corcoran } 111*0616c1c3SMichael Corcoran 112*0616c1c3SMichael Corcoran if (flags & MMOBJ_PADDING) { 113*0616c1c3SMichael Corcoran if (convert_64to32) { 114*0616c1c3SMichael Corcoran size32_t padding32; 115*0616c1c3SMichael Corcoran error = copyin(arg, &padding32, sizeof (padding32)); 116*0616c1c3SMichael Corcoran padding = padding32; 117*0616c1c3SMichael Corcoran } else { 118*0616c1c3SMichael Corcoran error = copyin(arg, &padding, sizeof (padding)); 119*0616c1c3SMichael Corcoran } 120*0616c1c3SMichael Corcoran if (error) { 121*0616c1c3SMichael Corcoran error = EFAULT; 122*0616c1c3SMichael Corcoran goto out; 123*0616c1c3SMichael Corcoran } 124*0616c1c3SMichael Corcoran 125*0616c1c3SMichael Corcoran /* 126*0616c1c3SMichael Corcoran * Need to catch overflow here for the 64 bit case. For the 127*0616c1c3SMichael Corcoran * 32 bit case, overflow would round up to 4G which would 128*0616c1c3SMichael Corcoran * not be able to fit in any address space and thus ENOMEM 129*0616c1c3SMichael Corcoran * would be returned after calling into mmapobj. 130*0616c1c3SMichael Corcoran */ 131*0616c1c3SMichael Corcoran if (padding) { 132*0616c1c3SMichael Corcoran padding = P2ROUNDUP(padding, PAGESIZE); 133*0616c1c3SMichael Corcoran if (padding == 0) { 134*0616c1c3SMichael Corcoran error = ENOMEM; 135*0616c1c3SMichael Corcoran goto out; 136*0616c1c3SMichael Corcoran } 137*0616c1c3SMichael Corcoran } 138*0616c1c3SMichael Corcoran /* turn off padding if no bytes were requested */ 139*0616c1c3SMichael Corcoran if (padding == 0) { 140*0616c1c3SMichael Corcoran flags = flags & (~MMOBJ_PADDING); 141*0616c1c3SMichael Corcoran } 142*0616c1c3SMichael Corcoran } 143*0616c1c3SMichael Corcoran 144*0616c1c3SMichael Corcoran if (num_mapped > MOBJ_STACK_SEGS) { 145*0616c1c3SMichael Corcoran num_mapped = MOBJ_STACK_SEGS; 146*0616c1c3SMichael Corcoran } 147*0616c1c3SMichael Corcoran retry: 148*0616c1c3SMichael Corcoran error = mmapobj(vp, flags, mrp, &num_mapped, padding, fp->f_cred); 149*0616c1c3SMichael Corcoran 150*0616c1c3SMichael Corcoran if (error == E2BIG && alloc_num == 0) { 151*0616c1c3SMichael Corcoran if (num_mapped > MOBJ_STACK_SEGS && num_mapped <= num_in) { 152*0616c1c3SMichael Corcoran mrp = kmem_alloc(sizeof (mmapobj_result_t) * num_mapped, 153*0616c1c3SMichael Corcoran KM_SLEEP); 154*0616c1c3SMichael Corcoran alloc_num = num_mapped; 155*0616c1c3SMichael Corcoran goto retry; 156*0616c1c3SMichael Corcoran } 157*0616c1c3SMichael Corcoran } 158*0616c1c3SMichael Corcoran 159*0616c1c3SMichael Corcoran old_error = error; 160*0616c1c3SMichael Corcoran if (error == 0 || error == E2BIG) { 161*0616c1c3SMichael Corcoran error = copyout(&num_mapped, elements, sizeof (uint_t)); 162*0616c1c3SMichael Corcoran if (error) { 163*0616c1c3SMichael Corcoran error = EFAULT; 164*0616c1c3SMichael Corcoran /* 165*0616c1c3SMichael Corcoran * We only mapped in segments if the mmapobj call 166*0616c1c3SMichael Corcoran * succeeded, so only unmap for that case. 167*0616c1c3SMichael Corcoran */ 168*0616c1c3SMichael Corcoran if (old_error == 0) { 169*0616c1c3SMichael Corcoran mmapobj_unmap(mrp, num_mapped, num_mapped, 0); 170*0616c1c3SMichael Corcoran } 171*0616c1c3SMichael Corcoran } else if (num_in < num_mapped) { 172*0616c1c3SMichael Corcoran ASSERT(old_error == E2BIG); 173*0616c1c3SMichael Corcoran error = E2BIG; 174*0616c1c3SMichael Corcoran } else { 175*0616c1c3SMichael Corcoran if (convert_64to32) { 176*0616c1c3SMichael Corcoran mmapobj_result32_t *mrp32; 177*0616c1c3SMichael Corcoran /* Need to translate from 64bit to 32bit */ 178*0616c1c3SMichael Corcoran mrp32 = kmem_alloc(num_mapped * sizeof (*mrp32), 179*0616c1c3SMichael Corcoran KM_SLEEP); 180*0616c1c3SMichael Corcoran mmapobj_copy_64to32(mrp, mrp32, num_mapped); 181*0616c1c3SMichael Corcoran error = copyout(mrp32, (void *)storage, 182*0616c1c3SMichael Corcoran num_mapped * sizeof (mmapobj_result32_t)); 183*0616c1c3SMichael Corcoran kmem_free(mrp32, num_mapped * sizeof (*mrp32)); 184*0616c1c3SMichael Corcoran } else { 185*0616c1c3SMichael Corcoran error = copyout(mrp, (void *)storage, 186*0616c1c3SMichael Corcoran num_mapped * sizeof (mmapobj_result_t)); 187*0616c1c3SMichael Corcoran } 188*0616c1c3SMichael Corcoran if (error) { 189*0616c1c3SMichael Corcoran error = EFAULT; 190*0616c1c3SMichael Corcoran mmapobj_unmap(mrp, num_mapped, num_mapped, 0); 191*0616c1c3SMichael Corcoran } 192*0616c1c3SMichael Corcoran } 193*0616c1c3SMichael Corcoran } 194*0616c1c3SMichael Corcoran 195*0616c1c3SMichael Corcoran /* 196*0616c1c3SMichael Corcoran * If stack_mr was not large enough, then we had to allocate 197*0616c1c3SMichael Corcoran * a larger piece of memory to hold the mmapobj_result array. 198*0616c1c3SMichael Corcoran */ 199*0616c1c3SMichael Corcoran if (alloc_num != 0) { 200*0616c1c3SMichael Corcoran ASSERT(mrp != stack_mr); 201*0616c1c3SMichael Corcoran ASSERT(num_mapped > MOBJ_STACK_SEGS); 202*0616c1c3SMichael Corcoran kmem_free(mrp, 203*0616c1c3SMichael Corcoran alloc_num * sizeof (mmapobj_result_t)); 204*0616c1c3SMichael Corcoran } 205*0616c1c3SMichael Corcoran 206*0616c1c3SMichael Corcoran out: 207*0616c1c3SMichael Corcoran releasef(fd); 208*0616c1c3SMichael Corcoran if (error) { 209*0616c1c3SMichael Corcoran return (set_errno(error)); 210*0616c1c3SMichael Corcoran } else { 211*0616c1c3SMichael Corcoran return (0); 212*0616c1c3SMichael Corcoran } 213*0616c1c3SMichael Corcoran } 214