xref: /minix/minix/servers/pm/exec.c (revision 433d6423)
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)
12  *
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
18  */
19 
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 <signal.h>
27 #include <libexec.h>
28 #include <sys/ptrace.h>
29 #include "mproc.h"
30 
31 #define ESCRIPT	(-2000)	/* Returned by read_header for a #! script. */
32 #define PTRSIZE	sizeof(char *) /* Size of pointers in argv[] and envp[]. */
33 
34 /*===========================================================================*
35  *				do_exec					     *
36  *===========================================================================*/
37 int do_exec()
38 {
39 	message m;
40 
41 	/* Forward call to VFS */
42 	memset(&m, 0, sizeof(m));
43 	m.m_type = VFS_PM_EXEC;
44 	m.VFS_PM_ENDPT = mp->mp_endpoint;
45 	m.VFS_PM_PATH = (void *)m_in.m_lc_pm_exec.name;
46 	m.VFS_PM_PATH_LEN = m_in.m_lc_pm_exec.namelen;
47 	m.VFS_PM_FRAME = (void *)m_in.m_lc_pm_exec.frame;
48 	m.VFS_PM_FRAME_LEN = m_in.m_lc_pm_exec.framelen;
49 	m.VFS_PM_PS_STR = m_in.m_lc_pm_exec.ps_str;
50 
51 	tell_vfs(mp, &m);
52 
53 	/* Do not reply */
54 	return SUSPEND;
55 }
56 
57 
58 /*===========================================================================*
59  *				do_newexec				     *
60  *===========================================================================*/
61 int do_newexec(void)
62 {
63 	int proc_e, proc_n, allow_setuid;
64 	vir_bytes ptr;
65 	struct mproc *rmp;
66 	struct exec_info args;
67 	int r;
68 
69 	if (who_e != VFS_PROC_NR && who_e != RS_PROC_NR)
70 		return EPERM;
71 
72 	proc_e= m_in.m_lexec_pm_exec_new.endpt;
73 	if (pm_isokendpt(proc_e, &proc_n) != OK) {
74 		panic("do_newexec: got bad endpoint: %d", proc_e);
75 	}
76 	rmp= &mproc[proc_n];
77 	ptr= m_in.m_lexec_pm_exec_new.ptr;
78 	r= sys_datacopy(who_e, ptr, SELF, (vir_bytes)&args, sizeof(args));
79 	if (r != OK)
80 		panic("do_newexec: sys_datacopy failed: %d", r);
81 
82 	allow_setuid = 0;	/* Do not allow setuid execution */
83 	rmp->mp_flags &= ~TAINTED;	/* By default not tainted */
84 
85 	if (rmp->mp_tracer == NO_TRACER) {
86 		/* Okay, setuid execution is allowed */
87 		allow_setuid = 1;
88 	}
89 
90 	if (allow_setuid && args.allow_setuid) {
91 		rmp->mp_effuid = args.new_uid;
92 		rmp->mp_effgid = args.new_gid;
93 	}
94 
95 	/* A process is considered 'tainted' when it's executing with
96 	 * setuid or setgid bit set, or when the real{u,g}id doesn't
97 	 * match the eff{u,g}id, respectively. */
98 	if (allow_setuid && args.allow_setuid) {
99 		/* Program has setuid and/or setgid bits set */
100 		rmp->mp_flags |= TAINTED;
101 	} else if (rmp->mp_effuid != rmp->mp_realuid ||
102 		   rmp->mp_effgid != rmp->mp_realgid) {
103 		rmp->mp_flags |= TAINTED;
104 	}
105 
106 	/* System will save command line for debugging, ps(1) output, etc. */
107 	strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1);
108 	rmp->mp_name[PROC_NAME_LEN-1] = '\0';
109 
110 	/* Save offset to initial argc (for procfs) */
111 	rmp->mp_frame_addr = (vir_bytes) args.stack_high - args.frame_len;
112 	rmp->mp_frame_len = args.frame_len;
113 
114 	/* Kill process if something goes wrong after this point. */
115 	rmp->mp_flags |= PARTIAL_EXEC;
116 
117 	mp->mp_reply.m_pm_lexec_exec_new.suid = (allow_setuid && args.allow_setuid);
118 
119 	return r;
120 }
121 
122 /*===========================================================================*
123  *				do_execrestart				     *
124  *===========================================================================*/
125 int do_execrestart(void)
126 {
127 	int proc_e, proc_n, result;
128 	struct mproc *rmp;
129 	vir_bytes pc, ps_str;
130 
131 	if (who_e != RS_PROC_NR)
132 		return EPERM;
133 
134 	proc_e = m_in.m_rs_pm_exec_restart.endpt;
135 	if (pm_isokendpt(proc_e, &proc_n) != OK) {
136 		panic("do_execrestart: got bad endpoint: %d", proc_e);
137 	}
138 	rmp = &mproc[proc_n];
139 	result = m_in.m_rs_pm_exec_restart.result;
140 	pc = m_in.m_rs_pm_exec_restart.pc;
141 	ps_str = m_in.m_rs_pm_exec_restart.ps_str;
142 
143 	exec_restart(rmp, result, pc, rmp->mp_frame_addr, ps_str);
144 
145 	return OK;
146 }
147 
148 /*===========================================================================*
149  *				exec_restart				     *
150  *===========================================================================*/
151 void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp,
152        vir_bytes ps_str)
153 {
154 	int r, sn;
155 
156 	if (result != OK)
157 	{
158 		if (rmp->mp_flags & PARTIAL_EXEC)
159 		{
160 			/* Use SIGKILL to signal that something went wrong */
161 			sys_kill(rmp->mp_endpoint, SIGKILL);
162 			return;
163 		}
164 		reply(rmp-mproc, result);
165 		return;
166 	}
167 
168 	rmp->mp_flags &= ~PARTIAL_EXEC;
169 
170 	/* Fix 'mproc' fields, tell kernel that exec is done, reset caught
171 	 * sigs.
172 	 */
173 	for (sn = 1; sn < _NSIG; sn++) {
174 		if (sigismember(&rmp->mp_catch, sn)) {
175 			sigdelset(&rmp->mp_catch, sn);
176 			rmp->mp_sigact[sn].sa_handler = SIG_DFL;
177 			sigemptyset(&rmp->mp_sigact[sn].sa_mask);
178 		}
179 	}
180 
181 	/* Cause a signal if this process is traced.
182 	 * Do this before making the process runnable again!
183 	 */
184 	if (rmp->mp_tracer != NO_TRACER && !(rmp->mp_trace_flags & TO_NOEXEC))
185 	{
186 		sn = (rmp->mp_trace_flags & TO_ALTEXEC) ? SIGSTOP : SIGTRAP;
187 
188 		check_sig(rmp->mp_pid, sn, FALSE /* ksig */);
189 	}
190 
191 	/* Call kernel to exec with SP and PC set by VFS. */
192 	r = sys_exec(rmp->mp_endpoint, sp, (vir_bytes)rmp->mp_name, pc, ps_str);
193 	if (r != OK) panic("sys_exec failed: %d", r);
194 }
195 
196