Subject: sysctl_proc_find() in kern_resource.c
To: YAMAMOTO Takashi <yamt@mwd.biglobe.ne.jp>
From: Elad Efrat <elad@NetBSD.org>
List: tech-kern
Date: 12/14/2006 11:20:48
This is a multi-part message in MIME format.
--------------040303080105050106020809
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

hi,

sysctl_proc_find() is used for both looking up a process by its pid
and performing "access" checks on it for three different callers.

attached diff:

  - moves 'nice' access semantics to secmodel code,
  - makes sysctl_proc_find() just lookup the process,
  - use KAUTH_PROCESS_CANSEE requests to determine if the caller is
    allowed to view the target process' corename, stop flags, and
    rlimits.
  - use explicit kauth(9) calls with KAUTH_PROCESS_CORENAME,
    KAUTH_REQ_PROCESS_RESOURCE_NICE, KAUTH_REQ_PROCESS_RESOURCE_RLIMIT,
    and KAUTH_PROCESS_STOPFLAG when modifying the aforementioned.

notes:

  - the semantics were copied verbatim from the sysctl code. I don't
    know if they are correct. for example, sys_setrlimit() allows
    modifying only the current process; no idea what the semantics
    should be for non-root user changing rlimits on not-current process.
    same goes for corename.

  - sysctl_proc_find()'s existence isn't justified. ideally, we can just
    use pfind(). however, pfind() should also use KAUTH_PROCESS_CANSEE,
    so I'll do that some other time.

-e.

--------------040303080105050106020809
Content-Type: text/plain;
 name="res.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="res.diff"

Index: secmodel/bsd44/secmodel_bsd44_suser.c
===================================================================
RCS file: /usr/cvs/src/sys/secmodel/bsd44/secmodel_bsd44_suser.c,v
retrieving revision 1.17
diff -u -p -r1.17 secmodel_bsd44_suser.c
--- secmodel/bsd44/secmodel_bsd44_suser.c	28 Nov 2006 17:27:10 -0000	1.17
+++ secmodel/bsd44/secmodel_bsd44_suser.c	13 Dec 2006 02:34:59 -0000
@@ -250,30 +250,112 @@ secmodel_bsd44_suser_process_cb(kauth_cr
 		result = KAUTH_RESULT_ALLOW;
 		break;
 
+	case KAUTH_PROCESS_CORENAME:
+		result = KAUTH_RESULT_ALLOW;
+
+		if (isroot)
+			break;
+
+		/*
+		 * suid proc of ours or proc not ours
+		 */
+		if (kauth_cred_getuid(cred) != kauth_cred_getuid(p->p_cred) ||
+		    kauth_cred_getuid(cred) != kauth_cred_getsvuid(p->p_cred))
+			result = KAUTH_RESULT_DENY;
+
+		/*
+		 * sgid proc has sgid back to us temporarily
+		 */
+		else if (kauth_cred_getgid(p->p_cred) != kauth_cred_getsvgid(p->p_cred))
+			result = KAUTH_RESULT_DENY;
+
+		/*
+		 * our rgid must be in target's group list (ie,
+		 * sub-processes started by a sgid process)
+		 */
+		else {
+			int ismember = 0;
+
+			if (kauth_cred_ismember_gid(cred,
+			    kauth_cred_getgid(p->p_cred), &ismember) != 0 ||
+			    !ismember)
+				result = KAUTH_RESULT_DENY;
+		}
+		break;
+
 	case KAUTH_PROCESS_RESOURCE:
 		switch ((u_long)arg1) {
 		case KAUTH_REQ_PROCESS_RESOURCE_NICE:
-			if (isroot)
+			if (isroot) {
+				result = KAUTH_RESULT_ALLOW;
+				break;
+			}
+
+			if (kauth_cred_geteuid(cred) !=
+			    kauth_cred_geteuid(p->p_cred) &&
+			    kauth_cred_getuid(cred) !=
+			    kauth_cred_geteuid(p->p_cred)) {
+				result = KAUTH_RESULT_DENY;
+				break;
+			}
+
+			if ((u_long)arg2 >= p->p_nice)
 				result = KAUTH_RESULT_ALLOW;
-			else if ((u_long)arg2 >= p->p_nice)
-				result = KAUTH_RESULT_ALLOW; 
+
 			break;
 
-		case KAUTH_REQ_PROCESS_RESOURCE_RLIMIT:
-			if (isroot)
+		case KAUTH_REQ_PROCESS_RESOURCE_RLIMIT: {
+			struct rlimit *new_rlimit;
+			u_long which;
+
+			if (isroot) {
 				result = KAUTH_RESULT_ALLOW;
-			else {
-				struct rlimit *new_rlimit;
-				u_long which;
+				break;
+			}
 
-				new_rlimit = arg2;
-				which = (u_long)arg3;
+			/*
+			 * suid proc of ours or proc not ours
+			 */
+			if (kauth_cred_getuid(cred) !=
+			    kauth_cred_getuid(p->p_cred) ||
+			    kauth_cred_getuid(cred) !=
+			    kauth_cred_getsvuid(p->p_cred)) {
+				result = KAUTH_RESULT_DENY;
+				break;
+			}
 
-				if (new_rlimit->rlim_max <=
-				    p->p_rlimit[which].rlim_max)
-					result = KAUTH_RESULT_ALLOW;
+			/*
+			 * sgid proc has sgid back to us temporarily
+			 */
+			else if (kauth_cred_getgid(p->p_cred) !=
+			    kauth_cred_getsvgid(p->p_cred)) {
+				result = KAUTH_RESULT_DENY;
+				break;
 			}
+
+			/*
+			 * our rgid must be in target's group list (ie,
+			 * sub-processes started by a sgid process)
+			 */
+			else {
+				int ismember = 0;
+
+				if (kauth_cred_ismember_gid(cred,
+				    kauth_cred_getgid(p->p_cred),
+				    &ismember) != 0 || !ismember) {
+					result = KAUTH_RESULT_DENY;
+					break;
+				}
+			}
+
+			new_rlimit = arg2;
+			which = (u_long)arg3;
+
+			if (new_rlimit->rlim_max <=
+			    p->p_rlimit[which].rlim_max)
+				result = KAUTH_RESULT_ALLOW;
 			break;
+			}
 
 		default:
 			result = KAUTH_RESULT_DEFER;
@@ -286,6 +368,39 @@ secmodel_bsd44_suser_process_cb(kauth_cr
 			result = KAUTH_RESULT_ALLOW;
 		break;
 
+	case KAUTH_PROCESS_STOPFLAG:
+		result = KAUTH_RESULT_ALLOW;
+
+		if (isroot)
+			break;
+
+		/*
+		 * suid proc of ours or proc not ours
+		 */
+		if (kauth_cred_getuid(cred) != kauth_cred_getuid(p->p_cred) ||
+		    kauth_cred_getuid(cred) != kauth_cred_getsvuid(p->p_cred))
+			result = KAUTH_RESULT_DENY;
+
+		/*
+		 * sgid proc has sgid back to us temporarily
+		 */
+		else if (kauth_cred_getgid(p->p_cred) != kauth_cred_getsvgid(p->p_cred))
+			result = KAUTH_RESULT_DENY;
+
+		/*
+		 * our rgid must be in target's group list (ie,
+		 * sub-processes started by a sgid process)
+		 */
+		else {
+			int ismember = 0;
+
+			if (kauth_cred_ismember_gid(cred,
+			    kauth_cred_getgid(p->p_cred), &ismember) != 0 ||
+			    !ismember)
+				result = KAUTH_RESULT_DENY;
+		}
+		break;
+
 	default:
 		result = KAUTH_RESULT_DEFER;
 		break;
Index: kern/kern_resource.c
===================================================================
RCS file: /usr/cvs/src/sys/kern/kern_resource.c,v
retrieving revision 1.110
diff -u -p -r1.110 kern_resource.c
--- kern/kern_resource.c	7 Dec 2006 20:04:31 -0000	1.110
+++ kern/kern_resource.c	13 Dec 2006 04:04:49 -0000
@@ -197,18 +197,13 @@ donice(struct lwp *l, struct proc *chgp,
 	kauth_cred_t cred = l->l_cred;
 	int s;
 
-	if (kauth_cred_geteuid(cred) && kauth_cred_getuid(cred) &&
-	    kauth_cred_geteuid(cred) != kauth_cred_geteuid(chgp->p_cred) &&
-	    kauth_cred_getuid(cred) != kauth_cred_geteuid(chgp->p_cred))
-		return (EPERM);
 	if (n > PRIO_MAX)
 		n = PRIO_MAX;
 	if (n < PRIO_MIN)
 		n = PRIO_MIN;
 	n += NZERO;
-	if (n < chgp->p_nice && kauth_authorize_process(cred,
-	    KAUTH_PROCESS_RESOURCE, chgp, (void *)KAUTH_REQ_PROCESS_RESOURCE_NICE,
-	    (void *)(u_long)n, NULL))
+	if (kauth_authorize_process(cred, KAUTH_PROCESS_RESOURCE, chgp,
+	    (void *)KAUTH_REQ_PROCESS_RESOURCE_NICE, KAUTH_ARG(n), NULL))
 		return (EACCES);
 	chgp->p_nice = n;
 	SCHED_LOCK(s);
@@ -261,10 +256,10 @@ dosetrlimit(struct lwp *l, struct proc *
 		 */
 		return (EINVAL);
 	}
-	if (limp->rlim_max > alimp->rlim_max && (error =
-	    kauth_authorize_process(l->l_cred, KAUTH_PROCESS_RESOURCE,
-	    p, (void *)KAUTH_REQ_PROCESS_RESOURCE_RLIMIT, limp,
-	    (void *)(u_long)which)))
+	error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_RESOURCE,
+	    p, KAUTH_ARG(KAUTH_REQ_PROCESS_RESOURCE_RLIMIT), limp,
+	    KAUTH_ARG(which));
+	if (error)
 			return (error);
 
 	if (p->p_limit->p_refcnt > 1 &&
@@ -573,39 +568,6 @@ sysctl_proc_findproc(struct lwp *l, stru
 		ptmp = l->l_proc;
 	else if ((ptmp = pfind(pid)) == NULL)
 		error = ESRCH;
-	else {
-		boolean_t isroot = kauth_authorize_generic(l->l_cred,
-		    KAUTH_GENERIC_ISSUSER, NULL) == 0;
-		/*
-		 * suid proc of ours or proc not ours
-		 */
-		if (kauth_cred_getuid(l->l_cred) !=
-		    kauth_cred_getuid(ptmp->p_cred) ||
-		    kauth_cred_getuid(l->l_cred) !=
-		    kauth_cred_getsvuid(ptmp->p_cred))
-			error = isroot ? 0 : EPERM;
-
-		/*
-		 * sgid proc has sgid back to us temporarily
-		 */
-		else if (kauth_cred_getgid(ptmp->p_cred) !=
-		    kauth_cred_getsvgid(ptmp->p_cred))
-			error = isroot ? 0 : EPERM;
-
-		/*
-		 * our rgid must be in target's group list (ie,
-		 * sub-processes started by a sgid process)
-		 */
-		else {
-			int ismember = 0;
-
-			if (kauth_cred_ismember_gid(l->l_cred,
-			    kauth_cred_getgid(ptmp->p_cred), &ismember) != 0 ||
-			    !ismember) {
-				error = isroot ? 0 : EPERM;
-			}
-		}
-	}
 
 	*p2 = ptmp;
 	return (error);
@@ -641,6 +603,12 @@ sysctl_proc_corename(SYSCTLFN_ARGS)
 	if (error)
 		return (error);
 
+	/* XXX this should be in p_find() */
+	error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
+	    ptmp, NULL, NULL, NULL);
+	if (error)
+		return (error);
+
 	cname = PNBUF_GET();
 	/*
 	 * let them modify a temporary copy of the core name
@@ -659,9 +627,10 @@ sysctl_proc_corename(SYSCTLFN_ARGS)
 		goto done;
 	}
 
-	if (kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CORENAME,
-	    ptmp, NULL, NULL, NULL) != 0)
-		return (EPERM);
+	error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CORENAME,
+	    ptmp, cname, NULL, NULL);
+	if (error)
+		return (error);
 
 	/*
 	 * no error yet and cname now has the new core name in it.
@@ -722,6 +691,12 @@ sysctl_proc_stop(SYSCTLFN_ARGS)
 	if (error)
 		return (error);
 
+	/* XXX this should be in p_find() */
+	error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
+	    ptmp, NULL, NULL, NULL);
+	if (error)
+		return (error);
+
 	switch (rnode->sysctl_num) {
 	case PROC_PID_STOPFORK:
 		f = P_STOPFORK;
@@ -743,6 +718,11 @@ sysctl_proc_stop(SYSCTLFN_ARGS)
 	if (error || newp == NULL)
 		return (error);
 
+	error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_STOPFLAG,
+	    ptmp, KAUTH_ARG(f), NULL, NULL);
+	if (error)
+		return (error);
+
 	if (i)
 		ptmp->p_flag |= f;
 	else
@@ -782,6 +762,12 @@ sysctl_proc_plimit(SYSCTLFN_ARGS)
 	if (error)
 		return (error);
 
+	/* XXX this should be in p_find() */
+	error = kauth_authorize_process(l->l_cred, KAUTH_PROCESS_CANSEE,
+	    ptmp, NULL, NULL, NULL);
+	if (error)
+		return (error);
+
 	node = *rnode;
 	memcpy(&alim, &ptmp->p_rlimit[limitno], sizeof(alim));
 	if (which == PROC_PID_LIMIT_TYPE_HARD)

--------------040303080105050106020809--