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
apply_lock(int op,int (* f)(caddr_t,u_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
plock(int op)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