xref: /netbsd-src/sys/kern/sys_process_lwpstatus.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
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