xref: /freebsd/sys/compat/linux/linux_ptrace.c (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org>
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
8  * ("CTSRD"), as part of the DARPA CRASH research programme.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/lock.h>
37 #include <sys/proc.h>
38 #include <sys/ptrace.h>
39 #include <sys/sx.h>
40 #include <sys/syscallsubr.h>
41 
42 #include <machine/../linux/linux.h>
43 #include <machine/../linux/linux_proto.h>
44 #include <compat/linux/linux_emul.h>
45 #include <compat/linux/linux_errno.h>
46 #include <compat/linux/linux_misc.h>
47 #include <compat/linux/linux_signal.h>
48 #include <compat/linux/linux_util.h>
49 
50 #define	LINUX_PTRACE_TRACEME		0
51 #define	LINUX_PTRACE_PEEKTEXT		1
52 #define	LINUX_PTRACE_PEEKDATA		2
53 #define	LINUX_PTRACE_PEEKUSER		3
54 #define	LINUX_PTRACE_POKETEXT		4
55 #define	LINUX_PTRACE_POKEDATA		5
56 #define	LINUX_PTRACE_POKEUSER		6
57 #define	LINUX_PTRACE_CONT		7
58 #define	LINUX_PTRACE_KILL		8
59 #define	LINUX_PTRACE_SINGLESTEP		9
60 #define	LINUX_PTRACE_GETREGS		12
61 #define	LINUX_PTRACE_SETREGS		13
62 #define	LINUX_PTRACE_GETFPREGS		14
63 #define	LINUX_PTRACE_SETFPREGS		15
64 #define	LINUX_PTRACE_ATTACH		16
65 #define	LINUX_PTRACE_DETACH		17
66 #define	LINUX_PTRACE_SYSCALL		24
67 #define	LINUX_PTRACE_SETOPTIONS		0x4200
68 #define	LINUX_PTRACE_GETEVENTMSG	0x4201
69 #define	LINUX_PTRACE_GETSIGINFO		0x4202
70 #define	LINUX_PTRACE_GETREGSET		0x4204
71 #define	LINUX_PTRACE_SEIZE		0x4206
72 #define	LINUX_PTRACE_GET_SYSCALL_INFO	0x420e
73 
74 #define	LINUX_PTRACE_EVENT_EXEC		4
75 #define	LINUX_PTRACE_EVENT_EXIT		6
76 
77 #define	LINUX_PTRACE_O_TRACESYSGOOD	1
78 #define	LINUX_PTRACE_O_TRACEFORK	2
79 #define	LINUX_PTRACE_O_TRACEVFORK	4
80 #define	LINUX_PTRACE_O_TRACECLONE	8
81 #define	LINUX_PTRACE_O_TRACEEXEC	16
82 #define	LINUX_PTRACE_O_TRACEVFORKDONE	32
83 #define	LINUX_PTRACE_O_TRACEEXIT	64
84 #define	LINUX_PTRACE_O_TRACESECCOMP	128
85 #define	LINUX_PTRACE_O_EXITKILL		1048576
86 #define	LINUX_PTRACE_O_SUSPEND_SECCOMP	2097152
87 
88 #define	LINUX_NT_PRSTATUS		0x1
89 #define	LINUX_NT_PRFPREG		0x2
90 #define	LINUX_NT_X86_XSTATE		0x202
91 
92 #define	LINUX_PTRACE_O_MASK	(LINUX_PTRACE_O_TRACESYSGOOD |	\
93     LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK |	\
94     LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC |	\
95     LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT |	\
96     LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL |	\
97     LINUX_PTRACE_O_SUSPEND_SECCOMP)
98 
99 #define	LINUX_PTRACE_SYSCALL_INFO_NONE	0
100 #define	LINUX_PTRACE_SYSCALL_INFO_ENTRY	1
101 #define	LINUX_PTRACE_SYSCALL_INFO_EXIT	2
102 
103 static int
104 map_signum(int lsig, int *bsigp)
105 {
106 	int bsig;
107 
108 	if (lsig == 0) {
109 		*bsigp = 0;
110 		return (0);
111 	}
112 
113 	if (lsig < 0 || lsig > LINUX_SIGRTMAX)
114 		return (EINVAL);
115 
116 	bsig = linux_to_bsd_signal(lsig);
117 	if (bsig == SIGSTOP)
118 		bsig = 0;
119 
120 	*bsigp = bsig;
121 	return (0);
122 }
123 
124 int
125 linux_ptrace_status(struct thread *td, pid_t pid, int status)
126 {
127 	struct ptrace_lwpinfo lwpinfo;
128 	struct linux_pemuldata *pem;
129 	register_t saved_retval;
130 	int error;
131 
132 	saved_retval = td->td_retval[0];
133 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
134 	td->td_retval[0] = saved_retval;
135 	if (error != 0) {
136 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
137 		return (status);
138 	}
139 
140 	pem = pem_find(td->td_proc);
141 	KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
142 
143 	LINUX_PEM_SLOCK(pem);
144 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
145 	    lwpinfo.pl_flags & PL_FLAG_SCE)
146 		status |= (LINUX_SIGTRAP | 0x80) << 8;
147 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
148 	    lwpinfo.pl_flags & PL_FLAG_SCX) {
149 		if (lwpinfo.pl_flags & PL_FLAG_EXEC)
150 			status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8;
151 		else
152 			status |= (LINUX_SIGTRAP | 0x80) << 8;
153 	}
154 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
155 	    lwpinfo.pl_flags & PL_FLAG_EXITED)
156 		status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
157 	LINUX_PEM_SUNLOCK(pem);
158 
159 	return (status);
160 }
161 
162 static int
163 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
164 {
165 	int error;
166 
167 	error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
168 	if (error == 0)
169 		error = copyout(td->td_retval, data, sizeof(l_int));
170 	else if (error == ENOMEM)
171 		error = EIO;
172 	td->td_retval[0] = error;
173 
174 	return (error);
175 }
176 
177 static int
178 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
179 {
180 	struct linux_pemuldata *pem;
181 	int mask;
182 
183 	mask = 0;
184 
185 	if (data & ~LINUX_PTRACE_O_MASK) {
186 		linux_msg(td, "unknown ptrace option %lx set; "
187 		    "returning EINVAL",
188 		    data & ~LINUX_PTRACE_O_MASK);
189 		return (EINVAL);
190 	}
191 
192 	pem = pem_find(td->td_proc);
193 	KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
194 
195 	/*
196 	 * PTRACE_O_EXITKILL is ignored, we do that by default.
197 	 */
198 
199 	LINUX_PEM_XLOCK(pem);
200 	if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
201 		pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
202 	} else {
203 		pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
204 	}
205 	LINUX_PEM_XUNLOCK(pem);
206 
207 	if (data & LINUX_PTRACE_O_TRACEFORK)
208 		mask |= PTRACE_FORK;
209 
210 	if (data & LINUX_PTRACE_O_TRACEVFORK)
211 		mask |= PTRACE_VFORK;
212 
213 	if (data & LINUX_PTRACE_O_TRACECLONE)
214 		mask |= PTRACE_VFORK;
215 
216 	if (data & LINUX_PTRACE_O_TRACEEXEC)
217 		mask |= PTRACE_EXEC;
218 
219 	if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
220 		mask |= PTRACE_VFORK; /* XXX: Close enough? */
221 
222 	if (data & LINUX_PTRACE_O_TRACEEXIT) {
223 		pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
224 	} else {
225 		pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
226 	}
227 
228 	return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
229 }
230 
231 static int
232 linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data)
233 {
234 
235 	linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL");
236 	return (EINVAL);
237 }
238 
239 static int
240 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
241 {
242 	struct ptrace_lwpinfo lwpinfo;
243 	l_siginfo_t l_siginfo;
244 	int error, sig;
245 
246 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
247 	if (error != 0) {
248 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
249 		return (error);
250 	}
251 
252 	if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
253 		error = EINVAL;
254 		linux_msg(td, "no PL_FLAG_SI, returning %d", error);
255 		return (error);
256 	}
257 
258 	sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
259 	memset(&l_siginfo, 0, sizeof(l_siginfo));
260 	siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
261 	error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
262 	return (error);
263 }
264 
265 static int
266 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
267 {
268 	struct reg b_reg;
269 	struct linux_pt_regset l_regset;
270 	int error;
271 
272 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
273 	if (error != 0)
274 		return (error);
275 
276 	bsd_to_linux_regset(&b_reg, &l_regset);
277 	error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
278 	if (error != 0)
279 		return (error);
280 
281 	error = copyout(&l_regset, (void *)data, sizeof(l_regset));
282 	return (error);
283 }
284 
285 static int
286 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
287 {
288 	struct reg b_reg;
289 	struct linux_pt_regset l_regset;
290 	int error;
291 
292 	error = copyin(data, &l_regset, sizeof(l_regset));
293 	if (error != 0)
294 		return (error);
295 	linux_to_bsd_regset(&b_reg, &l_regset);
296 	error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
297 	return (error);
298 }
299 
300 static int
301 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
302 {
303 	struct reg b_reg;
304 	struct linux_pt_regset l_regset;
305 	struct iovec iov;
306 	size_t len;
307 	int error;
308 
309 	error = copyin((const void *)data, &iov, sizeof(iov));
310 	if (error != 0) {
311 		linux_msg(td, "copyin error %d", error);
312 		return (error);
313 	}
314 
315 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
316 	if (error != 0)
317 		return (error);
318 
319 	bsd_to_linux_regset(&b_reg, &l_regset);
320 	error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
321 	if (error != 0)
322 		return (error);
323 
324 	len = MIN(iov.iov_len, sizeof(l_regset));
325 	error = copyout(&l_regset, (void *)iov.iov_base, len);
326 	if (error != 0) {
327 		linux_msg(td, "copyout error %d", error);
328 		return (error);
329 	}
330 
331 	iov.iov_len = len;
332 	error = copyout(&iov, (void *)data, sizeof(iov));
333 	if (error != 0) {
334 		linux_msg(td, "iov copyout error %d", error);
335 		return (error);
336 	}
337 
338 	return (error);
339 }
340 
341 static int
342 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
343 {
344 
345 	switch (addr) {
346 	case LINUX_NT_PRSTATUS:
347 		return (linux_ptrace_getregset_prstatus(td, pid, data));
348 	case LINUX_NT_PRFPREG:
349 		linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; "
350 		    "returning EINVAL");
351 		return (EINVAL);
352 	case LINUX_NT_X86_XSTATE:
353 		linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; "
354 		    "returning EINVAL");
355 		return (EINVAL);
356 	default:
357 		linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; "
358 		    "returning EINVAL", addr);
359 		return (EINVAL);
360 	}
361 }
362 
363 static int
364 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
365 {
366 
367 	linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
368 	return (EINVAL);
369 }
370 
371 static int
372 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid,
373     l_ulong len, l_ulong data)
374 {
375 	struct ptrace_lwpinfo lwpinfo;
376 	struct ptrace_sc_ret sr;
377 	struct reg b_reg;
378 	struct syscall_info si;
379 	int error;
380 
381 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
382 	if (error != 0) {
383 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
384 		return (error);
385 	}
386 
387 	memset(&si, 0, sizeof(si));
388 
389 	if (lwpinfo.pl_flags & PL_FLAG_SCE) {
390 		si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY;
391 		si.entry.nr = lwpinfo.pl_syscall_code;
392 		/*
393 		 * The use of PT_GET_SC_ARGS there is special,
394 		 * implementation of PT_GET_SC_ARGS for Linux-ABI
395 		 * callers emulates Linux bug which strace(1) depends
396 		 * on: at initialization it tests whether ptrace works
397 		 * by calling close(2), or some other single-argument
398 		 * syscall, _with six arguments_, and then verifies
399 		 * whether it can fetch them all using this API;
400 		 * otherwise it bails out.
401 		 */
402 		error = kern_ptrace(td, PT_GET_SC_ARGS, pid,
403 		    &si.entry.args, sizeof(si.entry.args));
404 		if (error != 0) {
405 			linux_msg(td, "PT_GET_SC_ARGS failed with error %d",
406 			    error);
407 			return (error);
408 		}
409 	} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
410 		si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT;
411 		error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr));
412 
413 		if (error != 0) {
414 			linux_msg(td, "PT_GET_SC_RET failed with error %d",
415 			    error);
416 			return (error);
417 		}
418 
419 		if (sr.sr_error == 0) {
420 			si.exit.rval = sr.sr_retval[0];
421 			si.exit.is_error = 0;
422 		} else if (sr.sr_error == EJUSTRETURN) {
423 			/*
424 			 * EJUSTRETURN means the actual value to return
425 			 * has already been put into td_frame; instead
426 			 * of extracting it and trying to determine whether
427 			 * it's an error or not just bail out and let
428 			 * the ptracing process fall back to another method.
429 			 */
430 			si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
431 		} else if (sr.sr_error == ERESTART) {
432 			si.exit.rval = -LINUX_ERESTARTSYS;
433 			si.exit.is_error = 1;
434 		} else {
435 			si.exit.rval = bsd_to_linux_errno(sr.sr_error);
436 			si.exit.is_error = 1;
437 		}
438 	} else {
439 		si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
440 	}
441 
442 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
443 	if (error != 0)
444 		return (error);
445 
446 	linux_ptrace_get_syscall_info_machdep(&b_reg, &si);
447 
448 	len = MIN(len, sizeof(si));
449 	error = copyout(&si, (void *)data, len);
450 	if (error == 0)
451 		td->td_retval[0] = sizeof(si);
452 
453 	return (error);
454 }
455 
456 int
457 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
458 {
459 	void *addr;
460 	pid_t pid;
461 	int error, sig;
462 
463 	if (!allow_ptrace)
464 		return (ENOSYS);
465 
466 	pid  = (pid_t)uap->pid;
467 	addr = (void *)uap->addr;
468 
469 	switch (uap->req) {
470 	case LINUX_PTRACE_TRACEME:
471 		error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
472 		break;
473 	case LINUX_PTRACE_PEEKTEXT:
474 	case LINUX_PTRACE_PEEKDATA:
475 		error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
476 		if (error != 0)
477 			goto out;
478 		/*
479 		 * Linux expects this syscall to read 64 bits, not 32.
480 		 */
481 		error = linux_ptrace_peek(td, pid,
482 		    (void *)(uap->addr + 4), (void *)(uap->data + 4));
483 		break;
484 	case LINUX_PTRACE_PEEKUSER:
485 		error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
486 		break;
487 	case LINUX_PTRACE_POKETEXT:
488 	case LINUX_PTRACE_POKEDATA:
489 		error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
490 		if (error != 0)
491 			goto out;
492 		/*
493 		 * Linux expects this syscall to write 64 bits, not 32.
494 		 */
495 		error = kern_ptrace(td, PT_WRITE_D, pid,
496 		    (void *)(uap->addr + 4), uap->data >> 32);
497 		break;
498 	case LINUX_PTRACE_POKEUSER:
499 		error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
500 		break;
501 	case LINUX_PTRACE_CONT:
502 		error = map_signum(uap->data, &sig);
503 		if (error != 0)
504 			break;
505 		error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
506 		break;
507 	case LINUX_PTRACE_KILL:
508 		error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
509 		break;
510 	case LINUX_PTRACE_SINGLESTEP:
511 		error = map_signum(uap->data, &sig);
512 		if (error != 0)
513 			break;
514 		error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
515 		break;
516 	case LINUX_PTRACE_GETREGS:
517 		error = linux_ptrace_getregs(td, pid, (void *)uap->data);
518 		break;
519 	case LINUX_PTRACE_SETREGS:
520 		error = linux_ptrace_setregs(td, pid, (void *)uap->data);
521 		break;
522 	case LINUX_PTRACE_ATTACH:
523 		error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
524 		break;
525 	case LINUX_PTRACE_DETACH:
526 		error = map_signum(uap->data, &sig);
527 		if (error != 0)
528 			break;
529 		error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
530 		break;
531 	case LINUX_PTRACE_SYSCALL:
532 		error = map_signum(uap->data, &sig);
533 		if (error != 0)
534 			break;
535 		error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
536 		break;
537 	case LINUX_PTRACE_SETOPTIONS:
538 		error = linux_ptrace_setoptions(td, pid, uap->data);
539 		break;
540 	case LINUX_PTRACE_GETEVENTMSG:
541 		error = linux_ptrace_geteventmsg(td, pid, uap->data);
542 		break;
543 	case LINUX_PTRACE_GETSIGINFO:
544 		error = linux_ptrace_getsiginfo(td, pid, uap->data);
545 		break;
546 	case LINUX_PTRACE_GETREGSET:
547 		error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
548 		break;
549 	case LINUX_PTRACE_SEIZE:
550 		error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
551 		break;
552 	case LINUX_PTRACE_GET_SYSCALL_INFO:
553 		error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
554 		break;
555 	default:
556 		linux_msg(td, "ptrace(%ld, ...) not implemented; "
557 		    "returning EINVAL", uap->req);
558 		error = EINVAL;
559 		break;
560 	}
561 
562 out:
563 	if (error == EBUSY)
564 		error = ESRCH;
565 
566 	return (error);
567 }
568