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