1 static char *rcsid = "$Id: exec.c,v 1.7 1996/08/14 04:43:42 paul Exp $";
2
3 /* This file handles the EXEC system call. It performs the work as follows:
4 * - see if the permissions allow the file to be executed
5 * - read the header and extract the sizes
6 * - fetch the initial args and environment from the user space
7 * - allocate the memory for the new process
8 * - copy the initial stack from MM to the process
9 * - read in the text and data segments and copy to the process
10 * - take care of setuid and setgid bits
11 * - fix up 'mproc' table
12 * - tell kernel about EXEC
13 * - save offset to initial argc (for ps)
14 *
15 * The entry points into this file are:
16 * do_exec: perform the EXEC system call
17 * find_share: find a process whose text segment can be shared
18 * zero_mem: Zeroes the specfied area of physical memory (for bss,
19 * stack, newly malloced data segment).
20 */
21
22 #include "mm.h"
23 #include <sys/stat.h>
24 #include <minix/callnr.h>
25 #include <a.out.h>
26 #include <signal.h>
27 #include <string.h>
28 #include "mproc.h"
29 #include "param.h"
30
31 /*
32 * This file has been changed quite a lot to allow for extendable data
33 * and stack segments in smx. Consequently, all INTEL-specific code
34 * has been removed to improve readability.
35 */
36 #if (MACHINE != SUN)
37 #error "This file has been tailored for use with Solaris MINIX only"
38 #endif
39
40 FORWARD _PROTOTYPE( void load_seg, (int fd, int seg, vir_bytes seg_bytes) );
41 FORWARD _PROTOTYPE( void patch_ptr, (char stack [ARG_MAX ], vir_bytes base) );
42 FORWARD _PROTOTYPE( int new_mem, (struct mproc *sh_mp, vir_bytes text_bytes,
43 vir_bytes data_bytes, vir_bytes bss_bytes,
44 vir_bytes stk_bytes, vir_bytes tvbase, vir_bytes dvbase));
45 FORWARD _PROTOTYPE( int read_header, (int fd, int *ft, vir_bytes *text_bytes,
46 vir_bytes *data_bytes, vir_bytes *bss_bytes, vir_clicks sc,
47 long *tvbase, long *dvbase, vir_bytes *pc) );
48
49
50 /*
51 * smx user stacks grow down from this address.
52 */
53 static vir_clicks stack_high;
54
55 /*===========================================================================*
56 * do_exec *
57 *===========================================================================*/
58 PUBLIC int do_exec()
59 {
60 /* Perform the execve(name, argv, envp) call. The user library builds a
61 * complete stack image, including pointers, args, environ, etc. The stack
62 * is copied to a buffer inside MM, and then to the new core image.
63 */
64
65 register struct mproc *rmp;
66 struct mproc *sh_mp;
67 int m, r, fd, ft, sn;
68 static char mbuf[ARG_MAX]; /* buffer for stack and zeroes */
69 static char name_buf[PATH_MAX]; /* the name of the file to exec */
70 char *new_sp, *basename;
71 vir_bytes src, dst, text_bytes, data_bytes, bss_bytes, stk_bytes, vsp;
72 vir_clicks sc;
73 struct stat s_buf;
74 vir_bytes pc;
75 vir_bytes tvbase, dvbase; /* need to track virtual addresses in smx */
76
77 /* Do some validity checks. */
78 rmp = mp;
79 stk_bytes = (vir_bytes) stack_bytes;
80 if (stk_bytes > ARG_MAX) return(ENOMEM); /* stack too big */
81 if (exec_len <= 0 || exec_len > PATH_MAX) return(EINVAL);
82
83 /* Get the exec file name and see if the file is executable. */
84 src = (vir_bytes) exec_name;
85 dst = (vir_bytes) name_buf;
86 r = sys_copy(who, D, (phys_bytes) src,
87 MM_PROC_NR, D, (phys_bytes) dst, (phys_bytes) exec_len);
88 if (r != OK) return(r); /* file name not in user data segment */
89 tell_fs(CHDIR, who, FALSE, 0); /* switch to the user's FS environ. */
90 fd = allowed(name_buf, &s_buf, X_BIT); /* is file executable? */
91 if (fd < 0) return(fd); /* file was not executable */
92
93 /* Read the file header and extract the segment sizes. */
94 sc = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
95 m = read_header(fd, &ft, &text_bytes, &data_bytes, &bss_bytes,
96 sc, &tvbase, &dvbase, &pc);
97 if (m < 0) {
98 close(fd); /* something wrong with header */
99 return(ENOEXEC);
100 }
101
102
103 /* Fetch the stack from the user before destroying the old core image. */
104 src = (vir_bytes) stack_ptr;
105 dst = (vir_bytes) mbuf;
106 r = sys_copy(who, D, (phys_bytes) src,
107 MM_PROC_NR, D, (phys_bytes) dst, (phys_bytes)stk_bytes);
108 if (r != OK) {
109 close(fd); /* can't fetch stack (e.g. bad virtual addr) */
110 return(EACCES);
111 }
112
113 /* Can the process' text be shared with that of one already running? */
114 sh_mp = find_share(rmp, s_buf.st_ino, s_buf.st_dev, s_buf.st_ctime);
115
116 /* Allocate new memory and release old memory. Fix map and tell kernel. */
117 r = new_mem(sh_mp, text_bytes, data_bytes, bss_bytes, stk_bytes,
118 tvbase, dvbase);
119 if (r != OK) {
120 close(fd); /* insufficient core or program too big */
121 return(r);
122 }
123
124 /* Save file identification to allow it to be shared. */
125 rmp->mp_ino = s_buf.st_ino;
126 rmp->mp_dev = s_buf.st_dev;
127 rmp->mp_ctime = s_buf.st_ctime;
128
129 /* Patch up stack and copy it from MM to new core image. */
130 vsp = (vir_bytes) rmp->mp_seg[S].mem_vir << CLICK_SHIFT;
131 vsp += (vir_bytes) rmp->mp_seg[S].mem_len << CLICK_SHIFT;
132 vsp -= stk_bytes;
133 vsp = stack_align(vsp); /* STack must be double-word aligned */
134
135 patch_ptr(mbuf, vsp);
136 src = (vir_bytes) mbuf;
137 r = sys_copy(MM_PROC_NR, D, (phys_bytes) src,
138 who, D, (phys_bytes) vsp, (phys_bytes)stk_bytes);
139 if (r != OK) panic("do_exec stack copy err", NO_NUM);
140
141 /* Read in text and data segments. */
142 if (sh_mp != NULL) {
143 lseek(fd, (off_t) text_bytes, SEEK_CUR); /* shared: skip text */
144 } else {
145 load_seg(fd, T, text_bytes);
146 }
147 load_seg(fd, D, data_bytes);
148
149 close(fd); /* don't need exec file any more */
150
151 /* Take care of setuid/setgid bits. */
152 if ((rmp->mp_flags & TRACED) == 0) { /* suppress if tracing */
153 if (s_buf.st_mode & I_SET_UID_BIT) {
154 rmp->mp_effuid = s_buf.st_uid;
155 tell_fs(SETUID,who, (int)rmp->mp_realuid, (int)rmp->mp_effuid);
156 }
157 if (s_buf.st_mode & I_SET_GID_BIT) {
158 rmp->mp_effgid = s_buf.st_gid;
159 tell_fs(SETGID,who, (int)rmp->mp_realgid, (int)rmp->mp_effgid);
160 }
161 }
162
163 /* Fix 'mproc' fields, tell kernel that exec is done, reset caught sigs. */
164 for (sn = 1; sn <= _NSIG; sn++) {
165 if (sigismember(&rmp->mp_catch, sn)) {
166 sigdelset(&rmp->mp_catch, sn);
167 rmp->mp_sigact[sn].sa_handler = SIG_DFL;
168 sigemptyset(&rmp->mp_sigact[sn].sa_mask);
169 }
170 }
171
172 rmp->mp_flags &= ~SEPARATE; /* turn off SEPARATE bit */
173 rmp->mp_flags |= ft; /* turn it on for separate I & D files */
174
175 /* Save offset to initial argc (for ps) */
176 rmp->mp_procargs = vsp;
177 vsp -= INIT_SP; /* leave space for a stack frame */
178 new_sp = (char *) vsp;
179
180 tell_fs(EXEC, who, 0, 0); /* allow FS to handle FD_CLOEXEC files */
181
182 /* System will save command line for debugging, ps(1) output, etc. */
183 basename = strrchr(name_buf, '/');
184 if (basename == NULL) basename = name_buf; else basename++;
185 sys_exec(who, new_sp, rmp->mp_flags & TRACED, basename, pc);
186
187 #if 0
188 printf("Exec: text from %x len %x, data from %x len %x, stack from %x len %x, pc = %x sp = %x\n",
189 rmp->mp_seg[T].mem_phys << CLICK_SHIFT, rmp->mp_seg[T].mem_len << CLICK_SHIFT,
190 rmp->mp_seg[D].mem_phys << CLICK_SHIFT, rmp->mp_seg[D].mem_len << CLICK_SHIFT,
191 rmp->mp_seg[S].mem_phys << CLICK_SHIFT, rmp->mp_seg[S].mem_len << CLICK_SHIFT,
192 pc, vsp);
193 #endif
194
195 return(OK);
196 }
197
198
199 /*===========================================================================*
200 * read_header *
201 *===========================================================================*/
202 PRIVATE int read_header(fd, ft, text_bytes, data_bytes, bss_bytes,
203 sc, tvbase, dvbase, pc)
204 int fd; /* file descriptor for reading exec file */
205 int *ft; /* place to return ft number */
206 vir_bytes *text_bytes; /* place to return text size */
207 vir_bytes *data_bytes; /* place to return initialized data size */
208 vir_bytes *bss_bytes; /* place to return bss size */
209 vir_clicks sc; /* stack size in clicks */
210 vir_bytes *pc; /* program entry point (initial PC) */
211 long *tvbase; /* Virtual address of start of text seg */
212 long *dvbase; /* Virtual address of start of data seg */
213 {
214 /* Read the header and extract the relevant from it. */
215
216 int ct;
217 vir_clicks tc, dc;
218 struct exec hdr; /* a.out header is read in here */
219
220 /* Read the header and check the magic number. The standard MINIX header
221 * is defined in <a.out.h>. It consists of 8 chars followed by 6 longs.
222 * Then come 4 more longs that are not used here.
223 * Byte 0: magic number 0x01
224 * Byte 1: magic number 0x03
225 * Byte 2: normal = 0x10 (not checked, 0 is OK), separate I/D = 0x20
226 * Byte 3: CPU type, Intel 16 bit = 0x04, Intel 32 bit = 0x10,
227 * Motorola = 0x0B, Sun SPARC = 0x17
228 * Byte 4: Header length = 0x20
229 * Bytes 5-7 are not used.
230 *
231 * Now come the 6 longs
232 * Bytes 8-11: size of text segments in bytes
233 * Bytes 12-15: size of initialized data segment in bytes
234 * Bytes 16-19: size of bss in bytes
235 * Bytes 20-23: program entry point
236 * Bytes 24-27: total memory (ignored in smx)
237 * Bytes 28-31: size of symbol (ignored in smx)
238 * and on smx
239 * Bytes 40-43: virtual address of the text segment
240 * Bytes 44-47: virtual address of the data segment
241 * The longs are represented in a machine dependent order,
242 * little-endian on the 8088, big-endian on the 68000.
243 * The header is followed directly by the text and data segments, and the
244 * symbol table (if any). The sizes are given in the header. Only the
245 * text and data segments are copied into memory by exec. The header is
246 * used here only. The symbol table is for the benefit of a debugger and
247 * is ignored here.
248 */
249
250 /*
251 * Note for smx, if the executable header changes src/Solaris/minix_load.c
252 * and src/Solaris/next_prog_addr.c may need changing.
253 */
254 if (read(fd, (char *) &hdr, sizeof(hdr)) != sizeof(hdr)) return(ENOEXEC);
255
256 /* Check magic number, cpu type, and flags. */
257 if (BADMAG(hdr)) return(ENOEXEC);
258 if (hdr.a_cpu != A_SUNOS) return(ENOEXEC);
259 if ((hdr.a_flags & ~(A_NSYM | A_EXEC | A_SEP)) != 0) return(ENOEXEC);
260
261 *ft = SEPARATE; /* separate I & D or not */
262
263 /* Get text and data sizes. */
264 *text_bytes = (vir_bytes) hdr.a_text; /* text size in bytes */
265 *data_bytes = (vir_bytes) hdr.a_data; /* data size in bytes */
266 *bss_bytes = (vir_bytes) hdr.a_bss; /* bss size in bytes */
267 *tvbase = hdr.a_tbase; /* virtual addr of text seg */
268 *dvbase = hdr.a_dbase; /* virtual addr of data seg */
269 *pc = hdr.a_entry; /* initial address to start execution */
270
271 /*
272 * Check to see if segment sizes are feasible. The text segment must not
273 * overlap the data segment, and the data segment must not overlap
274 * the stack segment.
275 */
276 tc = ((unsigned long) *text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
277 dc = (*data_bytes + *bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
278 if (*tvbase + (tc << CLICK_SHIFT) > *dvbase ||
279 *dvbase + (dc << CLICK_SHIFT) > stack_high - (sc << CLICK_SHIFT)) {
280 return(ENOMEM);
281 }
282
283 ct = hdr.a_hdrlen & BYTE; /* header length */
284 if (ct > A_MINHDR) lseek(fd, (off_t) ct, SEEK_SET); /* skip unused hdr */
285 return(OK);
286 }
287
288
289 /*===========================================================================*
290 * new_mem *
291 *===========================================================================*/
292 PRIVATE int new_mem(sh_mp, text_bytes, data_bytes, bss_bytes, stk_bytes,
293 tvbase, dvbase)
294 struct mproc *sh_mp; /* text can be shared with this process */
295 vir_bytes text_bytes; /* text segment size in bytes */
296 vir_bytes data_bytes; /* size of initialized data in bytes */
297 vir_bytes bss_bytes; /* size of bss in bytes */
298 vir_bytes stk_bytes; /* size of initial stack segment in bytes */
299 vir_bytes tvbase;
300 vir_bytes dvbase;
301 {
302 /* Allocate new memory and release the old memory. Change the map and report
303 * the new map to the kernel. Zero the new core image's bss, gap and stack.
304 */
305
306 register struct mproc *rmp;
307 vir_clicks text_clicks, data_clicks, stack_clicks, tot_clicks;
308 phys_clicks new_base;
309
310 /* No need to allocate text if it can be shared. */
311 if (sh_mp != NULL) text_bytes = 0;
312
313 /* Acquire the new memory. Each of the 3 parts: text, (data+bss)
314 * and stack occupies an integral number of clicks, starting at click
315 * boundary. The data and bss parts are run together with no space.
316 */
317
318 text_clicks = ((unsigned long) text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
319 data_clicks = (data_bytes + bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
320 stack_clicks = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
321 tot_clicks = text_clicks + data_clicks + stack_clicks;
322
323 /* Check to see if there is a hole big enough. If so, we can risk first
324 * releasing the old core image before allocating the new one, since we
325 * know it will succeed. If there is not enough, return failure.
326 */
327 if (tot_clicks > max_hole()) return(EAGAIN);
328
329 /* There is enough memory for the new core image. Release the old one. */
330 rmp = mp;
331
332 if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {
333 /* No other process shares the text segment, so free it. */
334 free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);
335 }
336 /* Free the data and stack segments. */
337 free_mem(rmp->mp_seg[D].mem_phys, rmp->mp_seg[D].mem_len);
338 free_mem(rmp->mp_seg[S].mem_phys, rmp->mp_seg[S].mem_len);
339
340 /* We have now passed the point of no return. The old core image has been
341 * forever lost. The call must go through now. Set up and report new map.
342 */
343 new_base = alloc_mem(tot_clicks); /* new core image */
344 if (new_base == NO_MEM) panic("MM hole list is inconsistent", NO_NUM);
345
346 if (sh_mp != NULL) {
347 /* Share the text segment. */
348 rmp->mp_seg[T] = sh_mp->mp_seg[T];
349 } else {
350 rmp->mp_seg[T].mem_phys = new_base;
351 rmp->mp_seg[T].mem_vir = tvbase >> CLICK_SHIFT;
352 rmp->mp_seg[T].mem_len = text_clicks;
353 }
354 rmp->mp_seg[D].mem_phys = new_base + text_clicks;
355 rmp->mp_seg[D].mem_vir = dvbase >> CLICK_SHIFT;
356 rmp->mp_seg[D].mem_len = data_clicks;
357 rmp->mp_seg[S].mem_phys = rmp->mp_seg[D].mem_phys + data_clicks;
358 rmp->mp_seg[S].mem_vir = stack_high - stack_clicks;
359 rmp->mp_seg[S].mem_len = stack_clicks;
360
361 sys_newmap(who, rmp->mp_seg); /* report new map to the kernel */
362
363 zero_mem((rmp->mp_seg[D].mem_phys << CLICK_SHIFT) + data_bytes,
364 ((data_clicks + stack_clicks) << CLICK_SHIFT) - data_bytes);
365
366 return(OK);
367 }
368
369
370 /*===========================================================================*
371 * patch_ptr *
372 *===========================================================================*/
373 PRIVATE void patch_ptr(stack, base)
374 char stack[ARG_MAX]; /* pointer to stack image within MM */
375 vir_bytes base; /* virtual address of stack base inside user */
376 {
377 /* When doing an exec(name, argv, envp) call, the user builds up a stack
378 * image with arg and env pointers relative to the start of the stack. Now
379 * these pointers must be relocated, since the stack is not positioned at
380 * address 0 in the user's address space.
381 */
382
383 char **ap, flag;
384 vir_bytes v;
385
386 flag = 0; /* counts number of 0-pointers seen */
387 ap = (char **) stack; /* points initially to 'nargs' */
388 ap++; /* now points to argv[0] */
389 while (flag < 2) {
390 if (ap >= (char **) &stack[ARG_MAX]) return; /* too bad */
391 if (*ap != NIL_PTR) {
392 v = (vir_bytes) *ap; /* v is relative pointer */
393 v += base; /* relocate it */
394 *ap = (char *) v; /* put it back */
395 } else {
396 flag++;
397 }
398 ap++;
399 }
400 }
401
402
403 /*===========================================================================*
404 * load_seg *
405 *===========================================================================*/
406 PRIVATE void load_seg(fd, seg, seg_bytes)
407 int fd; /* file descriptor to read from */
408 int seg; /* T or D */
409 vir_bytes seg_bytes; /* how big is the segment */
410 {
411 /* Read in text or data from the exec file and copy to the new core image.
412 * This procedure is a little bit tricky. The logical way to load a segment
413 * would be to read it block by block and copy each block to the user space
414 * one at a time. This is too slow, so we do something dirty here, namely
415 * send the user space and virtual address to the file system in the upper
416 * 10 bits of the file descriptor, and pass it the user virtual address
417 * instead of a MM address. The file system extracts these parameters when
418 * gets a read call from the memory manager, which is the only process that
419 * is permitted to use this trick. The file system then copies the whole
420 * segment directly to user space, bypassing MM completely.
421 */
422
423 int new_fd, bytes;
424 char *ubuf_ptr;
425
426 new_fd = (who << 8) | (seg << 6) | fd;
427 ubuf_ptr = (char *) ((vir_bytes)mp->mp_seg[seg].mem_vir << CLICK_SHIFT);
428 while (seg_bytes != 0) {
429 bytes = (INT_MAX / BLOCK_SIZE) * BLOCK_SIZE;
430 if (seg_bytes < bytes)
431 bytes = (int)seg_bytes;
432 if (read(new_fd, ubuf_ptr, bytes) != bytes)
433 break; /* error */
434 ubuf_ptr += bytes;
435 seg_bytes -= bytes;
436 }
437 }
438
439
440 /*===========================================================================*
441 * find_share *
442 *===========================================================================*/
443 PUBLIC struct mproc *find_share(mp_ign, ino, dev, ctime)
444 struct mproc *mp_ign; /* process that should not be looked at */
445 ino_t ino; /* parameters that uniquely identify a file */
446 dev_t dev;
447 time_t ctime;
448 {
449 /* Look for a process that is the file <ino, dev, ctime> in execution. Don't
450 * accidentally "find" mp_ign, because it is the process on whose behalf this
451 * call is made.
452 */
453 struct mproc *sh_mp;
454
455 for (sh_mp = &mproc[INIT_PROC_NR]; sh_mp < &mproc[NR_PROCS]; sh_mp++) {
456 if ((sh_mp->mp_flags & (IN_USE | HANGING | SEPARATE))
457 != (IN_USE | SEPARATE)) continue;
458 if (sh_mp == mp_ign) continue;
459 if (sh_mp->mp_ino != ino) continue;
460 if (sh_mp->mp_dev != dev) continue;
461 if (sh_mp->mp_ctime != ctime) continue;
462 return sh_mp;
463 }
464 return(NULL);
465 }
466
467
468 /*===========================================================================*
469 * set_stack_high *
470 *===========================================================================*/
471 PUBLIC void set_stack_high(high)
472 vir_bytes high;
473 {
474 stack_high = high;
475 }
476
477
478 PUBLIC void zero_mem(from, len)
479 phys_bytes from;
480 phys_bytes len;
481 {
482 static char zero[1024];
483 phys_bytes count;
484
485 while (len > 0) {
486 count = MIN(len, (phys_bytes) sizeof(zero));
487 if (sys_copy(MM_PROC_NR, D, (phys_bytes) zero,
488 ABS, 0, from, count) != OK) {
489 panic("new_mem can't zero", NO_NUM);
490 }
491 from += count;
492 len -= count;
493 }
494 }
495
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.