Home | History | Annotate | Line # | Download | only in kern
sys_process_lwpstatus.c revision 1.3
      1 /*	$NetBSD: sys_process_lwpstatus.c,v 1.3 2020/10/20 22:31:20 rin Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2019 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: sys_process_lwpstatus.c,v 1.3 2020/10/20 22:31:20 rin Exp $");
     31 
     32 #ifdef _KERNEL_OPT
     33 #include "opt_ptrace.h"
     34 #include "opt_ktrace.h"
     35 #include "opt_pax.h"
     36 #include "opt_compat_netbsd32.h"
     37 #endif
     38 
     39 #if defined(__HAVE_COMPAT_NETBSD32) && !defined(COMPAT_NETBSD32) \
     40     && !defined(_RUMPKERNEL)
     41 #define COMPAT_NETBSD32
     42 #endif
     43 
     44 #include <sys/param.h>
     45 #include <sys/systm.h>
     46 #include <sys/errno.h>
     47 #include <sys/lwp.h>
     48 #include <sys/proc.h>
     49 #include <sys/ptrace.h>
     50 
     51 #ifndef PTRACE_REGS_ALIGN
     52 #define PTRACE_REGS_ALIGN /* nothing */
     53 #endif
     54 
     55 void
     56 ptrace_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
     57 {
     58 
     59 	KASSERT(l->l_lid == pls->pl_lwpid);
     60 
     61 	memcpy(&pls->pl_sigmask, &l->l_sigmask, sizeof(pls->pl_sigmask));
     62 	memcpy(&pls->pl_sigpend, &l->l_sigpend.sp_set, sizeof(pls->pl_sigpend));
     63 
     64 	if (l->l_name == NULL)
     65 		memset(&pls->pl_name, 0, PL_LNAMELEN);
     66 	else {
     67 		KASSERT(strlen(l->l_name) < PL_LNAMELEN);
     68 		strncpy(pls->pl_name, l->l_name, PL_LNAMELEN);
     69 	}
     70 
     71 #ifdef PTRACE_LWP_GETPRIVATE
     72 	pls->pl_private = (void *)(intptr_t)PTRACE_LWP_GETPRIVATE(l);
     73 #else
     74 	pls->pl_private = l->l_private;
     75 #endif
     76 }
     77 
     78 void
     79 process_read_lwpstatus(struct lwp *l, struct ptrace_lwpstatus *pls)
     80 {
     81 
     82 	pls->pl_lwpid = l->l_lid;
     83 
     84 	ptrace_read_lwpstatus(l, pls);
     85 }
     86 
     87 int
     88 ptrace_update_lwp(struct proc *t, struct lwp **lt, lwpid_t lid)
     89 {
     90 	if (lid == 0 || lid == (*lt)->l_lid || t->p_nlwps == 1)
     91 		return 0;
     92 
     93 	mutex_enter(t->p_lock);
     94 	lwp_delref2(*lt);
     95 
     96 	*lt = lwp_find(t, lid);
     97 	if (*lt == NULL) {
     98 		mutex_exit(t->p_lock);
     99 		return ESRCH;
    100 	}
    101 
    102 	if ((*lt)->l_flag & LW_SYSTEM) {
    103 		mutex_exit(t->p_lock);
    104 		*lt = NULL;
    105 		return EINVAL;
    106 	}
    107 
    108 	lwp_addref(*lt);
    109 	mutex_exit(t->p_lock);
    110 
    111 	return 0;
    112 }
    113 
    114 int
    115 process_validfpregs(struct lwp *l)
    116 {
    117 
    118 #if defined(PT_SETFPREGS) || defined(PT_GETFPREGS)
    119 	return (l->l_flag & LW_SYSTEM) == 0;
    120 #else
    121 	return 0;
    122 #endif
    123 }
    124 
    125 int
    126 process_validregs(struct lwp *l)
    127 {
    128 
    129 #if defined(PT_SETREGS) || defined(PT_GETREGS)
    130 	return (l->l_flag & LW_SYSTEM) == 0;
    131 #else
    132 	return 0;
    133 #endif
    134 }
    135 
    136 int
    137 process_validdbregs(struct lwp *l)
    138 {
    139 
    140 #if defined(PT_SETDBREGS) || defined(PT_GETDBREGS)
    141 	return (l->l_flag & LW_SYSTEM) == 0;
    142 #else
    143 	return 0;
    144 #endif
    145 }
    146 
    147 #ifdef PT_REGISTERS
    148 static int
    149 proc_regio(struct lwp *l, struct uio *uio, size_t ks, ptrace_regrfunc_t r,
    150     ptrace_regwfunc_t w)
    151 {
    152 	char buf[1024] PTRACE_REGS_ALIGN;
    153 	int error;
    154 	char *kv;
    155 	size_t kl;
    156 
    157 	if (ks > sizeof(buf))
    158 		return E2BIG;
    159 
    160 	if (uio->uio_offset < 0 || uio->uio_offset > (off_t)ks)
    161 		return EINVAL;
    162 
    163 	kv = buf + uio->uio_offset;
    164 	kl = ks - uio->uio_offset;
    165 
    166 	if (kl > uio->uio_resid)
    167 		kl = uio->uio_resid;
    168 
    169 	error = (*r)(l, buf, &ks);
    170 	if (error == 0)
    171 		error = uiomove(kv, kl, uio);
    172 	if (error == 0 && uio->uio_rw == UIO_WRITE) {
    173 		if (l->l_stat != LSSTOP)
    174 			error = EBUSY;
    175 		else
    176 			error = (*w)(l, buf, ks);
    177 	}
    178 
    179 	uio->uio_offset = 0;
    180 	return error;
    181 }
    182 #endif
    183 
    184 int
    185 process_doregs(struct lwp *curl /*tracer*/,
    186     struct lwp *l /*traced*/,
    187     struct uio *uio)
    188 {
    189 #if defined(PT_GETREGS) || defined(PT_SETREGS)
    190 	size_t s;
    191 	ptrace_regrfunc_t r;
    192 	ptrace_regwfunc_t w;
    193 
    194 #ifdef COMPAT_NETBSD32
    195 	const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
    196 
    197 	if (__predict_false(pk32)) {
    198 		if ((l->l_proc->p_flag & PK_32) == 0) {
    199 			// 32 bit tracer can't trace 64 bit process
    200 			return EINVAL;
    201 		}
    202 		s = sizeof(process_reg32);
    203 		r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs32);
    204 		w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs32);
    205 	} else
    206 #endif
    207 	{
    208 		s = sizeof(struct reg);
    209 		r = __FPTRCAST(ptrace_regrfunc_t, process_read_regs);
    210 		w = __FPTRCAST(ptrace_regwfunc_t, process_write_regs);
    211 	}
    212 	return proc_regio(l, uio, s, r, w);
    213 #else
    214 	return EINVAL;
    215 #endif
    216 }
    217 
    218 int
    219 process_dofpregs(struct lwp *curl /*tracer*/,
    220     struct lwp *l /*traced*/,
    221     struct uio *uio)
    222 {
    223 #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS)
    224 	size_t s;
    225 	ptrace_regrfunc_t r;
    226 	ptrace_regwfunc_t w;
    227 
    228 #ifdef COMPAT_NETBSD32
    229 	const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
    230 
    231 	if (__predict_false(pk32)) {
    232 		if ((l->l_proc->p_flag & PK_32) == 0) {
    233 			// 32 bit tracer can't trace 64 bit process
    234 			return EINVAL;
    235 		}
    236 		s = sizeof(process_fpreg32);
    237 		r = (ptrace_regrfunc_t)process_read_fpregs32;
    238 		w = (ptrace_regwfunc_t)process_write_fpregs32;
    239 	} else
    240 #endif
    241 	{
    242 		s = sizeof(struct fpreg);
    243 		r = (ptrace_regrfunc_t)process_read_fpregs;
    244 		w = (ptrace_regwfunc_t)process_write_fpregs;
    245 	}
    246 	return proc_regio(l, uio, s, r, w);
    247 #else
    248 	return EINVAL;
    249 #endif
    250 }
    251 
    252 
    253 int
    254 process_dodbregs(struct lwp *curl /*tracer*/,
    255     struct lwp *l /*traced*/,
    256     struct uio *uio)
    257 {
    258 #if defined(PT_GETDBREGS) || defined(PT_SETDBREGS)
    259 	size_t s;
    260 	ptrace_regrfunc_t r;
    261 	ptrace_regwfunc_t w;
    262 
    263 #ifdef COMPAT_NETBSD32
    264 	const bool pk32 = (curl->l_proc->p_flag & PK_32) != 0;
    265 
    266 	if (__predict_false(pk32)) {
    267 		if ((l->l_proc->p_flag & PK_32) == 0) {
    268 			// 32 bit tracer can't trace 64 bit process
    269 			return EINVAL;
    270 		}
    271 		s = sizeof(process_dbreg32);
    272 		r = (ptrace_regrfunc_t)process_read_dbregs32;
    273 		w = (ptrace_regwfunc_t)process_write_dbregs32;
    274 	} else
    275 #endif
    276 	{
    277 		s = sizeof(struct dbreg);
    278 		r = (ptrace_regrfunc_t)process_read_dbregs;
    279 		w = (ptrace_regwfunc_t)process_write_dbregs;
    280 	}
    281 	return proc_regio(l, uio, s, r, w);
    282 #else
    283 	return EINVAL;
    284 #endif
    285 }
    286