Module Name: src Committed By: christos Date: Tue Oct 20 20:28:55 UTC 2020
Modified Files: src/sys/kern: sys_process_lwpstatus.c sys_ptrace_common.c src/sys/sys: ptrace.h Log Message: Basic register read/write functionality and lwp setting are always provided by the kernel because they are needed by multiple things (ptrace/procfs/coredump), so move them to sys_process_lwpstatus (this file should be renamed to sys_process_common.c?) To generate a diff of this commit: cvs rdiff -u -r1.1 -r1.2 src/sys/kern/sys_process_lwpstatus.c cvs rdiff -u -r1.86 -r1.87 src/sys/kern/sys_ptrace_common.c cvs rdiff -u -r1.71 -r1.72 src/sys/sys/ptrace.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/sys_process_lwpstatus.c diff -u src/sys/kern/sys_process_lwpstatus.c:1.1 src/sys/kern/sys_process_lwpstatus.c:1.2 --- src/sys/kern/sys_process_lwpstatus.c:1.1 Fri Jan 3 22:46:19 2020 +++ src/sys/kern/sys_process_lwpstatus.c Tue Oct 20 16:28:55 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_process_lwpstatus.c,v 1.1 2020/01/04 03:46:19 kamil Exp $ */ +/* $NetBSD: sys_process_lwpstatus.c,v 1.2 2020/10/20 20:28:55 christos Exp $ */ /*- * Copyright (c) 2019 The NetBSD Foundation, Inc. @@ -27,7 +27,19 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_process_lwpstatus.c,v 1.1 2020/01/04 03:46:19 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_process_lwpstatus.c,v 1.2 2020/10/20 20:28:55 christos Exp $"); + +#ifdef _KERNEL_OPT +#include "opt_ptrace.h" +#include "opt_ktrace.h" +#include "opt_pax.h" +#include "opt_compat_netbsd32.h" +#endif + +#if defined(__HAVE_COMPAT_NETBSD32) && !defined(COMPAT_NETBSD32) \ + && !defined(_RUMPKERNEL) +#define COMPAT_NETBSD32 +#endif #include <sys/param.h> #include <sys/systm.h> @@ -35,6 +47,9 @@ __KERNEL_RCSID(0, "$NetBSD: sys_process_ #include <sys/lwp.h> #include <sys/ptrace.h> +#ifndef PTRACE_REGS_ALIGN +#define PTRACE_REGS_ALIGN /* nothing */ +#endif void ptrace_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls) @@ -67,3 +82,203 @@ process_read_lwpstatus(struct lwp *l, st ptrace_read_lwpstatus(l, pls); } + +int +ptrace_update_lwp(struct proc *t, struct lwp **lt, lwpid_t lid) +{ + if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1) + return 0; + + mutex_enter(t->p_lock); + lwp_delref2(*lt); + + *lt = lwp_find(t, lid); + if (*lt == NULL) { + mutex_exit(t->p_lock); + return ESRCH; + } + + if ((*lt)->l_flag & LW_SYSTEM) { + mutex_exit(t->p_lock); + *lt = NULL; + return EINVAL; + } + + lwp_addref(*lt); + mutex_exit(t->p_lock); + + return 0; +} + +int +process_validfpregs(struct lwp *l) +{ + +#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) + return (l->l_flag & LW_SYSTEM) == 0; +#else + return 0; +#endif +} + +int +process_validregs(struct lwp *l) +{ + +#if defined(PT_SETREGS) || defined(PT_GETREGS) + return (l->l_flag & LW_SYSTEM) == 0; +#else + return 0; +#endif +} + +int +process_validdbregs(struct lwp *l) +{ + +#if defined(PT_SETDBREGS) || defined(PT_GETDBREGS) + return (l->l_flag & LW_SYSTEM) == 0; +#else + return 0; +#endif +} + +#ifdef PT_REGISTERS +static int +proc_regio(struct lwp *l, struct uio *uio, size_t ks, ptrace_regrfunc_t r, + ptrace_regwfunc_t w) +{ + char buf[1024] PTRACE_REGS_ALIGN; + int error; + char *kv; + size_t kl; + + if (ks > sizeof(buf)) + return E2BIG; + + if (uio->uio_offset < 0 || uio->uio_offset > (off_t)ks) + return EINVAL; + + kv = buf + uio->uio_offset; + kl = ks - uio->uio_offset; + + if (kl > uio->uio_resid) + kl = uio->uio_resid; + + error = (*r)(l, buf, &ks); + if (error == 0) + error = uiomove(kv, kl, uio); + if (error == 0 && uio->uio_rw == UIO_WRITE) { + if (l->l_stat != LSSTOP) + error = EBUSY; + else + error = (*w)(l, buf, ks); + } + + uio->uio_offset = 0; + return error; +} +#endif + +int +process_doregs(struct lwp *curl /*tracer*/, + struct lwp *l /*traced*/, + struct uio *uio) +{ +#if defined(PT_GETREGS) || defined(PT_SETREGS) + size_t s; + ptrace_regrfunc_t r; + ptrace_regwfunc_t w; + +#ifdef COMPAT_NETBSD32 + const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0; + + if (__predict_false(pk32)) { + if ((l->l_proc->p_flag & PK_32) == 0) { + // 32 bit tracer can't trace 64 bit process + return EINVAL; + } + s = sizeof(process_reg32); + r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs32); + w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs32); + } else +#endif + { + s = sizeof(struct reg); + r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs); + w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs); + } + return proc_regio(l, uio, s, r, w); +#else + return EINVAL; +#endif +} + +int +process_dofpregs(struct lwp *curl /*tracer*/, + struct lwp *l /*traced*/, + struct uio *uio) +{ +#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) + size_t s; + ptrace_regrfunc_t r; + ptrace_regwfunc_t w; + +#ifdef COMPAT_NETBSD32 + const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0; + + if (__predict_false(pk32)) { + if ((l->l_proc->p_flag & PK_32) == 0) { + // 32 bit tracer can't trace 64 bit process + return EINVAL; + } + s = sizeof(process_fpreg32); + r = (ptrace_regrfunc_t)process_read_fpregs32; + w = (ptrace_regwfunc_t)process_write_fpregs32; + } else +#endif + { + s = sizeof(struct fpreg); + r = (ptrace_regrfunc_t)process_read_fpregs; + w = (ptrace_regwfunc_t)process_write_fpregs; + } + return proc_regio(l, uio, s, r, w); +#else + return EINVAL; +#endif +} + + +int +process_dodbregs(struct lwp *curl /*tracer*/, + struct lwp *l /*traced*/, + struct uio *uio) +{ +#if defined(PT_GETDBREGS) || defined(PT_SETDBREGS) + size_t s; + ptrace_regrfunc_t r; + ptrace_regwfunc_t w; + +#ifdef COMPAT_NETBSD32 + const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0; + + if (__predict_false(pk32)) { + if ((l->l_proc->p_flag & PK_32) == 0) { + // 32 bit tracer can't trace 64 bit process + return EINVAL; + } + s = sizeof(process_dbreg32); + r = (ptrace_regrfunc_t)process_read_dbregs32; + w = (ptrace_regwfunc_t)process_write_dbregs32; + } else +#endif + { + s = sizeof(struct dbreg); + r = (ptrace_regrfunc_t)process_read_dbregs; + w = (ptrace_regwfunc_t)process_write_dbregs; + } + return proc_regio(l, uio, s, r, w); +#else + return EINVAL; +#endif +} Index: src/sys/kern/sys_ptrace_common.c diff -u src/sys/kern/sys_ptrace_common.c:1.86 src/sys/kern/sys_ptrace_common.c:1.87 --- src/sys/kern/sys_ptrace_common.c:1.86 Mon Oct 19 10:52:19 2020 +++ src/sys/kern/sys_ptrace_common.c Tue Oct 20 16:28:55 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_ptrace_common.c,v 1.86 2020/10/19 14:52:19 kamil Exp $ */ +/* $NetBSD: sys_ptrace_common.c,v 1.87 2020/10/20 20:28:55 christos Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -107,7 +107,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.86 2020/10/19 14:52:19 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.87 2020/10/20 20:28:55 christos Exp $"); #ifdef _KERNEL_OPT #include "opt_ptrace.h" @@ -197,16 +197,6 @@ static kcondvar_t ptrace_cv; # define case_PT_SETDBREGS #endif -#if defined(PT_SETREGS) || defined(PT_GETREGS) || \ - defined(PT_SETFPREGS) || defined(PT_GETFPREGS) || \ - defined(PT_SETDBREGS) || defined(PT_GETDBREGS) -# define PT_REGISTERS -#endif - -#ifndef PTRACE_REGS_ALIGN -#define PTRACE_REGS_ALIGN /* nothing */ -#endif - static int ptrace_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) @@ -554,33 +544,6 @@ ptrace_needs_hold(int req) } } -int -ptrace_update_lwp(struct proc *t, struct lwp **lt, lwpid_t lid) -{ - if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1) - return 0; - - mutex_enter(t->p_lock); - lwp_delref2(*lt); - - *lt = lwp_find(t, lid); - if (*lt == NULL) { - mutex_exit(t->p_lock); - return ESRCH; - } - - if ((*lt)->l_flag & LW_SYSTEM) { - mutex_exit(t->p_lock); - *lt = NULL; - return EINVAL; - } - - lwp_addref(*lt); - mutex_exit(t->p_lock); - - return 0; -} - static int ptrace_get_siginfo(struct proc *t, struct ptrace_methods *ptm, void *addr, size_t data) @@ -1576,181 +1539,6 @@ out: return error; } -typedef int (*regrfunc_t)(struct lwp *, void *, size_t *); -typedef int (*regwfunc_t)(struct lwp *, void *, size_t); - -#ifdef PT_REGISTERS -static int -proc_regio(struct lwp *l, struct uio *uio, size_t ks, regrfunc_t r, - regwfunc_t w) -{ - char buf[1024] PTRACE_REGS_ALIGN; - int error; - char *kv; - size_t kl; - - if (ks > sizeof(buf)) - return E2BIG; - - if (uio->uio_offset < 0 || uio->uio_offset > (off_t)ks) - return EINVAL; - - kv = buf + uio->uio_offset; - kl = ks - uio->uio_offset; - - if (kl > uio->uio_resid) - kl = uio->uio_resid; - - error = (*r)(l, buf, &ks); - if (error == 0) - error = uiomove(kv, kl, uio); - if (error == 0 && uio->uio_rw == UIO_WRITE) { - if (l->l_stat != LSSTOP) - error = EBUSY; - else - error = (*w)(l, buf, ks); - } - - uio->uio_offset = 0; - return error; -} -#endif - -int -process_doregs(struct lwp *curl /*tracer*/, - struct lwp *l /*traced*/, - struct uio *uio) -{ -#if defined(PT_GETREGS) || defined(PT_SETREGS) - size_t s; - regrfunc_t r; - regwfunc_t w; - -#ifdef COMPAT_NETBSD32 - const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0; - - if (__predict_false(pk32)) { - if ((l->l_proc->p_flag & PK_32) == 0) { - // 32 bit tracer can't trace 64 bit process - return EINVAL; - } - s = sizeof(process_reg32); - r = __FPTRCAST(regrfunc_t, process_read_regs32); - w = __FPTRCAST(regwfunc_t, process_write_regs32); - } else -#endif - { - s = sizeof(struct reg); - r = __FPTRCAST(regrfunc_t, process_read_regs); - w = __FPTRCAST(regwfunc_t, process_write_regs); - } - return proc_regio(l, uio, s, r, w); -#else - return EINVAL; -#endif -} - -int -process_validregs(struct lwp *l) -{ - -#if defined(PT_SETREGS) || defined(PT_GETREGS) - return (l->l_flag & LW_SYSTEM) == 0; -#else - return 0; -#endif -} - -int -process_dofpregs(struct lwp *curl /*tracer*/, - struct lwp *l /*traced*/, - struct uio *uio) -{ -#if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) - size_t s; - regrfunc_t r; - regwfunc_t w; - -#ifdef COMPAT_NETBSD32 - const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0; - - if (__predict_false(pk32)) { - if ((l->l_proc->p_flag & PK_32) == 0) { - // 32 bit tracer can't trace 64 bit process - return EINVAL; - } - s = sizeof(process_fpreg32); - r = (regrfunc_t)process_read_fpregs32; - w = (regwfunc_t)process_write_fpregs32; - } else -#endif - { - s = sizeof(struct fpreg); - r = (regrfunc_t)process_read_fpregs; - w = (regwfunc_t)process_write_fpregs; - } - return proc_regio(l, uio, s, r, w); -#else - return EINVAL; -#endif -} - -int -process_validfpregs(struct lwp *l) -{ - -#if defined(PT_SETFPREGS) || defined(PT_GETFPREGS) - return (l->l_flag & LW_SYSTEM) == 0; -#else - return 0; -#endif -} - -int -process_dodbregs(struct lwp *curl /*tracer*/, - struct lwp *l /*traced*/, - struct uio *uio) -{ -#if defined(PT_GETDBREGS) || defined(PT_SETDBREGS) - size_t s; - regrfunc_t r; - regwfunc_t w; - -#ifdef COMPAT_NETBSD32 - const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0; - - if (__predict_false(pk32)) { - if ((l->l_proc->p_flag & PK_32) == 0) { - // 32 bit tracer can't trace 64 bit process - return EINVAL; - } - s = sizeof(process_dbreg32); - r = (regrfunc_t)process_read_dbregs32; - w = (regwfunc_t)process_write_dbregs32; - } else -#endif - { - s = sizeof(struct dbreg); - r = (regrfunc_t)process_read_dbregs; - w = (regwfunc_t)process_write_dbregs; - } - return proc_regio(l, uio, s, r, w); -#else - return EINVAL; -#endif -} - -int -process_validdbregs(struct lwp *l) -{ - -#if defined(PT_SETDBREGS) || defined(PT_GETDBREGS) - return (l->l_flag & LW_SYSTEM) == 0; -#else - return 0; -#endif -} - static int process_auxv_offset(struct proc *p, struct uio *uio) { Index: src/sys/sys/ptrace.h diff -u src/sys/sys/ptrace.h:1.71 src/sys/sys/ptrace.h:1.72 --- src/sys/sys/ptrace.h:1.71 Thu Oct 15 13:37:36 2020 +++ src/sys/sys/ptrace.h Tue Oct 20 16:28:55 2020 @@ -1,4 +1,4 @@ -/* $NetBSD: ptrace.h,v 1.71 2020/10/15 17:37:36 mgorny Exp $ */ +/* $NetBSD: ptrace.h,v 1.72 2020/10/20 20:28:55 christos Exp $ */ /*- * Copyright (c) 1984, 1993 @@ -345,6 +345,15 @@ int ptrace_machdep_dorequest(struct lwp #define FIX_SSTEP(p) #endif +typedef int (*ptrace_regrfunc_t)(struct lwp *, void *, size_t *); +typedef int (*ptrace_regwfunc_t)(struct lwp *, void *, size_t); + +#if defined(PT_SETREGS) || defined(PT_GETREGS) || \ + defined(PT_SETFPREGS) || defined(PT_GETFPREGS) || \ + defined(PT_SETDBREGS) || defined(PT_GETDBREGS) +# define PT_REGISTERS +#endif + #else /* !_KERNEL */ #include <sys/cdefs.h>