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.
This commit is contained in:
Thomas Veerman 2012-01-27 11:50:11 +00:00
parent 4bee3cff2e
commit 0bd011affd
10 changed files with 55 additions and 28 deletions

View file

@ -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 */

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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';

View file

@ -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");
}

View file

@ -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);

View file

@ -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) \

View file

@ -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;