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:
		
							parent
							
								
									4bee3cff2e
								
							
						
					
					
						commit
						0bd011affd
					
				| @ -764,39 +764,41 @@ | |||||||
| #define PM_SETGROUPS_REPLY	(PM_RS_BASE + 11) | #define PM_SETGROUPS_REPLY	(PM_RS_BASE + 11) | ||||||
| 
 | 
 | ||||||
| /* Standard parameters for all requests and replies, except PM_REBOOT */ | /* 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 */ | /* Additional parameters for PM_INIT */ | ||||||
| #  define PM_SLOT		m1_i2	/* process slot number */ | #  define PM_SLOT		m7_i2	/* process slot number */ | ||||||
| #  define PM_PID		m1_i3	/* process pid */ | #  define PM_PID		m7_i3	/* process pid */ | ||||||
| 
 | 
 | ||||||
| /* Additional parameters for PM_SETUID and PM_SETGID */ | /* Additional parameters for PM_SETUID and PM_SETGID */ | ||||||
| #  define PM_EID		m1_i2	/* effective user/group id */ | #  define PM_EID		m7_i2	/* effective user/group id */ | ||||||
| #  define PM_RID		m1_i3	/* real user/group id */ | #  define PM_RID		m7_i3	/* real user/group id */ | ||||||
| 
 | 
 | ||||||
| /* Additional parameter for PM_SETGROUPS */ | /* Additional parameter for PM_SETGROUPS */ | ||||||
| #  define PM_GROUP_NO		m1_i2	/* number of groups */ | #  define PM_GROUP_NO		m7_i2	/* number of groups */ | ||||||
| #  define PM_GROUP_ADDR		m1_p1	/* struct holding group data */ | #  define PM_GROUP_ADDR		m7_p1	/* struct holding group data */ | ||||||
| 
 | 
 | ||||||
| /* Additional parameters for PM_EXEC */ | /* Additional parameters for PM_EXEC */ | ||||||
| #  define PM_PATH		m1_p1	/* executable */ | #  define PM_PATH		m7_p1	/* executable */ | ||||||
| #  define PM_PATH_LEN		m1_i2	/* length of path including | #  define PM_PATH_LEN		m7_i2	/* length of path including | ||||||
| 					 * terminating null character | 					 * terminating null character | ||||||
| 					 */ | 					 */ | ||||||
| #  define PM_FRAME		m1_p2	/* arguments and environment */ | #  define PM_FRAME		m7_p2	/* arguments and environment */ | ||||||
| #  define PM_FRAME_LEN		m1_i3	/* size of frame */ | #  define PM_FRAME_LEN		m7_i3	/* size of frame */ | ||||||
| 
 | 
 | ||||||
| /* Additional parameters for PM_EXEC_REPLY and PM_CORE_REPLY */ | /* Additional parameters for PM_EXEC_REPLY and PM_CORE_REPLY */ | ||||||
| #  define PM_STATUS		m1_i2	/* OK or failure */ | #  define PM_STATUS		m7_i2	/* OK or failure */ | ||||||
| #  define PM_PC	        m1_p1	/* program counter */ | #  define PM_PC			m7_p1	/* program counter */ | ||||||
| 
 | 
 | ||||||
| /* Additional parameters for PM_FORK and PM_SRV_FORK */ | /* Additional parameters for PM_FORK and PM_SRV_FORK */ | ||||||
| #  define PM_PPROC		m1_i2	/* parent process endpoint */ | #  define PM_PPROC		m7_i2	/* parent process endpoint */ | ||||||
| #  define PM_CPID		m1_i3	/* child pid */ | #  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 */ | /* Additional parameters for PM_DUMPCORE */ | ||||||
| #  define PM_TERM_SIG		m1_i2	/* process's termination signal */ | #  define PM_TERM_SIG		m7_i2	/* process's termination signal */ | ||||||
| #  define PM_TRACED_PROC	m1_i3	/* required for T_DUMPCORE */ | #  define PM_TRACED_PROC	m7_i3	/* required for T_DUMPCORE */ | ||||||
| 
 | 
 | ||||||
| /* Parameters for the EXEC_NEWMEM call */ | /* Parameters for the EXEC_NEWMEM call */ | ||||||
| #define EXC_NM_PROC	m1_i1		/* process that needs new map */ | #define EXC_NM_PROC	m1_i1		/* process that needs new map */ | ||||||
|  | |||||||
| @ -104,7 +104,6 @@ service vfs | |||||||
| 
 | 
 | ||||||
| service mfs | service mfs | ||||||
| { | { | ||||||
| 	uid     0; |  | ||||||
| 	ipc	ALL_SYS;	# All system ipc targets allowed | 	ipc	ALL_SYS;	# All system ipc targets allowed | ||||||
| 	system	BASIC;		# Only basic kernel calls allowed | 	system	BASIC;		# Only basic kernel calls allowed | ||||||
| 	vm	BASIC;		# Only basic VM calls allowed | 	vm	BASIC;		# Only basic VM calls allowed | ||||||
| @ -144,7 +143,6 @@ service ext2 | |||||||
| 
 | 
 | ||||||
| service pfs | service pfs | ||||||
| { | { | ||||||
| 	uid     0; |  | ||||||
| 	ipc	ALL_SYS;	# All system ipc targets allowed | 	ipc	ALL_SYS;	# All system ipc targets allowed | ||||||
| 	system	BASIC;		# Only basic kernel calls allowed | 	system	BASIC;		# Only basic kernel calls allowed | ||||||
| 	vm	BASIC;		# Only basic VM calls allowed | 	vm	BASIC;		# Only basic VM calls allowed | ||||||
|  | |||||||
| @ -908,8 +908,14 @@ PRIVATE void service_pm() | |||||||
|     case PM_FORK: |     case PM_FORK: | ||||||
|     case PM_SRV_FORK: |     case PM_SRV_FORK: | ||||||
| 	pm_fork(m_in.PM_PPROC, m_in.PM_PROC, m_in.PM_CPID); | 	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; | 	m_out.PM_PROC = m_in.PM_PROC; | ||||||
| 
 | 
 | ||||||
| 	break; | 	break; | ||||||
|  | |||||||
| @ -89,7 +89,9 @@ PUBLIC int do_exec_newmem() | |||||||
| 		if (rmp->mp_tracer == NO_TRACER) { | 		if (rmp->mp_tracer == NO_TRACER) { | ||||||
| 			/* Okay, setuid execution is allowed */ | 			/* Okay, setuid execution is allowed */ | ||||||
| 			allow_setuid = 1; | 			allow_setuid = 1; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if (allow_setuid && args.setugid) { | ||||||
| 			rmp->mp_effuid = args.new_uid; | 			rmp->mp_effuid = args.new_uid; | ||||||
| 			rmp->mp_effgid = args.new_gid; | 			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_res2= (vir_bytes) stack_top; | ||||||
| 		mp->mp_reply.reply_res3= flags; | 		mp->mp_reply.reply_res3= flags; | ||||||
| 		if (allow_setuid) | 		if (allow_setuid && args.setugid) | ||||||
| 			mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID; | 			mp->mp_reply.reply_res3 |= EXC_NM_RF_ALLOW_SETUID; | ||||||
| 	} else { | 	} else { | ||||||
| 		printf("PM: newmem failed for %s\n", args.progname); | 		printf("PM: newmem failed for %s\n", args.progname); | ||||||
|  | |||||||
| @ -120,6 +120,8 @@ PUBLIC int do_fork() | |||||||
|   m.PM_PROC = rmc->mp_endpoint; |   m.PM_PROC = rmc->mp_endpoint; | ||||||
|   m.PM_PPROC = rmp->mp_endpoint; |   m.PM_PPROC = rmp->mp_endpoint; | ||||||
|   m.PM_CPID = rmc->mp_pid; |   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); |   tell_vfs(rmc, &m); | ||||||
| 
 | 
 | ||||||
| @ -198,6 +200,10 @@ PUBLIC int do_srv_fork() | |||||||
|   rmc->mp_exitstatus = 0; |   rmc->mp_exitstatus = 0; | ||||||
|   rmc->mp_sigstatus = 0; |   rmc->mp_sigstatus = 0; | ||||||
|   rmc->mp_endpoint = child_ep;		/* passed back by VM */ |   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++) |   for (i = 0; i < NR_ITIMERS; i++) | ||||||
| 	rmc->mp_interval[i] = 0;	/* reset timer intervals */ | 	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_PROC = rmc->mp_endpoint; | ||||||
|   m.PM_PPROC = rmp->mp_endpoint; |   m.PM_PPROC = rmp->mp_endpoint; | ||||||
|   m.PM_CPID = rmc->mp_pid; |   m.PM_CPID = rmc->mp_pid; | ||||||
|  |   m.PM_REUID = m_in.m1_i1; | ||||||
|  |   m.PM_REGID = m_in.m1_i2; | ||||||
| 
 | 
 | ||||||
|   tell_vfs(rmc, &m); |   tell_vfs(rmc, &m); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -193,6 +193,7 @@ static int load_aout(struct exec_info *execi) | |||||||
| 
 | 
 | ||||||
| 	new_uid= getuid(); | 	new_uid= getuid(); | ||||||
| 	new_gid= getgid(); | 	new_gid= getgid(); | ||||||
|  | 	allow_setuid = 0; | ||||||
| 
 | 
 | ||||||
| 	/* XXX what should we use to identify the executable? */ | 	/* XXX what should we use to identify the executable? */ | ||||||
| 	r= exec_newmem(proc_e, 0 /*text_addr*/, text_bytes, | 	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_uid= getuid(); | ||||||
|   new_gid= getgid(); |   new_gid= getgid(); | ||||||
|  |   allow_setuid = 0; | ||||||
| 
 | 
 | ||||||
|   sep_id = 0; |   sep_id = 0; | ||||||
|   is_elf = 1; |   is_elf = 1; | ||||||
| @ -347,6 +349,7 @@ static int exec_newmem( | |||||||
| 	e.enst_ctime= ctime; | 	e.enst_ctime= ctime; | ||||||
| 	e.new_uid= new_uid; | 	e.new_uid= new_uid; | ||||||
| 	e.new_gid= new_gid; | 	e.new_gid= new_gid; | ||||||
|  | 	e.setugid= *allow_setuidp; | ||||||
| 	strncpy(e.progname, progname, sizeof(e.progname)-1); | 	strncpy(e.progname, progname, sizeof(e.progname)-1); | ||||||
| 	e.progname[sizeof(e.progname)-1]= '\0'; | 	e.progname[sizeof(e.progname)-1]= '\0'; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -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); |       panic("unable to clone current RS instance: %d", s); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /* Fork a new RS instance. */ |   /* Fork a new RS instance with root:operator. */ | ||||||
|   pid = srv_fork(); |   pid = srv_fork(0, 0); | ||||||
|   if(pid == -1) { |   if(pid == -1) { | ||||||
|       panic("unable to fork a new RS instance"); |       panic("unable to fork a new RS instance"); | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -211,11 +211,13 @@ PUBLIC void build_cmd_dep(struct rproc *rp) | |||||||
| /*===========================================================================*
 | /*===========================================================================*
 | ||||||
|  *				 srv_fork				     * |  *				 srv_fork				     * | ||||||
|  *===========================================================================*/ |  *===========================================================================*/ | ||||||
| PUBLIC pid_t srv_fork() | PUBLIC pid_t srv_fork(uid_t reuid, gid_t regid) | ||||||
| { | { | ||||||
|   message m; |   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) |   if(rs_verbose) | ||||||
|       printf("RS: forking child with srv_fork()...\n"); |       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) { |   if(child_pid == -1) { | ||||||
|       printf("RS: srv_fork() failed (error %d)\n", errno); |       printf("RS: srv_fork() failed (error %d)\n", errno); | ||||||
|       free_slot(rp); |       free_slot(rp); | ||||||
|  | |||||||
| @ -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, | _PROTOTYPE( int copy_label, (endpoint_t src_e, char *src_label, size_t src_len, | ||||||
| 	char *dst_label, size_t dst_len) ); | 	char *dst_label, size_t dst_len) ); | ||||||
| _PROTOTYPE( void build_cmd_dep, (struct rproc *rp) ); | _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_kill, (pid_t pid, int sig) ); | ||||||
| _PROTOTYPE( int srv_update, (endpoint_t src_e, endpoint_t dst_e) ); | _PROTOTYPE( int srv_update, (endpoint_t src_e, endpoint_t dst_e) ); | ||||||
| #define kill_service(rp, errstr, err) \ | #define kill_service(rp, errstr, err) \ | ||||||
|  | |||||||
| @ -566,8 +566,14 @@ PRIVATE void service_pm() | |||||||
|   case PM_FORK: |   case PM_FORK: | ||||||
|   case PM_SRV_FORK: |   case PM_SRV_FORK: | ||||||
| 	pm_fork(m_in.PM_PPROC, m_in.PM_PROC, m_in.PM_CPID); | 	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; | 	m_out.PM_PROC = m_in.PM_PROC; | ||||||
| 
 | 
 | ||||||
| 	break; | 	break; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Thomas Veerman
						Thomas Veerman