Date: Tue, 28 Apr 2020 15:44:39 +0000 (UTC) From: John Baldwin <jhb@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r360439 - in stable/12: lib/libc/sys sys/kern sys/sys tests/sys/kern Message-ID: <202004281544.03SFiduq000352@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jhb Date: Tue Apr 28 15:44:39 2020 New Revision: 360439 URL: https://svnweb.freebsd.org/changeset/base/360439 Log: MFC 350017: 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]. Modified: stable/12/lib/libc/sys/ptrace.2 stable/12/sys/kern/sys_process.c stable/12/sys/sys/ptrace.h stable/12/tests/sys/kern/ptrace_test.c Directory Properties: stable/12/ (props changed) Modified: stable/12/lib/libc/sys/ptrace.2 ============================================================================== --- stable/12/lib/libc/sys/ptrace.2 Tue Apr 28 15:02:44 2020 (r360438) +++ stable/12/lib/libc/sys/ptrace.2 Tue Apr 28 15:44:39 2020 (r360439) @@ -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: stable/12/sys/kern/sys_process.c ============================================================================== --- stable/12/sys/kern/sys_process.c Tue Apr 28 15:02:44 2020 (r360438) +++ stable/12/sys/kern/sys_process.c Tue Apr 28 15:44:39 2020 (r360439) @@ -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; @@ -517,6 +522,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 */ /* @@ -579,6 +595,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; @@ -597,6 +614,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); @@ -667,6 +685,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); @@ -718,6 +740,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; @@ -725,7 +748,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; @@ -1047,6 +1074,38 @@ kern_ptrace(struct thread *td, int req, pid_t pid, voi 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: case PT_TO_SCE: @@ -1332,7 +1391,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: stable/12/sys/sys/ptrace.h ============================================================================== --- stable/12/sys/sys/ptrace.h Tue Apr 28 15:02:44 2020 (r360438) +++ stable/12/sys/sys/ptrace.h Tue Apr 28 15:44:39 2020 (r360439) @@ -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: stable/12/tests/sys/kern/ptrace_test.c ============================================================================== --- stable/12/tests/sys/kern/ptrace_test.c Tue Apr 28 15:02:44 2020 (r360438) +++ stable/12/tests/sys/kern/ptrace_test.c Tue Apr 28 15:44:39 2020 (r360439) @@ -3927,12 +3927,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; @@ -3941,6 +3942,7 @@ ATF_TC_BODY(ptrace__syscall_args, tc) if (fpid == 0) { trace_me(); kill(getpid(), 0); + close(3); exit(1); } @@ -3952,9 +3954,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(). @@ -3971,6 +3973,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); @@ -3987,6 +4008,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,
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202004281544.03SFiduq000352>