Page MenuHomeFreeBSD

D58247.id182031.diff
No OneTemporary

D58247.id182031.diff

diff --git a/lib/libsys/ptrace.2 b/lib/libsys/ptrace.2
--- a/lib/libsys/ptrace.2
+++ b/lib/libsys/ptrace.2
@@ -851,6 +851,24 @@
.Xr sigreturn 2
.Pc .
.El
+.It Dv PT_SET_SC_RET
+Set the current system call return values.
+This request is only valid for threads stopped in a syscall
+entry (the
+.Dv PL_FLAG_SCE
+state).
+The
+.Fa addr
+argument specifies a pointer to a
+.Vt "struct ptrace_sc_ret" ,
+the
+.Fa data
+argument is set to the size of the structure.
+.Pp
+The current system call handler is not executed.
+After the thread is resumed, it is returned to userspace.
+with the machine state set as if the handler results were according
+to the passed structure content.
.It Dv PT_FOLLOW_FORK
This request controls tracing for new child processes of a traced process.
If
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1005,6 +1005,16 @@
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,12 @@
case PT_GET_SC_ARGS:
case PT_GET_SC_RET:
break;
+ case PT_SET_SC_RET:
+ error = copyin(uap->addr, &r32.psr, MIN(uap->data,
+ 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
--- a/sys/kern/subr_syscall.c
+++ b/sys/kern/subr_syscall.c
@@ -66,10 +66,11 @@
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 @@
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.
@@ -201,7 +205,7 @@
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
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -752,6 +752,9 @@
case PT_GET_SC_ARGS:
case PT_GET_SC_RET:
break;
+ case PT_SET_SC_RET:
+ error = copyin(uap->addr, &r.psr, sizeof(r.psr));
+ break;
case PT_GETREGS:
bzero(&r.reg, sizeof(r.reg));
break;
@@ -1340,6 +1343,24 @@
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
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -531,6 +531,7 @@
#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
--- 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 @@
};
#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;

File Metadata

Mime Type
text/plain
Expires
Wed, Sep 2, 2:54 PM (11 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37976974
Default Alt Text
D58247.id182031.diff (4 KB)

Event Timeline