git: dea055a0e86f - main - ptrace: Fix validation of PT_SC_REMOTE arguments
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 20 May 2026 19:35:47 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=dea055a0e86fc279a51439b695461b3eda94ad0b
commit dea055a0e86fc279a51439b695461b3eda94ad0b
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-05-12 17:32:17 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-05-20 19:34:50 +0000
ptrace: Fix validation of PT_SC_REMOTE arguments
- Fix an off-by-one in the system call number check. A value of
SYS_MAXSYSCALL was permitted.
- Validate the system call number after we've dealt with
syscall(2)/__syscall(2), since they pass the syscall number as an
argument.
- When the syscall number is for syscall(2) or __syscall(2), we must
make sure that nargs > 0 to avoid an underflow when shifting arguments
down.
Add regression tests.
Approved by: so
Security: FreeBSD-SA-26:21.ptrace
Security: CVE-2026-45253
Fixes: 140ceb5d956b ("ptrace(2): add PT_SC_REMOTE remote syscall request")
Reported by: Yuxiang Yang, Yizhou Zhao, Ao Wang, Xuewei Feng, Qi Li, and Ke Xu from Tsinghua University using GLM-5.1 from Z.ai
Reviewed by: kib, emaste
Differential Revision: https://reviews.freebsd.org/D56978
---
sys/kern/kern_sig.c | 17 +++++----
tests/sys/kern/ptrace_test.c | 85 ++++++++++++++++++++++++++++++++++----------
2 files changed, 76 insertions(+), 26 deletions(-)
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index a55f3c761449..9be7c82ee98b 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2679,23 +2679,26 @@ ptrace_syscallreq(struct thread *td, struct proc *p,
struct sysentvec *sv;
struct sysent *se;
register_t rv_saved[2];
+ unsigned int sc;
int error, nerror;
- int sc;
bool audited, sy_thr_static;
- sv = p->p_sysent;
- if (sv->sv_table == NULL || sv->sv_size < tsr->ts_sa.code) {
- tsr->ts_ret.sr_error = ENOSYS;
- return;
- }
-
sc = tsr->ts_sa.code;
if (sc == SYS_syscall || sc == SYS___syscall) {
+ if (tsr->ts_nargs == 0) {
+ tsr->ts_ret.sr_error = EINVAL;
+ return;
+ }
sc = tsr->ts_sa.args[0];
memmove(&tsr->ts_sa.args[0], &tsr->ts_sa.args[1],
sizeof(register_t) * (tsr->ts_nargs - 1));
}
+ sv = p->p_sysent;
+ if (sv->sv_table == NULL || sc >= sv->sv_size) {
+ tsr->ts_ret.sr_error = ENOSYS;
+ return;
+ }
tsr->ts_sa.callp = se = &sv->sv_table[sc];
VM_CNT_INC(v_syscall);
diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c
index fee0bd2ffa38..c1a5d226e990 100644
--- a/tests/sys/kern/ptrace_test.c
+++ b/tests/sys/kern/ptrace_test.c
@@ -4362,6 +4362,25 @@ ATF_TC_BODY(ptrace__procdesc_reparent_wait_child, tc)
REQUIRE_EQ(close(pd), 0);
}
+static void
+pt_sc_remote(pid_t pid, struct ptrace_sc_remote *pscr, int error,
+ syscallarg_t ret)
+{
+ pid_t wpid;
+ int status;
+
+ ATF_REQUIRE(ptrace(PT_SC_REMOTE, pid, (caddr_t)pscr, sizeof(*pscr)) !=
+ -1);
+ ATF_REQUIRE_EQ(pscr->pscr_ret.sr_error, error);
+ if (error == 0)
+ ATF_REQUIRE_EQ(pscr->pscr_ret.sr_retval[0], ret);
+
+ wpid = waitpid(pid, &status, 0);
+ REQUIRE_EQ(wpid, pid);
+ ATF_REQUIRE(WIFSTOPPED(status));
+ REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
+}
+
/*
* Try using PT_SC_REMOTE to get the PID of a traced child process.
*/
@@ -4386,35 +4405,62 @@ ATF_TC_BODY(ptrace__PT_SC_REMOTE_getpid, tc)
pscr.pscr_syscall = SYS_getpid;
pscr.pscr_nargs = 0;
pscr.pscr_args = NULL;
- ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
- -1);
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
- "remote getpid failed with error %d", pscr.pscr_ret.sr_error);
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == fpid,
- "unexpected return value %jd instead of %d",
- (intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
-
- wpid = waitpid(fpid, &status, 0);
- REQUIRE_EQ(wpid, fpid);
- ATF_REQUIRE(WIFSTOPPED(status));
- REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
+ pt_sc_remote(fpid, &pscr, 0, fpid);
pscr.pscr_syscall = SYS_getppid;
pscr.pscr_nargs = 0;
pscr.pscr_args = NULL;
- ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
- -1);
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
- "remote getppid failed with error %d", pscr.pscr_ret.sr_error);
- ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == getpid(),
- "unexpected return value %jd instead of %d",
- (intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
+ pt_sc_remote(fpid, &pscr, 0, getpid());
+
+ ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
+}
+
+ATF_TC_WITHOUT_HEAD(ptrace__PT_SC_REMOTE_syscall_validation);
+ATF_TC_BODY(ptrace__PT_SC_REMOTE_syscall_validation, tc)
+{
+ struct ptrace_sc_remote pscr;
+ quad_t code;
+ int status;
+ pid_t fpid, wpid;
+
+ code = SYS_MAXSYSCALL;
+
+ ATF_REQUIRE((fpid = fork()) != -1);
+ if (fpid == 0) {
+ trace_me();
+ exit(0);
+ }
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
+ pscr.pscr_syscall = SYS_MAXSYSCALL;
+ pscr.pscr_nargs = 0;
+ pscr.pscr_args = NULL;
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
+
+ pscr.pscr_syscall = SYS_syscall;
+ pscr.pscr_nargs = 0;
+ pscr.pscr_args = NULL;
+ pt_sc_remote(fpid, &pscr, EINVAL, 0);
+
+ pscr.pscr_syscall = SYS_syscall;
+ pscr.pscr_nargs = 1;
+ pscr.pscr_args = (syscallarg_t *)&code;
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
+
+ pscr.pscr_syscall = SYS___syscall;
+ pscr.pscr_nargs = 0;
+ pscr.pscr_args = NULL;
+ pt_sc_remote(fpid, &pscr, EINVAL, 0);
+
+ pscr.pscr_syscall = SYS___syscall;
+ pscr.pscr_nargs = 1;
+ pscr.pscr_args = (syscallarg_t *)&code;
+ pt_sc_remote(fpid, &pscr, ENOSYS, 0);
+
ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
}
@@ -4657,6 +4703,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, ptrace__procdesc_wait_child);
ATF_TP_ADD_TC(tp, ptrace__procdesc_reparent_wait_child);
ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_getpid);
+ ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_syscall_validation);
ATF_TP_ADD_TC(tp, ptrace__reap_kill_stopped);
ATF_TP_ADD_TC(tp, ptrace__PT_ATTACH_no_EINTR);
ATF_TP_ADD_TC(tp, ptrace__PT_DETACH_continued);