git: 03c5b4d8768b - stable/15 - ptrace(2): PT_SET_SC_RET request

Konstantin Belousov <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a66a68c.308d4.13c2300e__18666.8584284902$1785112419$gmane$org@gitrepo.freebsd.org>
The branch stable/15 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=03c5b4d8768bac1febafdbfaa6d43aab2f3c5ac9

commit 03c5b4d8768bac1febafdbfaa6d43aab2f3c5ac9
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-07-15 02:23:17 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2026-07-27 00:28:41 +0000

    ptrace(2): PT_SET_SC_RET request
    
    (cherry picked from commit fd5faa5629aed98f4daee84063da3494c4d1eee9)
---
 sys/compat/freebsd32/freebsd32_misc.c | 19 +++++++++++++++++++
 sys/kern/subr_syscall.c               | 12 ++++++++----
 sys/kern/sys_process.c                | 24 ++++++++++++++++++++++++
 sys/sys/proc.h                        |  1 +
 sys/sys/ptrace.h                      |  3 ++-
 5 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index e4a4f256feb4..e07000015d54 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1005,6 +1005,16 @@ ptrace_sc_ret_to32(const struct ptrace_sc_ret *psr,
 	psr32->sr_error = psr->sr_error;
 }
 
+static void
+ptrace_sc_ret32_to_ret(const struct ptrace_sc_ret32 *psr32,
+    struct ptrace_sc_ret *psr)
+{
+	bzero(psr, sizeof(*psr));
+	psr->sr_retval[0] = psr32->sr_retval[0];
+	psr->sr_retval[1] = psr32->sr_retval[1];
+	psr->sr_error = psr32->sr_error;
+}
+
 int
 freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
 {
@@ -1051,6 +1061,15 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
 	case PT_GET_SC_ARGS:
 	case PT_GET_SC_RET:
 		break;
+	case PT_SET_SC_RET:
+		if (uap->data != sizeof(r32.psr)) {
+			error = EINVAL;
+		} else {
+			error = copyin(uap->addr, &r32.psr, sizeof(r32.psr));
+			if (error == 0)
+				ptrace_sc_ret32_to_ret(&r32.psr, &r.psr);
+		}
+		break;
 	case PT_LWPINFO:
 		if (uap->data > sizeof(r32.pl))
 			return (EINVAL);
diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c
index 48896529f685..64fc24d149a6 100644
--- a/sys/kern/subr_syscall.c
+++ b/sys/kern/subr_syscall.c
@@ -66,10 +66,11 @@ syscallenter(struct thread *td)
 	if (__predict_false(td->td_cowgen != atomic_load_int(&p->p_cowgen)))
 		thread_cow_update(td);
 	traced = (p->p_flag & P_TRACED) != 0;
-	if (__predict_false(traced || td->td_dbgflags & TDB_USERWR)) {
+	if (__predict_false(traced || (td->td_dbgflags & (TDB_USERWR |
+	    TDB_SET_SC_RET)) != 0)) {
 		PROC_LOCK(p);
 		MPASS((td->td_dbgflags & TDB_BOUNDARY) == 0);
-		td->td_dbgflags &= ~TDB_USERWR;
+		td->td_dbgflags &= ~(TDB_USERWR | TDB_SET_SC_RET);
 		if (traced)
 			td->td_dbgflags |= TDB_SCE;
 		PROC_UNLOCK(p);
@@ -97,7 +98,10 @@ syscallenter(struct thread *td)
 			ptracestop((td), SIGTRAP, NULL);
 		PROC_UNLOCK(p);
 
-		if ((td->td_dbgflags & TDB_USERWR) != 0) {
+		if ((td->td_dbgflags & TDB_SET_SC_RET) != 0) {
+			error = td->td_errno;
+			goto retval;
+		} else if ((td->td_dbgflags & TDB_USERWR) != 0) {
 			/*
 			 * Reread syscall number and arguments if debugger
 			 * modified registers or memory.
@@ -205,7 +209,7 @@ syscallenter(struct thread *td)
 	    td->td_retval[1]);
 	if (__predict_false(traced)) {
 		PROC_LOCK(p);
-		td->td_dbgflags &= ~(TDB_SCE | TDB_BOUNDARY);
+		td->td_dbgflags &= ~(TDB_SCE | TDB_BOUNDARY | TDB_SET_SC_RET);
 		PROC_UNLOCK(p);
 	}
 	(p->p_sysent->sv_set_syscall_retval)(td, error);
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 023d61d4346c..631b142d366a 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -719,6 +719,12 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
 	case PT_GET_SC_ARGS:
 	case PT_GET_SC_RET:
 		break;
+	case PT_SET_SC_RET:
+		if (uap->data != sizeof(r.psr))
+			error = EINVAL;
+		else
+			error = copyin(uap->addr, &r.psr, sizeof(r.psr));
+		break;
 	case PT_GETREGS:
 		bzero(&r.reg, sizeof(r.reg));
 		break;
@@ -1307,6 +1313,24 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
 		    psr->sr_retval[1]);
 		break;
 
+	case PT_SET_SC_RET:
+		if ((td2->td_dbgflags & TDB_SCE) == 0
+#ifdef COMPAT_FREEBSD32
+		    || (wrap32 && !safe)
+#endif
+		    ) {
+			error = EINVAL;
+			break;
+		}
+		psr = addr;
+		td2->td_errno = psr->sr_error;
+		if (td2->td_errno == 0) {
+			td2->td_retval[0] = psr->sr_retval[0];
+			td2->td_retval[1] = psr->sr_retval[1];
+		}
+		td2->td_dbgflags |= TDB_SET_SC_RET;
+		break;
+
 	case PT_STEP:
 	case PT_CONTINUE:
 	case PT_TO_SCE:
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 4e423c3ad0c7..0d354ec93b7f 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -531,6 +531,7 @@ enum {
 #define	TDB_BOUNDARY	0x00008000 /* ptracestop() at boundary */
 #define	TDB_COREDUMPREQ	0x00010000 /* Coredump request */
 #define	TDB_SCREMOTEREQ	0x00020000 /* Remote syscall request */
+#define	TDB_SET_SC_RET	0x00040000 /* PT_SET_SC_RET applied */
 
 /*
  * "Private" flags kept in td_pflags:
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index 2ef52b22044c..2aa82ce07a1d 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -85,6 +85,7 @@
 #define	PT_GETREGSET	42	/* Get a target register set */
 #define	PT_SETREGSET	43	/* Set a target register set */
 #define	PT_SC_REMOTE	44	/* Execute a syscall */
+#define	PT_SET_SC_RET	45	/* Set (fake) syscall results */
 
 #define PT_FIRSTMACH    64	/* for machine-specific requests */
 #define	PT_LASTMACH     127
@@ -166,7 +167,7 @@ struct ptrace_lwpinfo32 {
 };
 #endif
 
-/* Argument structure for PT_GET_SC_RET. */
+/* Argument structure for PT_GET_SC_RET and PT_SET_SC_RET. */
 struct ptrace_sc_ret {
 	syscallarg_t	sr_retval[2];	/* Only valid if sr_error == 0. */
 	int		sr_error;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.