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