From 0bd011affd7ee93768bfeb68bc8115e812137435 Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Fri, 27 Jan 2012 11:50:11 +0000 Subject: [PATCH] PM: extend srv_fork to set a specific UID Currently, all servers and drivers run as root as they are forks of RS. srv_fork now tells PM with which credentials to run the resulting fork. Subsequently, PM lets VFS now as well. This patch also fixes the following bugs: - RS doesn't initialize the setugid variable during exec, causing the servers and drivers to run setuid rendering the srv_fork extension useless. - PM erroneously tells VFS to run processes setuid. This doesn't actually lead to setuid processes as VFS sets {r,e}uid and {r,e}gid properly before checking PM's approval. --- common/include/minix/com.h | 36 +++++++++++++++++++----------------- etc/system.conf | 2 -- servers/avfs/main.c | 8 +++++++- servers/pm/exec.c | 4 +++- servers/pm/forkexit.c | 8 ++++++++ servers/rs/exec.c | 3 +++ servers/rs/main.c | 4 ++-- servers/rs/manager.c | 8 +++++--- servers/rs/proto.h | 2 +- servers/vfs/main.c | 8 +++++++- 10 files changed, 55 insertions(+), 28 deletions(-) diff --git a/common/include/minix/com.h b/common/include/minix/com.h index 1278c6018..c1c4f6f40 100644 --- a/common/include/minix/com.h +++ b/common/include/minix/com.h @@ -764,39 +764,41 @@ #define PM_SETGROUPS_REPLY (PM_RS_BASE + 11) /* Standard parameters for all requests and replies, except PM_REBOOT */ -# define PM_PROC m1_i1 /* process endpoint */ +# define PM_PROC m7_i1 /* process endpoint */ /* Additional parameters for PM_INIT */ -# define PM_SLOT m1_i2 /* process slot number */ -# define PM_PID m1_i3 /* process pid */ +# define PM_SLOT m7_i2 /* process slot number */ +# define PM_PID m7_i3 /* process pid */ /* Additional parameters for PM_SETUID and PM_SETGID */ -# define PM_EID m1_i2 /* effective user/group id */ -# define PM_RID m1_i3 /* real user/group id */ +# define PM_EID m7_i2 /* effective user/group id */ +# define PM_RID m7_i3 /* real user/group id */ /* Additional parameter for PM_SETGROUPS */ -# define PM_GROUP_NO m1_i2 /* number of groups */ -# define PM_GROUP_ADDR m1_p1 /* struct holding group data */ +# define PM_GROUP_NO m7_i2 /* number of groups */ +# define PM_GROUP_ADDR m7_p1 /* struct holding group data */ /* Additional parameters for PM_EXEC */ -# define PM_PATH m1_p1 /* executable */ -# define PM_PATH_LEN m1_i2 /* length of path including +# define PM_PATH m7_p1 /* executable */ +# define PM_PATH_LEN m7_i2 /* length of path including * terminating null character */ -# define PM_FRAME m1_p2 /* arguments and environment */ -# define PM_FRAME_LEN m1_i3 /* size of frame */ +# define PM_FRAME m7_p2 /* arguments and environment */ +# define PM_FRAME_LEN m7_i3 /* size of frame */ /* Additional parameters for PM_EXEC_REPLY and PM_CORE_REPLY */ -# define PM_STATUS m1_i2 /* OK or failure */ -# define PM_PC m1_p1 /* program counter */ +# define PM_STATUS m7_i2 /* OK or failure */ +# define PM_PC m7_p1 /* program counter */ /* Additional parameters for PM_FORK and PM_SRV_FORK */ -# define PM_PPROC m1_i2 /* parent process endpoint */ -# define PM_CPID m1_i3 /* child pid */ +# define PM_PPROC m7_i2 /* parent process endpoint */ +# define PM_CPID m7_i3 /* child pid */ +# define PM_REUID m7_i4 /* real and effective uid */ +# define PM_REGID m7_i5 /* real and effective gid */ /* Additional parameters for PM_DUMPCORE */ -# define PM_TERM_SIG m1_i2 /* process's termination signal */ -# define PM_TRACED_PROC m1_i3 /* required for T_DUMPCORE */ +# define PM_TERM_SIG m7_i2 /* process's termination signal */ +# define PM_TRACED_PROC m7_i3 /* required for T_DUMPCORE */ /* Parameters for the EXEC_NEWMEM call */ #define EXC_NM_PROC m1_i1 /* process that needs new map */ diff --git a/etc/system.conf b/etc/system.conf index efa65b714..7a021b812 100644 --- a/etc/system.conf +++ b/etc/system.conf @@ -104,7 +104,6 @@ service vfs service mfs { - uid 0; ipc ALL_SYS; # All system ipc targets allowed system BASIC; # Only basic kernel calls allowed vm BASIC; # Only basic VM calls allowed @@ -144,7 +143,6 @@ service ext2 service pfs { - uid 0; ipc ALL_SYS; # All system ipc targets allowed system BASIC; # Only basic kernel calls allowed vm BASIC; # Only basic VM calls allowed diff --git a/servers/avfs/main.c b/servers/avfs/main.c index 85ac294b8..bca40234a 100644 --- a/servers/avfs/main.c +++ b/servers/avfs/main.c @@ -908,8 +908,14 @@ PRIVATE void service_pm() case PM_FORK: case PM_SRV_FORK: pm_fork(m_in.PM_PPROC, m_in.PM_PROC, m_in.PM_CPID); + m_out.m_type = PM_FORK_REPLY; + + if (call_nr == PM_SRV_FORK) { + m_out.m_type = PM_SRV_FORK_REPLY; + pm_setuid(m_in.PM_PROC, m_in.PM_REUID, m_in.PM_REUID); + pm_setgid(m_in.PM_PROC, m_in.PM_REGID, m_in.PM_REGID); + } - m_out.m_type = (call_nr == PM_FORK) ? PM_FORK_REPLY : PM_SRV_FORK_REPLY; m_out.PM_PROC = m_in.PM_PROC; break; diff --git a/servers/pm/exec.c b/servers/pm/exec.c index 2b03018a8..0942b9970 100644 --- a/servers/pm/exec.c +++ b/servers/pm/exec.c @@ -89,7 +89,9 @@ PUBLIC int do_exec_newmem() if (rmp->mp_tracer == NO_TRACER) { /* Okay, setuid execution is allowed */ allow_setuid = 1; + } + if (allow_setuid && args.setugid) { rmp->mp_effuid = args.new_uid; rmp->mp_effgid = args.new_gid; } @@ -118,7 +120,7 @@ PUBLIC int do_exec_newmem() mp->mp_reply.reply_res2= (vir_bytes) stack_top; mp->mp_reply.reply_res3= flags; - if (allow_setuid) + if (allow_setuid && args.setugid) mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID; } else { printf("PM: newmem failed for %s\n", args.progname); diff --git a/servers/pm/forkexit.c b/servers/pm/forkexit.c index 020bc6e7f..49ea34585 100644 --- a/servers/pm/forkexit.c +++ b/servers/pm/forkexit.c @@ -120,6 +120,8 @@ PUBLIC int do_fork() m.PM_PROC = rmc->mp_endpoint; m.PM_PPROC = rmp->mp_endpoint; m.PM_CPID = rmc->mp_pid; + m.PM_REUID = -1; /* Not used by PM_FORK */ + m.PM_REGID = -1; /* Not used by PM_FORK */ tell_vfs(rmc, &m); @@ -198,6 +200,10 @@ PUBLIC int do_srv_fork() rmc->mp_exitstatus = 0; rmc->mp_sigstatus = 0; rmc->mp_endpoint = child_ep; /* passed back by VM */ + rmc->mp_realuid = (uid_t) m_in.m1_i1; + rmc->mp_effuid = (uid_t) m_in.m1_i1; + rmc->mp_realgid = (uid_t) m_in.m1_i2; + rmc->mp_effgid = (uid_t) m_in.m1_i2; for (i = 0; i < NR_ITIMERS; i++) rmc->mp_interval[i] = 0; /* reset timer intervals */ @@ -209,6 +215,8 @@ PUBLIC int do_srv_fork() m.PM_PROC = rmc->mp_endpoint; m.PM_PPROC = rmp->mp_endpoint; m.PM_CPID = rmc->mp_pid; + m.PM_REUID = m_in.m1_i1; + m.PM_REGID = m_in.m1_i2; tell_vfs(rmc, &m); diff --git a/servers/rs/exec.c b/servers/rs/exec.c index 1e5556b54..a706d0d9d 100644 --- a/servers/rs/exec.c +++ b/servers/rs/exec.c @@ -193,6 +193,7 @@ static int load_aout(struct exec_info *execi) new_uid= getuid(); new_gid= getgid(); + allow_setuid = 0; /* XXX what should we use to identify the executable? */ r= exec_newmem(proc_e, 0 /*text_addr*/, text_bytes, @@ -263,6 +264,7 @@ static int load_elf(struct exec_info *execi) new_uid= getuid(); new_gid= getgid(); + allow_setuid = 0; sep_id = 0; is_elf = 1; @@ -347,6 +349,7 @@ static int exec_newmem( e.enst_ctime= ctime; e.new_uid= new_uid; e.new_gid= new_gid; + e.setugid= *allow_setuidp; strncpy(e.progname, progname, sizeof(e.progname)-1); e.progname[sizeof(e.progname)-1]= '\0'; diff --git a/servers/rs/main.c b/servers/rs/main.c index 34b376b22..ebbf3ead3 100644 --- a/servers/rs/main.c +++ b/servers/rs/main.c @@ -436,8 +436,8 @@ PRIVATE int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) panic("unable to clone current RS instance: %d", s); } - /* Fork a new RS instance. */ - pid = srv_fork(); + /* Fork a new RS instance with root:operator. */ + pid = srv_fork(0, 0); if(pid == -1) { panic("unable to fork a new RS instance"); } diff --git a/servers/rs/manager.c b/servers/rs/manager.c index d9dd58075..b524a06de 100644 --- a/servers/rs/manager.c +++ b/servers/rs/manager.c @@ -211,11 +211,13 @@ PUBLIC void build_cmd_dep(struct rproc *rp) /*===========================================================================* * srv_fork * *===========================================================================*/ -PUBLIC pid_t srv_fork() +PUBLIC pid_t srv_fork(uid_t reuid, gid_t regid) { message m; - return(_syscall(PM_PROC_NR, SRV_FORK, &m)); + m.m1_i1 = (int) reuid; + m.m1_i2 = (int) regid; + return _syscall(PM_PROC_NR, SRV_FORK, &m); } /*===========================================================================* @@ -476,7 +478,7 @@ struct rproc *rp; */ if(rs_verbose) printf("RS: forking child with srv_fork()...\n"); - child_pid= srv_fork(); + child_pid= srv_fork(rp->r_uid, 0); /* Force group to operator for now */ if(child_pid == -1) { printf("RS: srv_fork() failed (error %d)\n", errno); free_slot(rp); diff --git a/servers/rs/proto.h b/servers/rs/proto.h index 1a0fe047e..3f9ba4a0a 100644 --- a/servers/rs/proto.h +++ b/servers/rs/proto.h @@ -34,7 +34,7 @@ _PROTOTYPE( int copy_rs_start, (endpoint_t src_e, char *src_rs_start, _PROTOTYPE( int copy_label, (endpoint_t src_e, char *src_label, size_t src_len, char *dst_label, size_t dst_len) ); _PROTOTYPE( void build_cmd_dep, (struct rproc *rp) ); -_PROTOTYPE( int srv_fork, (void) ); +_PROTOTYPE( int srv_fork, (uid_t reuid, gid_t regid) ); _PROTOTYPE( int srv_kill, (pid_t pid, int sig) ); _PROTOTYPE( int srv_update, (endpoint_t src_e, endpoint_t dst_e) ); #define kill_service(rp, errstr, err) \ diff --git a/servers/vfs/main.c b/servers/vfs/main.c index 53a631b15..34165898a 100644 --- a/servers/vfs/main.c +++ b/servers/vfs/main.c @@ -566,8 +566,14 @@ PRIVATE void service_pm() case PM_FORK: case PM_SRV_FORK: pm_fork(m_in.PM_PPROC, m_in.PM_PROC, m_in.PM_CPID); + m_out.m_type = PM_FORK_REPLY; + + if (call_nr == PM_SRV_FORK) { + m_out.m_type = PM_SRV_FORK_REPLY; + pm_setuid(m_in.PM_PROC, m_in.PM_REUID, m_in.PM_REUID); + pm_setgid(m_in.PM_PROC, m_in.PM_REGID, m_in.PM_REGID); + } - m_out.m_type = (call_nr == PM_FORK) ? PM_FORK_REPLY : PM_SRV_FORK_REPLY; m_out.PM_PROC = m_in.PM_PROC; break;