1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1989 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * plock - lock "segments" in physical memory. 31 * 32 * Supports SVID-compatible plock, taking into account dynamically linked 33 * objects (such as shared libraries). 34 */ 35 36 #include <sys/types.h> 37 #include <sys/mman.h> 38 #include <sys/lock.h> 39 #include <sys/time.h> 40 #include <sys/resource.h> 41 #include <machine/param.h> 42 #include <machine/vmparam.h> 43 #include <a.out.h> 44 #include <link.h> 45 #include <errno.h> 46 47 /* 48 * Globals we reference. 49 */ 50 extern struct link_dynamic _DYNAMIC; 51 extern int mlock(); 52 extern int munlock(); 53 extern caddr_t sbrk(); /* find end of data segment */ 54 extern caddr_t etext; /* end of text segment */ 55 56 /* 57 * Module-scope variables. 58 */ 59 static int page_size = 0; /* cached result of getpagesize() */ 60 static int lock_state = 0; /* lock state */ 61 static int state_pid = -1; /* pid to which state belongs */ 62 63 /* 64 * Local worker routine to lock text and data segments. Handles 65 * dynamically loaded objects. This routine is highly dependent 66 * on executable format and layout. 67 * 68 * Arguments: 69 * op: desired operation 70 * f: function to perform 71 */ 72 static int 73 apply_lock(int op, int (*f)(caddr_t, u_int)) 74 { 75 int e = 0; /* return value */ 76 caddr_t a; /* address of operation */ 77 u_int l; /* length of operation */ 78 struct link_map *lmp; /* link map walker */ 79 struct exec *eh; /* exec header */ 80 81 /* 82 * Operate on application segment first. 83 */ 84 switch (op) { 85 case TXTLOCK: 86 a = (caddr_t)USRTEXT; /* note: old Sun-2 not handled */ 87 l = (u_int)&etext - USRTEXT; 88 break; 89 case DATLOCK: 90 a = (caddr_t)(((int)&etext + (SEGSIZ - 1)) & ~(SEGSIZ - 1)); 91 l = (u_int)(sbrk(0) - a); 92 break; 93 } 94 l = (l + (page_size - 1)) & (u_int)~(page_size - 1); 95 96 /* 97 * Perform the operation -- if failure, return immediately. 98 */ 99 if (e = (*f)(a, l)) 100 return (e); 101 102 /* 103 * If we're not a dynamically linked program, we are finished. 104 */ 105 if (&_DYNAMIC == 0) 106 return (0); 107 108 /* 109 * Find the list of dynamically linked objects. If we get 110 * dynamic linking formats we don't recognize, then punt. 111 */ 112 switch (_DYNAMIC.ld_version) { 113 case 2: 114 #if defined(__sparc) 115 case 3: 116 #endif /* __sparc */ 117 lmp = _DYNAMIC.ld_un.ld_2->ld_loaded; 118 break; 119 default: 120 return (0); 121 } 122 123 /* 124 * Loop over all objects. Extract the addresses and lengths as 125 * required, and perform the appropriate operation. 126 */ 127 128 while (lmp) { 129 eh = (struct exec *)lmp->lm_addr; 130 switch (op) { 131 case TXTLOCK: 132 a = (caddr_t)eh; 133 l = (u_int)eh->a_text; 134 break; 135 case DATLOCK: 136 a = (caddr_t)((u_int)eh + N_DATADDR(*eh) - 137 N_TXTADDR(*eh)); 138 l = (u_int)eh->a_data + (u_int)eh->a_bss; 139 break; 140 } 141 l = (l + (page_size - 1)) & ~(page_size - 1); 142 if (e = (*f)(a, l)) 143 return (e); 144 lmp = lmp->lm_next; 145 } 146 return (0); 147 } 148 149 /* 150 * plock 151 * 152 * Argument: 153 * op: desired operation 154 */ 155 int 156 plock(int op) 157 { 158 int e = 0; /* return value */ 159 int pid; /* current pid */ 160 caddr_t a1, a2; /* loop variables */ 161 struct rlimit rl; /* resource limit */ 162 163 /* 164 * Initialize static caches. 165 */ 166 if (page_size == 0) 167 page_size = getpagesize(); 168 169 /* 170 * Validate state of lock's. If parent has forked, then 171 * the lock state needs to be reset (children do not inherit 172 * memory locks, and thus do not inherit their state). 173 */ 174 if ((pid = getpid()) != state_pid) { 175 lock_state = 0; 176 state_pid = pid; 177 } 178 179 /* 180 * Dispatch on operation. Note: plock and its relatives depend 181 * upon "op" being bit encoded. 182 */ 183 switch (op) { 184 185 /* 186 * UNLOCK: remove all memory locks. Requires that some be set! 187 */ 188 case UNLOCK: 189 if (lock_state == 0) { 190 errno = EINVAL; 191 return (-1); 192 } 193 if (e = munlockall()) 194 return (-1); 195 else { 196 lock_state = 0; 197 return (0); 198 } 199 /*NOTREACHED*/ 200 201 /* 202 * TXTLOCK: locks text segments. 203 */ 204 case TXTLOCK: 205 206 /* 207 * If a text or process lock is already set, then fail. 208 */ 209 if ((lock_state & TXTLOCK) || (lock_state & PROCLOCK)) { 210 errno = EINVAL; 211 return (-1); 212 } 213 214 /* 215 * Try to apply the lock(s). If a failure occurs, 216 * back them out. On success, remember that a text 217 * lock was set. 218 */ 219 if (e = apply_lock(op, mlock)) 220 (void) apply_lock(op, munlock); 221 else 222 lock_state |= TXTLOCK; 223 return (e); 224 /*NOTREACHED*/ 225 226 /* 227 * DATLOCK: locks data segment(s), including the stack and all 228 * future growth in the address space. 229 */ 230 case DATLOCK: 231 232 /* 233 * If a data or process lock is already set, then fail. 234 */ 235 if ((lock_state & DATLOCK) || (lock_state & PROCLOCK)) { 236 errno = EINVAL; 237 return (-1); 238 } 239 240 /* 241 * Try to lock the data segments. On failure, back out 242 * the locks and return. 243 */ 244 if (e = apply_lock(op, mlock)) { 245 (void) apply_lock(op, munlock); 246 return (-1); 247 } 248 249 /* 250 * Try to lock the stack segment. Find out the extent 251 * and start of the stack (there should be a function for 252 * this!) and then iterate over the pages of the stack 253 * locking them. The stack *could* be sparely populated. 254 * Ignore lock failures resulting from the absence of a 255 * mapping. 256 */ 257 (void) getrlimit(RLIMIT_STACK, &rl); 258 for (a1 = (caddr_t)USRSTACK - page_size; 259 a1 != (caddr_t)USRSTACK - rl.rlim_cur; a1 -= page_size) 260 if (e = mlock(a1, page_size)) { 261 if (errno == ENOMEM) 262 e = 0; 263 break; 264 } 265 266 /* 267 * If we were successful in locking the stack, then 268 * try to set a lock for all future mappings. 269 */ 270 if (!e) 271 e = mlockall(MCL_FUTURE); 272 273 /* 274 * If failures have occurred, back out the locks 275 * and return failure. 276 */ 277 if (e) { 278 e = errno; 279 (void) apply_lock(op, munlock); 280 for (a2 = (caddr_t)USRSTACK - page_size; a2 != a1; 281 a2 -= page_size) 282 (void) munlock(a2, page_size); 283 errno = e; 284 return (-1); 285 } 286 287 /* 288 * Data, stack, and growth have been locked. Set state 289 * and return success. 290 */ 291 lock_state |= DATLOCK; 292 return (0); 293 /*NOTREACHED*/ 294 295 /* 296 * PROCLOCK: lock everything, and all future things as well. 297 * There should be nothing locked when this is called. 298 */ 299 case PROCLOCK: 300 if (lock_state) { 301 errno = EINVAL; 302 return (-1); 303 } 304 if (mlockall(MCL_CURRENT | MCL_FUTURE) == 0) { 305 lock_state |= PROCLOCK; 306 return (0); 307 } else 308 return (-1); 309 /*NOTREACHED*/ 310 311 /* 312 * Invalid operation. 313 */ 314 default: 315 errno = EINVAL; 316 return (-1); 317 /*NOTREACHED*/ 318 } 319 } 320