git: 4495cd6e7e50 - stable/13 - ptrace: do not allow for parallel ptrace requests

Konstantin Belousov kib at FreeBSD.org
Mon May 10 01:14:54 UTC 2021


The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=4495cd6e7e50e54515cc3d9b9faba7c6fb21042b

commit 4495cd6e7e50e54515cc3d9b9faba7c6fb21042b
Author:     Konstantin Belousov <kib at FreeBSD.org>
AuthorDate: 2021-04-24 11:57:40 +0000
Commit:     Konstantin Belousov <kib at FreeBSD.org>
CommitDate: 2021-05-10 01:02:47 +0000

    ptrace: do not allow for parallel ptrace requests
    
    (cherry picked from commit 9ebf9100bad129a92961572ac862781d6c5681c7)
---
 sys/kern/sys_process.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
 sys/sys/proc.h         |  1 +
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index c93bfe15324c..e89fc6dff7e0 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -604,11 +604,18 @@ proc_set_traced(struct proc *p, bool stop)
 static int
 proc_can_ptrace(struct thread *td, struct proc *p)
 {
+	int error;
+
 	PROC_LOCK_ASSERT(p, MA_OWNED);
 
 	if ((p->p_flag & P_WEXIT) != 0)
 		return (ESRCH);
 
+	if ((error = p_cansee(td, p)) != 0)
+		return (error);
+	if ((error = p_candebug(td, p)) != 0)
+		return (error);
+
 	/* not being traced... */
 	if ((p->p_flag & P_TRACED) == 0)
 		return (EPERM);
@@ -640,10 +647,11 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
 #ifdef COMPAT_FREEBSD32
 	int wrap32 = 0, safe = 0;
 #endif
-	bool proctree_locked;
+	bool proctree_locked, p2_req_set;
 
 	curp = td->td_proc;
 	proctree_locked = false;
+	p2_req_set = false;
 
 	/* Lock proctree before locking the process. */
 	switch (req) {
@@ -782,15 +790,47 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
 
 		/* FALLTHROUGH */
 	default:
+		/*
+		 * Check for ptrace eligibility before waiting for
+		 * holds to drain.
+		 */
 		error = proc_can_ptrace(td, p);
 		if (error != 0)
 			goto fail;
 
+		/*
+		 * Block parallel ptrace requests.  Most important, do
+		 * not allow other thread in debugger to continue the
+		 * debuggee until coredump finished.
+		 */
+		while ((p->p_flag2 & P2_PTRACEREQ) != 0) {
+			if (proctree_locked)
+				sx_xunlock(&proctree_lock);
+			error = msleep(&p->p_flag2, &p->p_mtx, PPAUSE | PCATCH |
+			    (proctree_locked ? PDROP : 0), "pptrace", 0);
+			if (proctree_locked) {
+				sx_xlock(&proctree_lock);
+				PROC_LOCK(p);
+			}
+			if (error == 0 && td2->td_proc != p)
+				error = ESRCH;
+			if (error == 0)
+				error = proc_can_ptrace(td, p);
+			if (error != 0)
+				goto fail;
+		}
+
 		/* Ok */
 		break;
 	}
 
-	/* Keep this process around until we finish this request. */
+	/*
+	 * Keep this process around and request parallel ptrace()
+	 * request to wait until we finish this request.
+	 */
+	MPASS((p->p_flag2 & P2_PTRACEREQ) == 0);
+	p->p_flag2 |= P2_PTRACEREQ;
+	p2_req_set = true;
 	_PHOLD(p);
 
 	/*
@@ -1325,6 +1365,11 @@ out:
 	/* Drop our hold on this process now that the request has completed. */
 	_PRELE(p);
 fail:
+	if (p2_req_set) {
+		if ((p->p_flag2 & P2_PTRACEREQ) != 0)
+			wakeup(&p->p_flag2);
+		p->p_flag2 &= ~P2_PTRACEREQ;
+	}
 	PROC_UNLOCK(p);
 	if (proctree_locked)
 		sx_xunlock(&proctree_lock);
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 9de7be4628dd..0a779820fddc 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -817,6 +817,7 @@ struct proc {
 #define	P2_STKGAP_DISABLE_EXEC	0x00001000	/* Stack gap disabled
 						   after exec */
 #define	P2_ITSTOPPED		0x00002000
+#define	P2_PTRACEREQ		0x00004000	/* Active ptrace req */
 
 /* Flags protected by proctree_lock, kept in p_treeflags. */
 #define	P_TREE_ORPHANED		0x00000001	/* Reparented, on orphan list */


More information about the dev-commits-src-all mailing list