From 2fb7474eacb70b26dcecb69cb26ffa7a9e7034cc Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Fri, 24 Jun 2011 21:41:39 +0200
Subject: [PATCH 09/18] kernel: Abstract out the ptrace permission checks.

In-collaboration-with: aggelos
---
 sys/kern/sys_process.c |   84 +++++++++++++++++++++++-------------------------
 sys/sys/proc.h         |    1 +
 2 files changed, 41 insertions(+), 44 deletions(-)

diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 2b78add..dc7dc6b 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -29,7 +29,6 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/sys_process.c,v 1.51.2.6 2003/01/08 03:06:45 kan Exp $
- * $DragonFly: src/sys/kern/sys_process.c,v 1.30 2007/02/19 01:14:23 corecode Exp $
  */
 
 #include <sys/param.h>
@@ -272,42 +271,20 @@ sys_ptrace(struct ptrace_args *uap)
 }
 
 int
-kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
-	    int data, int *res)
+p_canptrace(struct proc *curp, int req, struct proc *p)
 {
-	struct proc *p, *pp;
-	struct lwp *lp;
-	struct iovec iov;
-	struct uio uio;
-	struct ptrace_io_desc *piod;
+	struct proc *pp;
 	int error = 0;
-	int write, tmp;
-	int t;
 
-	lwkt_gettoken(&proc_token);
+	KKASSERT(PHELD(p));
 
-	write = 0;
-	if (req == PT_TRACE_ME) {
-		p = curp;
-		PHOLD(p);
-	} else {
-		if ((p = pfind(pid)) == NULL) {
-			lwkt_reltoken(&proc_token);
-			return ESRCH;
-		}
-	}
-	if (!PRISON_CHECK(curp->p_ucred, p->p_ucred)) {
-		PRELE(p);
-		lwkt_reltoken(&proc_token);
+	if (!PRISON_CHECK(curp->p_ucred, p->p_ucred))
 		return (ESRCH);
-	}
 
 	lwkt_gettoken(&p->p_token);
 	/* Can't trace a process that's currently exec'ing. */
 	if ((p->p_flags & P_INEXEC) != 0) {
 		lwkt_reltoken(&p->p_token);
-		PRELE(p);
-		lwkt_reltoken(&proc_token);
 		return EAGAIN;
 	}
 
@@ -323,16 +300,12 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 		/* Self */
 		if (p->p_pid == curp->p_pid) {
 			lwkt_reltoken(&p->p_token);
-			PRELE(p);
-			lwkt_reltoken(&proc_token);
 			return EINVAL;
 		}
 
 		/* Already traced */
 		if (p->p_flags & P_TRACED) {
 			lwkt_reltoken(&p->p_token);
-			PRELE(p);
-			lwkt_reltoken(&proc_token);
 			return EBUSY;
 		}
 
@@ -340,8 +313,6 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 			for (pp = curp->p_pptr; pp != NULL; pp = pp->p_pptr)
 				if (pp == p) {
 					lwkt_reltoken(&p->p_token);
-					PRELE(p);
-					lwkt_reltoken(&proc_token);
 					return (EINVAL);
 				}
 
@@ -350,8 +321,6 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 		     (p->p_flags & P_SUGID)) {
 			if ((error = priv_check_cred(curp->p_ucred, PRIV_ROOT, 0)) != 0) {
 				lwkt_reltoken(&p->p_token);
-				PRELE(p);
-				lwkt_reltoken(&proc_token);
 				return error;
 			}
 		}
@@ -359,8 +328,6 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 		/* can't trace init when securelevel > 0 */
 		if (securelevel > 0 && p->p_pid == 1) {
 			lwkt_reltoken(&p->p_token);
-			PRELE(p);
-			lwkt_reltoken(&proc_token);
 			return EPERM;
 		}
 
@@ -397,16 +364,12 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 		/* not being traced... */
 		if ((p->p_flags & P_TRACED) == 0) {
 			lwkt_reltoken(&p->p_token);
-			PRELE(p);
-			lwkt_reltoken(&proc_token);
 			return EPERM;
 		}
 
 		/* not being traced by YOU */
 		if (p->p_pptr != curp) {
 			lwkt_reltoken(&p->p_token);
-			PRELE(p);
-			lwkt_reltoken(&proc_token);
 			return EBUSY;
 		}
 
@@ -414,8 +377,6 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 		if (p->p_stat != SSTOP ||
 		    (p->p_flags & P_WAITED) == 0) {
 			lwkt_reltoken(&p->p_token);
-			PRELE(p);
-			lwkt_reltoken(&proc_token);
 			return EBUSY;
 		}
 
@@ -424,9 +385,44 @@ kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
 
 	default:
 		lwkt_reltoken(&p->p_token);
+		return EINVAL;
+	}
+	lwkt_reltoken(&p->p_token);
+	return(0);
+}
+
+int
+kern_ptrace(struct proc *curp, int req, pid_t pid, void *addr,
+	    int data, int *res)
+{
+	struct proc *p;
+	struct lwp *lp;
+	struct iovec iov;
+	struct uio uio;
+	struct ptrace_io_desc *piod;
+	int error = 0;
+	int write, tmp;
+	int t;
+
+	lwkt_gettoken(&proc_token);
+
+	write = 0;
+	if (req == PT_TRACE_ME) {
+		p = curp;
+		PHOLD(p);
+	} else {
+		if ((p = pfind(pid)) == NULL) {
+			lwkt_reltoken(&proc_token);
+			return ESRCH;
+		}
+	}
+
+	lwkt_gettoken(&p->p_token);
+
+	if ((error = p_canptrace(curp, req, p)) != 0) {
 		PRELE(p);
 		lwkt_reltoken(&proc_token);
-		return EINVAL;
+		return (error);
 	}
 
 	/* XXX lwp */
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index e0fc90a..85b6dd6 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -559,6 +559,7 @@ void	prele (struct proc *);
 void	pstall (struct proc *, const char *, int);
 
 u_int32_t	procrunnable (void);
+int	p_canptrace(struct proc *curp, int req, struct proc *p);
 
 #endif	/* _KERNEL */
 
-- 
1.7.0.5

