svn commit: r350017 - in head: lib/libc/sys sys/kern sys/sys tests/sys/kern

John Baldwin jhb at FreeBSD.org
Mon Jul 15 21:48:04 UTC 2019


Author: jhb
Date: Mon Jul 15 21:48:02 2019
New Revision: 350017
URL: https://svnweb.freebsd.org/changeset/base/350017

Log:
  Add ptrace op PT_GET_SC_RET.
  
  This ptrace operation returns a structure containing the error and
  return values from the current system call.  It is only valid when a
  thread is stopped during a system call exit (PL_FLAG_SCX is set).
  
  The sr_error member holds the error value from the system call.  Note
  that this error value is the native FreeBSD error value that has _not_
  been translated to an ABI-specific error value similar to the values
  logged to ktrace.
  
  If sr_error is zero, then the return values of the system call will be
  set in sr_retval[0] and sr_retval[1].
  
  Reviewed by:	kib
  MFC after:	1 month
  Sponsored by:	DARPA
  Differential Revision:	https://reviews.freebsd.org/D20901

Modified:
  head/lib/libc/sys/ptrace.2
  head/sys/kern/sys_process.c
  head/sys/sys/ptrace.h
  head/tests/sys/kern/ptrace_test.c

Modified: head/lib/libc/sys/ptrace.2
==============================================================================
--- head/lib/libc/sys/ptrace.2	Mon Jul 15 21:47:40 2019	(r350016)
+++ head/lib/libc/sys/ptrace.2	Mon Jul 15 21:48:02 2019	(r350017)
@@ -2,7 +2,7 @@
 .\"	$NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
 .\"
 .\" This file is in the public domain.
-.Dd June 2, 2018
+.Dd July 15, 2019
 .Dt PTRACE 2
 .Os
 .Sh NAME
@@ -664,6 +664,52 @@ member of the
 but not more than the
 .Fa data
 bytes in total are copied.
+.It Dv PT_GET_SC_RET
+Fetch the system call return values on exit from a syscall.
+This request is only valid for threads stopped in a syscall
+exit (the
+.Dv PL_FLAG_SCX
+state).
+The
+.Fa addr
+argument specifies a pointer to a
+.Vt "struct ptrace_sc_ret" ,
+which is defined as follows:
+.Bd -literal
+struct ptrace_sc_ret {
+	register_t	sr_retval[2];
+	int		sr_error;
+};
+.Ed
+.Pp
+The
+.Fa data
+argument is set to the size of the structure.
+.Pp
+If the system call completed successfully,
+.Va sr_error
+is set to zero and the return values of the system call are saved in
+.Va sr_retval .
+If the system call failed to execute,
+.Va sr_error
+field is set to a positive
+.Xr errno 2
+value.
+If the system call completed in an unusual fashion,
+.Va sr_error
+is set to a negative value:
+.Pp
+.Bl -tag -width Dv EJUSTRETURN -compact
+.It Dv ERESTART
+System call will be restarted.
+.It Dv EJUSTRETURN
+System call completed sucessfully but did not set a return value
+.Po for example,
+.Xr setcontext 2
+and
+.Xr sigreturn 2
+.Pc .
+.El
 .It Dv PT_FOLLOW_FORK
 This request controls tracing for new child processes of a traced process.
 If

Modified: head/sys/kern/sys_process.c
==============================================================================
--- head/sys/kern/sys_process.c	Mon Jul 15 21:47:40 2019	(r350016)
+++ head/sys/kern/sys_process.c	Mon Jul 15 21:48:02 2019	(r350017)
@@ -76,6 +76,11 @@ struct ptrace_io_desc32 {
 	uint32_t	piod_len;
 };
 
+struct ptrace_sc_ret32 {
+	uint32_t	sr_retval[2];
+	int		sr_error;
+};
+
 struct ptrace_vm_entry32 {
 	int		pve_entry;
 	int		pve_timestamp;
@@ -518,6 +523,17 @@ ptrace_lwpinfo_to32(const struct ptrace_lwpinfo *pl,
 	pl32->pl_syscall_code = pl->pl_syscall_code;
 	pl32->pl_syscall_narg = pl->pl_syscall_narg;
 }
+
+static void
+ptrace_sc_ret_to32(const struct ptrace_sc_ret *psr,
+    struct ptrace_sc_ret32 *psr32)
+{
+
+	bzero(psr32, sizeof(*psr32));
+	psr32->sr_retval[0] = psr->sr_retval[0];
+	psr32->sr_retval[1] = psr->sr_retval[1];
+	psr32->sr_error = psr->sr_error;
+}
 #endif /* COMPAT_FREEBSD32 */
 
 /*
@@ -580,6 +596,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
 		struct ptrace_vm_entry32 pve32;
 #endif
 		char args[sizeof(td->td_sa.args)];
+		struct ptrace_sc_ret psr;
 		int ptevents;
 	} r;
 	void *addr;
@@ -598,6 +615,7 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
 	case PT_GET_EVENT_MASK:
 	case PT_LWPINFO:
 	case PT_GET_SC_ARGS:
+	case PT_GET_SC_RET:
 		break;
 	case PT_GETREGS:
 		BZERO(&r.reg, sizeof r.reg);
@@ -668,6 +686,10 @@ sys_ptrace(struct thread *td, struct ptrace_args *uap)
 		error = copyout(r.args, uap->addr, MIN(uap->data,
 		    sizeof(r.args)));
 		break;
+	case PT_GET_SC_RET:
+		error = copyout(&r.psr, uap->addr, MIN(uap->data,
+		    sizeof(r.psr)));
+		break;
 	}
 
 	return (error);
@@ -719,6 +741,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
 	struct thread *td2 = NULL, *td3;
 	struct ptrace_io_desc *piod = NULL;
 	struct ptrace_lwpinfo *pl;
+	struct ptrace_sc_ret *psr;
 	int error, num, tmp;
 	int proctree_locked = 0;
 	lwpid_t tid = 0, *buf;
@@ -726,7 +749,11 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
 	int wrap32 = 0, safe = 0;
 	struct ptrace_io_desc32 *piod32 = NULL;
 	struct ptrace_lwpinfo32 *pl32 = NULL;
-	struct ptrace_lwpinfo plr;
+	struct ptrace_sc_ret32 *psr32 = NULL;
+	union {
+		struct ptrace_lwpinfo pl;
+		struct ptrace_sc_ret psr;
+	} r;
 #endif
 
 	curp = td->td_proc;
@@ -1049,6 +1076,38 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
 			bcopy(td2->td_sa.args, addr, td2->td_sa.narg *
 			    sizeof(register_t));
 		break;
+
+	case PT_GET_SC_RET:
+		if ((td2->td_dbgflags & (TDB_SCX)) == 0
+#ifdef COMPAT_FREEBSD32
+		    || (wrap32 && !safe)
+#endif
+		    ) {
+			error = EINVAL;
+			break;
+		}
+#ifdef COMPAT_FREEBSD32
+		if (wrap32) {
+			psr = &r.psr;
+			psr32 = addr;
+		} else
+#endif
+		psr = addr;
+		bzero(psr, sizeof(*psr));
+		psr->sr_error = td2->td_errno;
+		if (psr->sr_error == 0) {
+			psr->sr_retval[0] = td2->td_retval[0];
+			psr->sr_retval[1] = td2->td_retval[1];
+		}
+#ifdef COMPAT_FREEBSD32
+		if (wrap32)
+			ptrace_sc_ret_to32(psr, psr32);
+#endif
+		CTR4(KTR_PTRACE,
+		    "PT_GET_SC_RET: pid %d error %d retval %#lx,%#lx",
+		    p->p_pid, psr->sr_error, psr->sr_retval[0],
+		    psr->sr_retval[1]);
+		break;
 		
 	case PT_STEP:
 	case PT_CONTINUE:
@@ -1335,7 +1394,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi
 		}
 #ifdef COMPAT_FREEBSD32
 		if (wrap32) {
-			pl = &plr;
+			pl = &r.pl;
 			pl32 = addr;
 		} else
 #endif

Modified: head/sys/sys/ptrace.h
==============================================================================
--- head/sys/sys/ptrace.h	Mon Jul 15 21:47:40 2019	(r350016)
+++ head/sys/sys/ptrace.h	Mon Jul 15 21:48:02 2019	(r350017)
@@ -72,6 +72,7 @@
 #define	PT_SET_EVENT_MASK 26	/* set mask of optional events */
 
 #define	PT_GET_SC_ARGS	27	/* fetch syscall args */
+#define	PT_GET_SC_RET	28	/* fetch syscall results */
 
 #define PT_GETREGS      33	/* get general-purpose registers */
 #define PT_SETREGS      34	/* set general-purpose registers */
@@ -154,6 +155,12 @@ struct ptrace_lwpinfo32 {
 	u_int		pl_syscall_narg;
 };
 #endif
+
+/* Argument structure for PT_GET_SC_RET. */
+struct ptrace_sc_ret {
+	register_t	sr_retval[2];	/* Only valid if sr_error == 0. */
+	int		sr_error;
+};
 
 /* Argument structure for PT_VM_ENTRY. */
 struct ptrace_vm_entry {

Modified: head/tests/sys/kern/ptrace_test.c
==============================================================================
--- head/tests/sys/kern/ptrace_test.c	Mon Jul 15 21:47:40 2019	(r350016)
+++ head/tests/sys/kern/ptrace_test.c	Mon Jul 15 21:48:02 2019	(r350017)
@@ -3905,12 +3905,13 @@ ATF_TC_BODY(ptrace__PT_LWPINFO_stale_siginfo, tc)
 }
 
 /*
- * A simple test of PT_GET_SC_ARGS.
+ * A simple test of PT_GET_SC_ARGS and PT_GET_SC_RET.
  */
 ATF_TC_WITHOUT_HEAD(ptrace__syscall_args);
 ATF_TC_BODY(ptrace__syscall_args, tc)
 {
 	struct ptrace_lwpinfo pl;
+	struct ptrace_sc_ret psr;
 	pid_t fpid, wpid;
 	register_t args[2];
 	int events, status;
@@ -3919,6 +3920,7 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
 	if (fpid == 0) {
 		trace_me();
 		kill(getpid(), 0);
+		close(3);
 		exit(1);
 	}
 
@@ -3930,9 +3932,9 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
 
 	/*
 	 * Continue the process ignoring the signal, but enabling
-	 * syscall entry traps.
+	 * syscall traps.
 	 */
-	ATF_REQUIRE(ptrace(PT_TO_SCE, fpid, (caddr_t)1, 0) == 0);
+	ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0);
 
 	/*
 	 * The next stop should be the syscall entry from getpid().
@@ -3949,6 +3951,25 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
 	ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
 
 	/*
+	 * The next stop should be the syscall exit from getpid().
+	 */
+	wpid = waitpid(fpid, &status, 0);
+	ATF_REQUIRE(wpid == fpid);
+	ATF_REQUIRE(WIFSTOPPED(status));
+	ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+	ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+	ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
+	ATF_REQUIRE(pl.pl_syscall_code == SYS_getpid);
+
+	ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr,
+	    sizeof(psr)) != -1);
+	ATF_REQUIRE(psr.sr_error == 0);
+	ATF_REQUIRE(psr.sr_retval[0] == wpid);
+
+	ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+	/*
 	 * The next stop should be the syscall entry from kill().
 	 */
 	wpid = waitpid(fpid, &status, 0);
@@ -3965,6 +3986,61 @@ ATF_TC_BODY(ptrace__syscall_args, tc)
 	    sizeof(args)) != -1);
 	ATF_REQUIRE(args[0] == wpid);
 	ATF_REQUIRE(args[1] == 0);
+
+	ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+	/*
+	 * The next stop should be the syscall exit from kill().
+	 */
+	wpid = waitpid(fpid, &status, 0);
+	ATF_REQUIRE(wpid == fpid);
+	ATF_REQUIRE(WIFSTOPPED(status));
+	ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+	ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+	ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
+	ATF_REQUIRE(pl.pl_syscall_code == SYS_kill);
+
+	ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr,
+	    sizeof(psr)) != -1);
+	ATF_REQUIRE(psr.sr_error == 0);
+
+	ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+	/*
+	 * The next stop should be the syscall entry from close().
+	 */
+	wpid = waitpid(fpid, &status, 0);
+	ATF_REQUIRE(wpid == fpid);
+	ATF_REQUIRE(WIFSTOPPED(status));
+	ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+	ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+	ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
+	ATF_REQUIRE(pl.pl_syscall_code == SYS_close);
+	ATF_REQUIRE(pl.pl_syscall_narg == 1);
+
+	ATF_REQUIRE(ptrace(PT_GET_SC_ARGS, wpid, (caddr_t)args,
+	    sizeof(args)) != -1);
+	ATF_REQUIRE(args[0] == 3);
+
+	ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+	/*
+	 * The next stop should be the syscall exit from close().
+	 */
+	wpid = waitpid(fpid, &status, 0);
+	ATF_REQUIRE(wpid == fpid);
+	ATF_REQUIRE(WIFSTOPPED(status));
+	ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+	ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+	ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
+	ATF_REQUIRE(pl.pl_syscall_code == SYS_close);
+
+	ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr,
+	    sizeof(psr)) != -1);
+	ATF_REQUIRE(psr.sr_error == EBADF);
 
 	/* Disable syscall tracing and continue the child to let it exit. */
 	ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,


More information about the svn-src-all mailing list