1433d6423SLionel Sambuc /* This file handles the EXEC system call. It performs the work as follows: 2433d6423SLionel Sambuc * - see if the permissions allow the file to be executed 3433d6423SLionel Sambuc * - read the header and extract the sizes 4433d6423SLionel Sambuc * - fetch the initial args and environment from the user space 5433d6423SLionel Sambuc * - allocate the memory for the new process 6433d6423SLionel Sambuc * - copy the initial stack from PM to the process 7433d6423SLionel Sambuc * - read in the text and data segments and copy to the process 8433d6423SLionel Sambuc * - take care of setuid and setgid bits 9433d6423SLionel Sambuc * - fix up 'mproc' table 10433d6423SLionel Sambuc * - tell kernel about EXEC 11433d6423SLionel Sambuc * - save offset to initial argc (for procfs) 12433d6423SLionel Sambuc * 13433d6423SLionel Sambuc * The entry points into this file are: 14433d6423SLionel Sambuc * do_exec: perform the EXEC system call 15433d6423SLionel Sambuc * do_newexec: handle PM part of exec call after VFS 16433d6423SLionel Sambuc * do_execrestart: finish the special exec call for RS 17433d6423SLionel Sambuc * exec_restart: finish a regular exec call 18433d6423SLionel Sambuc */ 19433d6423SLionel Sambuc 20433d6423SLionel Sambuc #include "pm.h" 21433d6423SLionel Sambuc #include <sys/stat.h> 22433d6423SLionel Sambuc #include <minix/callnr.h> 23433d6423SLionel Sambuc #include <minix/endpoint.h> 24433d6423SLionel Sambuc #include <minix/com.h> 25433d6423SLionel Sambuc #include <minix/vm.h> 26433d6423SLionel Sambuc #include <signal.h> 27433d6423SLionel Sambuc #include <libexec.h> 28433d6423SLionel Sambuc #include <sys/ptrace.h> 29433d6423SLionel Sambuc #include "mproc.h" 30433d6423SLionel Sambuc 31433d6423SLionel Sambuc #define ESCRIPT (-2000) /* Returned by read_header for a #! script. */ 32433d6423SLionel Sambuc #define PTRSIZE sizeof(char *) /* Size of pointers in argv[] and envp[]. */ 33433d6423SLionel Sambuc 34433d6423SLionel Sambuc /*===========================================================================* 35433d6423SLionel Sambuc * do_exec * 36433d6423SLionel Sambuc *===========================================================================*/ 37433d6423SLionel Sambuc int do_exec() 38433d6423SLionel Sambuc { 39433d6423SLionel Sambuc message m; 40433d6423SLionel Sambuc 41433d6423SLionel Sambuc /* Forward call to VFS */ 42433d6423SLionel Sambuc memset(&m, 0, sizeof(m)); 43433d6423SLionel Sambuc m.m_type = VFS_PM_EXEC; 44433d6423SLionel Sambuc m.VFS_PM_ENDPT = mp->mp_endpoint; 45433d6423SLionel Sambuc m.VFS_PM_PATH = (void *)m_in.m_lc_pm_exec.name; 46433d6423SLionel Sambuc m.VFS_PM_PATH_LEN = m_in.m_lc_pm_exec.namelen; 47433d6423SLionel Sambuc m.VFS_PM_FRAME = (void *)m_in.m_lc_pm_exec.frame; 48433d6423SLionel Sambuc m.VFS_PM_FRAME_LEN = m_in.m_lc_pm_exec.framelen; 49433d6423SLionel Sambuc m.VFS_PM_PS_STR = m_in.m_lc_pm_exec.ps_str; 50433d6423SLionel Sambuc 51433d6423SLionel Sambuc tell_vfs(mp, &m); 52433d6423SLionel Sambuc 53433d6423SLionel Sambuc /* Do not reply */ 54433d6423SLionel Sambuc return SUSPEND; 55433d6423SLionel Sambuc } 56433d6423SLionel Sambuc 57433d6423SLionel Sambuc 58433d6423SLionel Sambuc /*===========================================================================* 59433d6423SLionel Sambuc * do_newexec * 60433d6423SLionel Sambuc *===========================================================================*/ 61433d6423SLionel Sambuc int do_newexec(void) 62433d6423SLionel Sambuc { 63433d6423SLionel Sambuc int proc_e, proc_n, allow_setuid; 64433d6423SLionel Sambuc vir_bytes ptr; 65433d6423SLionel Sambuc struct mproc *rmp; 66433d6423SLionel Sambuc struct exec_info args; 67433d6423SLionel Sambuc int r; 68433d6423SLionel Sambuc 69433d6423SLionel Sambuc if (who_e != VFS_PROC_NR && who_e != RS_PROC_NR) 70433d6423SLionel Sambuc return EPERM; 71433d6423SLionel Sambuc 72433d6423SLionel Sambuc proc_e= m_in.m_lexec_pm_exec_new.endpt; 73433d6423SLionel Sambuc if (pm_isokendpt(proc_e, &proc_n) != OK) { 74433d6423SLionel Sambuc panic("do_newexec: got bad endpoint: %d", proc_e); 75433d6423SLionel Sambuc } 76433d6423SLionel Sambuc rmp= &mproc[proc_n]; 77433d6423SLionel Sambuc ptr= m_in.m_lexec_pm_exec_new.ptr; 78433d6423SLionel Sambuc r= sys_datacopy(who_e, ptr, SELF, (vir_bytes)&args, sizeof(args)); 79433d6423SLionel Sambuc if (r != OK) 80433d6423SLionel Sambuc panic("do_newexec: sys_datacopy failed: %d", r); 81433d6423SLionel Sambuc 82433d6423SLionel Sambuc allow_setuid = 0; /* Do not allow setuid execution */ 83433d6423SLionel Sambuc rmp->mp_flags &= ~TAINTED; /* By default not tainted */ 84433d6423SLionel Sambuc 85433d6423SLionel Sambuc if (rmp->mp_tracer == NO_TRACER) { 86433d6423SLionel Sambuc /* Okay, setuid execution is allowed */ 87433d6423SLionel Sambuc allow_setuid = 1; 88433d6423SLionel Sambuc } 89433d6423SLionel Sambuc 90433d6423SLionel Sambuc if (allow_setuid && args.allow_setuid) { 91433d6423SLionel Sambuc rmp->mp_effuid = args.new_uid; 92433d6423SLionel Sambuc rmp->mp_effgid = args.new_gid; 93433d6423SLionel Sambuc } 94433d6423SLionel Sambuc 95*1122b286SDavid van Moolenbroek /* Always update the saved user and group ID at this point. */ 96*1122b286SDavid van Moolenbroek rmp->mp_svuid = rmp->mp_effuid; 97*1122b286SDavid van Moolenbroek rmp->mp_svgid = rmp->mp_effgid; 98*1122b286SDavid van Moolenbroek 99433d6423SLionel Sambuc /* A process is considered 'tainted' when it's executing with 100433d6423SLionel Sambuc * setuid or setgid bit set, or when the real{u,g}id doesn't 101433d6423SLionel Sambuc * match the eff{u,g}id, respectively. */ 102433d6423SLionel Sambuc if (allow_setuid && args.allow_setuid) { 103433d6423SLionel Sambuc /* Program has setuid and/or setgid bits set */ 104433d6423SLionel Sambuc rmp->mp_flags |= TAINTED; 105433d6423SLionel Sambuc } else if (rmp->mp_effuid != rmp->mp_realuid || 106433d6423SLionel Sambuc rmp->mp_effgid != rmp->mp_realgid) { 107433d6423SLionel Sambuc rmp->mp_flags |= TAINTED; 108433d6423SLionel Sambuc } 109433d6423SLionel Sambuc 110433d6423SLionel Sambuc /* System will save command line for debugging, ps(1) output, etc. */ 111433d6423SLionel Sambuc strncpy(rmp->mp_name, args.progname, PROC_NAME_LEN-1); 112433d6423SLionel Sambuc rmp->mp_name[PROC_NAME_LEN-1] = '\0'; 113433d6423SLionel Sambuc 114433d6423SLionel Sambuc /* Save offset to initial argc (for procfs) */ 115433d6423SLionel Sambuc rmp->mp_frame_addr = (vir_bytes) args.stack_high - args.frame_len; 116433d6423SLionel Sambuc rmp->mp_frame_len = args.frame_len; 117433d6423SLionel Sambuc 118433d6423SLionel Sambuc /* Kill process if something goes wrong after this point. */ 119433d6423SLionel Sambuc rmp->mp_flags |= PARTIAL_EXEC; 120433d6423SLionel Sambuc 121433d6423SLionel Sambuc mp->mp_reply.m_pm_lexec_exec_new.suid = (allow_setuid && args.allow_setuid); 122433d6423SLionel Sambuc 123433d6423SLionel Sambuc return r; 124433d6423SLionel Sambuc } 125433d6423SLionel Sambuc 126433d6423SLionel Sambuc /*===========================================================================* 127433d6423SLionel Sambuc * do_execrestart * 128433d6423SLionel Sambuc *===========================================================================*/ 129433d6423SLionel Sambuc int do_execrestart(void) 130433d6423SLionel Sambuc { 131433d6423SLionel Sambuc int proc_e, proc_n, result; 132433d6423SLionel Sambuc struct mproc *rmp; 133433d6423SLionel Sambuc vir_bytes pc, ps_str; 134433d6423SLionel Sambuc 135433d6423SLionel Sambuc if (who_e != RS_PROC_NR) 136433d6423SLionel Sambuc return EPERM; 137433d6423SLionel Sambuc 138433d6423SLionel Sambuc proc_e = m_in.m_rs_pm_exec_restart.endpt; 139433d6423SLionel Sambuc if (pm_isokendpt(proc_e, &proc_n) != OK) { 140433d6423SLionel Sambuc panic("do_execrestart: got bad endpoint: %d", proc_e); 141433d6423SLionel Sambuc } 142433d6423SLionel Sambuc rmp = &mproc[proc_n]; 143433d6423SLionel Sambuc result = m_in.m_rs_pm_exec_restart.result; 144433d6423SLionel Sambuc pc = m_in.m_rs_pm_exec_restart.pc; 145433d6423SLionel Sambuc ps_str = m_in.m_rs_pm_exec_restart.ps_str; 146433d6423SLionel Sambuc 147433d6423SLionel Sambuc exec_restart(rmp, result, pc, rmp->mp_frame_addr, ps_str); 148433d6423SLionel Sambuc 149433d6423SLionel Sambuc return OK; 150433d6423SLionel Sambuc } 151433d6423SLionel Sambuc 152433d6423SLionel Sambuc /*===========================================================================* 153433d6423SLionel Sambuc * exec_restart * 154433d6423SLionel Sambuc *===========================================================================*/ 155433d6423SLionel Sambuc void exec_restart(struct mproc *rmp, int result, vir_bytes pc, vir_bytes sp, 156433d6423SLionel Sambuc vir_bytes ps_str) 157433d6423SLionel Sambuc { 158433d6423SLionel Sambuc int r, sn; 159433d6423SLionel Sambuc 160433d6423SLionel Sambuc if (result != OK) 161433d6423SLionel Sambuc { 162433d6423SLionel Sambuc if (rmp->mp_flags & PARTIAL_EXEC) 163433d6423SLionel Sambuc { 164433d6423SLionel Sambuc /* Use SIGKILL to signal that something went wrong */ 165433d6423SLionel Sambuc sys_kill(rmp->mp_endpoint, SIGKILL); 166433d6423SLionel Sambuc return; 167433d6423SLionel Sambuc } 168433d6423SLionel Sambuc reply(rmp-mproc, result); 169433d6423SLionel Sambuc return; 170433d6423SLionel Sambuc } 171433d6423SLionel Sambuc 172433d6423SLionel Sambuc rmp->mp_flags &= ~PARTIAL_EXEC; 173433d6423SLionel Sambuc 174433d6423SLionel Sambuc /* Fix 'mproc' fields, tell kernel that exec is done, reset caught 175433d6423SLionel Sambuc * sigs. 176433d6423SLionel Sambuc */ 177433d6423SLionel Sambuc for (sn = 1; sn < _NSIG; sn++) { 178433d6423SLionel Sambuc if (sigismember(&rmp->mp_catch, sn)) { 179433d6423SLionel Sambuc sigdelset(&rmp->mp_catch, sn); 180433d6423SLionel Sambuc rmp->mp_sigact[sn].sa_handler = SIG_DFL; 181433d6423SLionel Sambuc sigemptyset(&rmp->mp_sigact[sn].sa_mask); 182433d6423SLionel Sambuc } 183433d6423SLionel Sambuc } 184433d6423SLionel Sambuc 185433d6423SLionel Sambuc /* Cause a signal if this process is traced. 186433d6423SLionel Sambuc * Do this before making the process runnable again! 187433d6423SLionel Sambuc */ 188433d6423SLionel Sambuc if (rmp->mp_tracer != NO_TRACER && !(rmp->mp_trace_flags & TO_NOEXEC)) 189433d6423SLionel Sambuc { 190433d6423SLionel Sambuc sn = (rmp->mp_trace_flags & TO_ALTEXEC) ? SIGSTOP : SIGTRAP; 191433d6423SLionel Sambuc 192433d6423SLionel Sambuc check_sig(rmp->mp_pid, sn, FALSE /* ksig */); 193433d6423SLionel Sambuc } 194433d6423SLionel Sambuc 195433d6423SLionel Sambuc /* Call kernel to exec with SP and PC set by VFS. */ 196433d6423SLionel Sambuc r = sys_exec(rmp->mp_endpoint, sp, (vir_bytes)rmp->mp_name, pc, ps_str); 197433d6423SLionel Sambuc if (r != OK) panic("sys_exec failed: %d", r); 198433d6423SLionel Sambuc } 199433d6423SLionel Sambuc 200