arm: make signal handlers work
[minix.git] / servers / pm / exec.c
blob040dcd393ee5fdfa8b25b78e5fd2fd43abb95ffe
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 procfs)
13 * The entry points into this file are:
14 * do_exec: perform the EXEC system call
15 * do_newexec: handle PM part of exec call after VFS
16 * do_execrestart: finish the special exec call for RS
17 * exec_restart: finish a regular exec call
20 #include "pm.h"
21 #include <sys/stat.h>
22 #include <minix/callnr.h>
23 #include <minix/endpoint.h>
24 #include <minix/com.h>
25 #include <minix/vm.h>
26 #include <a.out.h>
27 #include <signal.h>
28 #include <string.h>
29 #include <libexec.h>
30 #include <sys/ptrace.h>
31 #include "mproc.h"
32 #include "param.h"
34 #define ESCRIPT (-2000) /* Returned by read_header for a #! script. */
35 #define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */
37 /*===========================================================================*
38 * do_exec *
39 *===========================================================================*/
40 int do_exec()
42 message m;
44 /* Forward call to VFS */
45 m.m_type = PM_EXEC;
46 m.PM_PROC = mp->mp_endpoint;
47 m.PM_PATH = m_in.exec_name;
48 m.PM_PATH_LEN = m_in.exec_len;
49 m.PM_FRAME = m_in.frame_ptr;
50 m.PM_FRAME_LEN = m_in.msg_frame_len;
51 m.PM_EXECFLAGS = m_in.PMEXEC_FLAGS;
53 tell_vfs(mp, &m);
55 /* Do not reply */
56 return SUSPEND;
60 /*===========================================================================*
61 * do_newexec *
62 *===========================================================================*/
63 int do_newexec()
65 int proc_e, proc_n, allow_setuid;
66 char *ptr;
67 struct mproc *rmp;
68 struct exec_info args;
69 int r, flags = 0;
71 if (who_e != VFS_PROC_NR && who_e != RS_PROC_NR)
72 return EPERM;
74 proc_e= m_in.EXC_NM_PROC;
75 if (pm_isokendpt(proc_e, &proc_n) != OK) {
76 panic("do_newexec: got bad endpoint: %d", proc_e);
78 rmp= &mproc[proc_n];
79 ptr= m_in.EXC_NM_PTR;
80 r= sys_datacopy(who_e, (vir_bytes)ptr,
81 SELF, (vir_bytes)&args, sizeof(args));
82 if (r != OK)
83 panic("do_newexec: sys_datacopy failed: %d", r);
85 allow_setuid = 0; /* Do not allow setuid execution */
86 rmp->mp_flags &= ~TAINTED; /* By default not tainted */
88 if (rmp->mp_tracer == NO_TRACER) {
89 /* Okay, setuid execution is allowed */
90 allow_setuid = 1;
93 if (allow_setuid && args.allow_setuid) {
94 rmp->mp_effuid = args.new_uid;
95 rmp->mp_effgid = args.new_gid;
98 /* A process is considered 'tainted' when it's executing with
99 * setuid or setgid bit set, or when the real{u,g}id doesn't
100 * match the eff{u,g}id, respectively. */
101 if (allow_setuid && args.allow_setuid) {
102 /* Program has setuid and/or setgid bits set */
103 rmp->mp_flags |= TAINTED;
104 } else if (rmp->mp_effuid != rmp->mp_realuid ||
105 rmp->mp_effgid != rmp->mp_realgid) {
106 rmp->mp_flags |= TAINTED;
109 /* System will save command line for debugging, ps(1) output, etc. */
110 strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1);
111 rmp->mp_name[PROC_NAME_LEN-1] = '\0';
113 /* Save offset to initial argc (for procfs) */
114 rmp->mp_frame_addr = (vir_bytes) args.stack_high - args.frame_len;
115 rmp->mp_frame_len = args.frame_len;
117 /* Kill process if something goes wrong after this point. */
118 rmp->mp_flags |= PARTIAL_EXEC;
120 mp->mp_reply.reply_res2= (vir_bytes) rmp->mp_frame_addr;
121 mp->mp_reply.reply_res3= flags;
122 if (allow_setuid && args.allow_setuid)
123 mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID;
125 return r;
128 /*===========================================================================*
129 * do_execrestart *
130 *===========================================================================*/
131 int do_execrestart()
133 int proc_e, proc_n, result;
134 struct mproc *rmp;
135 vir_bytes pc;
137 if (who_e != RS_PROC_NR)
138 return EPERM;
140 proc_e= m_in.EXC_RS_PROC;
141 if (pm_isokendpt(proc_e, &proc_n) != OK) {
142 panic("do_execrestart: got bad endpoint: %d", proc_e);
144 rmp= &mproc[proc_n];
145 result= m_in.EXC_RS_RESULT;
146 pc= (vir_bytes)m_in.EXC_RS_PC;
148 exec_restart(rmp, result, pc, rmp->mp_frame_addr);
150 return OK;
154 /*===========================================================================*
155 * exec_restart *
156 *===========================================================================*/
157 void exec_restart(rmp, result, pc, vfs_newsp)
158 struct mproc *rmp;
159 int result;
160 vir_bytes pc;
161 vir_bytes vfs_newsp;
163 int r, sn;
165 if (result != OK)
167 if (rmp->mp_flags & PARTIAL_EXEC)
169 /* Use SIGKILL to signal that something went wrong */
170 sys_kill(rmp->mp_endpoint, SIGKILL);
171 return;
173 setreply(rmp-mproc, result);
174 return;
177 rmp->mp_flags &= ~PARTIAL_EXEC;
179 /* Fix 'mproc' fields, tell kernel that exec is done, reset caught
180 * sigs.
182 for (sn = 1; sn < _NSIG; sn++) {
183 if (sigismember(&rmp->mp_catch, sn)) {
184 sigdelset(&rmp->mp_catch, sn);
185 rmp->mp_sigact[sn].sa_handler = SIG_DFL;
186 sigemptyset(&rmp->mp_sigact[sn].sa_mask);
190 /* Cause a signal if this process is traced.
191 * Do this before making the process runnable again!
193 #if USE_TRACE
194 if (rmp->mp_tracer != NO_TRACER && !(rmp->mp_trace_flags & TO_NOEXEC))
196 sn = (rmp->mp_trace_flags & TO_ALTEXEC) ? SIGSTOP : SIGTRAP;
198 check_sig(rmp->mp_pid, sn, FALSE /* ksig */);
200 #endif /* USE_TRACE */
202 /* Call kernel to exec with SP and PC set by VFS. */
203 r= sys_exec(rmp->mp_endpoint, (char *) vfs_newsp, rmp->mp_name, pc);
204 if (r != OK) panic("sys_exec failed: %d", r);