1 /* This file handles the EXEC system call. It performs the work as follows:
2 * - see if the permissions allow the file to be executed
3 * - read the header and extract the sizes
4 * - fetch the initial args and environment from the user space
5 * - allocate the memory for the new process
6 * - copy the initial stack from PM to the process
7 * - read in the text and data segments and copy to the process
8 * - take care of setuid and setgid bits
9 * - fix up 'mproc' table
10 * - tell kernel about EXEC
11 * - save offset to initial argc (for ps)
13 * The entry points into this file are:
14 * do_exec: perform the EXEC system call
15 * exec_newmem: allocate new memory map for a process that tries to exec
16 * do_execrestart: finish the special exec call for RS
17 * exec_restart: finish a regular exec call
18 * find_share: find a process whose text segment can be shared
23 #include <minix/callnr.h>
24 #include <minix/endpoint.h>
25 #include <minix/com.h>
32 FORWARD
_PROTOTYPE( int new_mem
, (struct mproc
*rmp
, struct mproc
*sh_mp
,
33 vir_bytes text_bytes
, vir_bytes data_bytes
, vir_bytes bss_bytes
,
34 vir_bytes stk_bytes
, phys_bytes tot_bytes
) );
36 #define ESCRIPT (-2000) /* Returned by read_header for a #! script. */
37 #define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */
39 /*===========================================================================*
41 *===========================================================================*/
47 mp
->mp_exec_path
= m_in
.exec_name
;
48 mp
->mp_exec_path_len
= m_in
.exec_len
;
49 mp
->mp_exec_frame
= m_in
.stack_ptr
;
50 mp
->mp_exec_frame_len
= m_in
.stack_bytes
;
52 /* Forward call to FS */
53 if (mp
->mp_fs_call
!= PM_IDLE
)
55 panic(__FILE__
, "do_exec: not idle", mp
->mp_fs_call
);
57 mp
->mp_fs_call
= PM_EXEC
;
58 r
= notify(FS_PROC_NR
);
60 panic(__FILE__
, "do_getset: unable to notify FS", r
);
67 /*===========================================================================*
69 *===========================================================================*/
70 PUBLIC
int exec_newmem()
72 int r
, proc_e
, proc_n
, allow_setuid
;
74 vir_clicks tc
, dc
, sc
, totc
, dvir
, s_vir
;
75 struct mproc
*rmp
, *sh_mp
;
77 struct exec_newmem args
;
79 if (who_e
!= FS_PROC_NR
&& who_e
!= RS_PROC_NR
)
82 proc_e
= m_in
.EXC_NM_PROC
;
83 if (pm_isokendpt(proc_e
, &proc_n
) != OK
)
85 panic(__FILE__
, "exec_newmem: got bad endpoint",
91 r
= sys_datacopy(who_e
, (vir_bytes
)ptr
,
92 SELF
, (vir_bytes
)&args
, sizeof(args
));
94 panic(__FILE__
, "exec_newmem: sys_datacopy failed", r
);
96 /* Check to see if segment sizes are feasible. */
97 tc
= ((unsigned long) args
.text_bytes
+ CLICK_SIZE
- 1) >> CLICK_SHIFT
;
98 dc
= (args
.data_bytes
+args
.bss_bytes
+ CLICK_SIZE
- 1) >> CLICK_SHIFT
;
99 totc
= (args
.tot_bytes
+ CLICK_SIZE
- 1) >> CLICK_SHIFT
;
100 sc
= (args
.args_bytes
+ CLICK_SIZE
- 1) >> CLICK_SHIFT
;
101 if (dc
>= totc
) return(ENOEXEC
); /* stack must be at least 1 click */
103 dvir
= (args
.sep_id
? 0 : tc
);
104 s_vir
= dvir
+ (totc
- sc
);
105 #if (CHIP == INTEL && _WORD_SIZE == 2)
106 r
= size_ok(*ft
, tc
, dc
, sc
, dvir
, s_vir
);
108 r
= (dvir
+ dc
> s_vir
) ? ENOMEM
: OK
;
113 /* Can the process' text be shared with that of one already running? */
114 sh_mp
= find_share(rmp
, args
.st_ino
, args
.st_dev
, args
.st_ctime
);
116 /* Allocate new memory and release old memory. Fix map and tell
119 r
= new_mem(rmp
, sh_mp
, args
.text_bytes
, args
.data_bytes
,
120 args
.bss_bytes
, args
.args_bytes
, args
.tot_bytes
);
121 if (r
!= OK
) return(r
);
123 rmp
->mp_flags
|= PARTIAL_EXEC
; /* Kill process if something goes
124 * wrong after this point.
127 /* Save file identification to allow it to be shared. */
128 rmp
->mp_ino
= args
.st_ino
;
129 rmp
->mp_dev
= args
.st_dev
;
130 rmp
->mp_ctime
= args
.st_ctime
;
132 stack_top
= ((vir_bytes
)rmp
->mp_seg
[S
].mem_vir
<< CLICK_SHIFT
) +
133 ((vir_bytes
)rmp
->mp_seg
[S
].mem_len
<< CLICK_SHIFT
);
135 /* Save offset to initial argc (for ps) */
136 rmp
->mp_procargs
= stack_top
- args
.args_bytes
;
138 /* set/clear separate I&D flag */
140 rmp
->mp_flags
|= SEPARATE
;
142 rmp
->mp_flags
&= ~SEPARATE
;
144 allow_setuid
= 0; /* Do not allow setuid execution */
145 if ((rmp
->mp_flags
& TRACED
) == 0) {
146 /* Okay, setuid execution is allowed */
148 rmp
->mp_effuid
= args
.new_uid
;
149 rmp
->mp_effgid
= args
.new_gid
;
152 /* System will save command line for debugging, ps(1) output, etc. */
153 strncpy(rmp
->mp_name
, args
.progname
, PROC_NAME_LEN
-1);
154 rmp
->mp_name
[PROC_NAME_LEN
-1] = '\0';
156 mp
->mp_reply
.reply_res2
= stack_top
;
157 mp
->mp_reply
.reply_res3
= 0;
158 if (!sh_mp
) /* Load text if sh_mp = NULL */
159 mp
->mp_reply
.reply_res3
|= EXC_NM_RF_LOAD_TEXT
;
161 mp
->mp_reply
.reply_res3
|= EXC_NM_RF_ALLOW_SETUID
;
167 /*===========================================================================*
169 *===========================================================================*/
170 PUBLIC
int do_execrestart()
172 int proc_e
, proc_n
, result
;
175 if (who_e
!= RS_PROC_NR
)
178 proc_e
= m_in
.EXC_RS_PROC
;
179 if (pm_isokendpt(proc_e
, &proc_n
) != OK
)
181 panic(__FILE__
, "do_execrestart: got bad endpoint",
185 result
= m_in
.EXC_RS_RESULT
;
187 exec_restart(rmp
, result
);
193 /*===========================================================================*
195 *===========================================================================*/
196 PUBLIC
void exec_restart(rmp
, result
)
206 if (rmp
->mp_flags
& PARTIAL_EXEC
)
208 printf("partial exec; killing process\n");
210 /* Use SIGILL signal that something went wrong */
211 rmp
->mp_sigstatus
= SIGILL
;
212 pm_exit(rmp
, 0, FALSE
/*!for_trace*/);
215 setreply(rmp
-mproc
, result
);
219 rmp
->mp_flags
&= ~PARTIAL_EXEC
;
221 /* Fix 'mproc' fields, tell kernel that exec is done, reset caught
224 for (sn
= 1; sn
<= _NSIG
; sn
++) {
225 if (sigismember(&rmp
->mp_catch
, sn
)) {
226 sigdelset(&rmp
->mp_catch
, sn
);
227 rmp
->mp_sigact
[sn
].sa_handler
= SIG_DFL
;
228 sigemptyset(&rmp
->mp_sigact
[sn
].sa_mask
);
233 new_sp
= (char *)rmp
->mp_procargs
;
235 r
= sys_exec(rmp
->mp_endpoint
, new_sp
, rmp
->mp_name
, pc
);
236 if (r
!= OK
) panic(__FILE__
, "sys_exec failed", r
);
238 /* Cause a signal if this process is traced. */
239 if (rmp
->mp_flags
& TRACED
) check_sig(rmp
->mp_pid
, SIGTRAP
);
242 /*===========================================================================*
244 *===========================================================================*/
245 PUBLIC
struct mproc
*find_share(mp_ign
, ino
, dev
, ctime
)
246 struct mproc
*mp_ign
; /* process that should not be looked at */
247 ino_t ino
; /* parameters that uniquely identify a file */
251 /* Look for a process that is the file <ino, dev, ctime> in execution. Don't
252 * accidentally "find" mp_ign, because it is the process on whose behalf this
256 for (sh_mp
= &mproc
[0]; sh_mp
< &mproc
[NR_PROCS
]; sh_mp
++) {
258 if (!(sh_mp
->mp_flags
& SEPARATE
)) continue;
259 if (sh_mp
== mp_ign
) continue;
260 if (sh_mp
->mp_ino
!= ino
) continue;
261 if (sh_mp
->mp_dev
!= dev
) continue;
262 if (sh_mp
->mp_ctime
!= ctime
) continue;
268 /*===========================================================================*
270 *===========================================================================*/
271 PRIVATE
int new_mem(rmp
, sh_mp
, text_bytes
, data_bytes
,
272 bss_bytes
,stk_bytes
,tot_bytes
)
273 struct mproc
*rmp
; /* process to get a new memory map */
274 struct mproc
*sh_mp
; /* text can be shared with this process */
275 vir_bytes text_bytes
; /* text segment size in bytes */
276 vir_bytes data_bytes
; /* size of initialized data in bytes */
277 vir_bytes bss_bytes
; /* size of bss in bytes */
278 vir_bytes stk_bytes
; /* size of initial stack segment in bytes */
279 phys_bytes tot_bytes
; /* total memory to allocate, including gap */
281 /* Allocate new memory and release the old memory. Change the map and report
282 * the new map to the kernel. Zero the new core image's bss, gap and stack.
285 vir_clicks text_clicks
, data_clicks
, gap_clicks
, stack_clicks
, tot_clicks
;
286 phys_clicks new_base
;
287 phys_bytes bytes
, base
, bss_offset
;
290 /* No need to allocate text if it can be shared. */
291 if (sh_mp
!= NULL
) text_bytes
= 0;
293 /* Allow the old data to be swapped out to make room. (Which is really a
294 * waste of time, because we are going to throw it away anyway.)
296 rmp
->mp_flags
|= WAITING
;
298 /* Acquire the new memory. Each of the 4 parts: text, (data+bss), gap,
299 * and stack occupies an integral number of clicks, starting at click
300 * boundary. The data and bss parts are run together with no space.
302 text_clicks
= ((unsigned long) text_bytes
+ CLICK_SIZE
- 1) >> CLICK_SHIFT
;
303 data_clicks
= (data_bytes
+ bss_bytes
+ CLICK_SIZE
- 1) >> CLICK_SHIFT
;
304 stack_clicks
= (stk_bytes
+ CLICK_SIZE
- 1) >> CLICK_SHIFT
;
305 tot_clicks
= (tot_bytes
+ CLICK_SIZE
- 1) >> CLICK_SHIFT
;
306 gap_clicks
= tot_clicks
- data_clicks
- stack_clicks
;
307 if ( (int) gap_clicks
< 0) return(ENOMEM
);
309 /* Try to allocate memory for the new process. */
310 new_base
= alloc_mem(text_clicks
+ tot_clicks
);
311 if (new_base
== NO_MEM
) return(ENOMEM
);
313 /* We've got memory for the new core image. Release the old one. */
314 if (find_share(rmp
, rmp
->mp_ino
, rmp
->mp_dev
, rmp
->mp_ctime
) == NULL
) {
315 /* No other process shares the text segment, so free it. */
316 free_mem(rmp
->mp_seg
[T
].mem_phys
, rmp
->mp_seg
[T
].mem_len
);
318 /* Free the data and stack segments. */
319 free_mem(rmp
->mp_seg
[D
].mem_phys
,
320 rmp
->mp_seg
[S
].mem_vir
+ rmp
->mp_seg
[S
].mem_len
- rmp
->mp_seg
[D
].mem_vir
);
322 /* We have now passed the point of no return. The old core image has been
323 * forever lost, memory for a new core image has been allocated. Set up
324 * and report new map.
327 /* Share the text segment. */
328 rmp
->mp_seg
[T
] = sh_mp
->mp_seg
[T
];
330 rmp
->mp_seg
[T
].mem_phys
= new_base
;
331 rmp
->mp_seg
[T
].mem_vir
= 0;
332 rmp
->mp_seg
[T
].mem_len
= text_clicks
;
336 /* Zero the last click of the text segment. Otherwise the
337 * part of that click may remain unchanged.
339 base
= (phys_bytes
)(new_base
+text_clicks
-1) << CLICK_SHIFT
;
340 if ((s
= sys_memset(0, base
, CLICK_SIZE
)) != OK
)
341 panic(__FILE__
, "new_mem: sys_memset failed", s
);
344 rmp
->mp_seg
[D
].mem_phys
= new_base
+ text_clicks
;
345 rmp
->mp_seg
[D
].mem_vir
= 0;
346 rmp
->mp_seg
[D
].mem_len
= data_clicks
;
347 rmp
->mp_seg
[S
].mem_phys
= rmp
->mp_seg
[D
].mem_phys
+ data_clicks
+ gap_clicks
;
348 rmp
->mp_seg
[S
].mem_vir
= rmp
->mp_seg
[D
].mem_vir
+ data_clicks
+ gap_clicks
;
349 rmp
->mp_seg
[S
].mem_len
= stack_clicks
;
352 rmp
->mp_seg
[T
].mem_vir
= 0;
353 rmp
->mp_seg
[D
].mem_vir
= rmp
->mp_seg
[T
].mem_len
;
354 rmp
->mp_seg
[S
].mem_vir
= rmp
->mp_seg
[D
].mem_vir
355 + rmp
->mp_seg
[D
].mem_len
+ gap_clicks
;
358 if((r2
=sys_newmap(rmp
->mp_endpoint
, rmp
->mp_seg
)) != OK
) {
359 /* report new map to the kernel */
360 panic(__FILE__
,"sys_newmap failed", r2
);
363 /* The old memory may have been swapped out, but the new memory is real. */
364 rmp
->mp_flags
&= ~(WAITING
|ONSWAP
|SWAPIN
);
366 /* Zero the bss, gap, and stack segment. */
367 bytes
= (phys_bytes
)(data_clicks
+ gap_clicks
+ stack_clicks
) << CLICK_SHIFT
;
368 base
= (phys_bytes
) rmp
->mp_seg
[D
].mem_phys
<< CLICK_SHIFT
;
369 bss_offset
= (data_bytes
>> CLICK_SHIFT
) << CLICK_SHIFT
;
373 if ((s
=sys_memset(0, base
, bytes
)) != OK
) {
374 panic(__FILE__
,"new_mem can't zero", s
);