~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Minix Cross Reference
Minix/mm/exec.c


  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.