xref: /illumos-gate/usr/src/lib/libproc/common/Psyscall.c (revision a7cee4e9766ebda975dd156d1f10a70f51c242f0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
28  * Copyright 2026 Oxide Computer Company
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <ctype.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <memory.h>
38 #include <errno.h>
39 #include <dirent.h>
40 #include <limits.h>
41 #include <signal.h>
42 #include <sys/types.h>
43 #include <sys/uio.h>
44 #include <sys/stat.h>
45 #include <sys/resource.h>
46 #include <sys/param.h>
47 #include <sys/stack.h>
48 #include <sys/fault.h>
49 #include <sys/syscall.h>
50 #include <sys/sysmacros.h>
51 
52 #include "libproc.h"
53 #include "Pcontrol.h"
54 #include "Putil.h"
55 #include "P32ton.h"
56 #include "Pisadep.h"
57 
58 extern sigset_t blockable_sigs;
59 extern int _libproc_test_fail_copyinargs;
60 
61 static void
62 Pabort_agent(struct ps_prochandle *P)
63 {
64 	int sysnum = P->status.pr_lwp.pr_syscall;
65 	int stop;
66 
67 	Pdprintf("agent LWP is stopped or asleep in syscall %d\n", sysnum);
68 	(void) Pstop(P, 0);
69 	stop = Psysexit(P, sysnum, TRUE);
70 
71 	if (Psetrun(P, 0, PRSABORT) == 0) {
72 		while (Pwait(P, 0) == -1 && errno == EINTR)
73 			continue;
74 		(void) Psysexit(P, sysnum, stop);
75 		Pdprintf("agent LWP system call aborted\n");
76 	}
77 }
78 
79 /*
80  * Create the /proc agent LWP for further operations.
81  */
82 int
83 Pcreate_agent(struct ps_prochandle *P)
84 {
85 	int fd;
86 	char pathname[PATH_MAX];
87 	char *fname;
88 	struct {
89 		long	cmd;
90 		prgregset_t regs;
91 	} cmd;
92 
93 	/*
94 	 * If not first reference, we already have the /proc agent LWP active.
95 	 */
96 	if (P->agentcnt > 0) {
97 		P->agentcnt++;
98 		return (0);
99 	}
100 
101 	/*
102 	 * The agent is not available for use as a mortician or as an
103 	 * obstetrician.
104 	 */
105 	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
106 	    P->state == PS_IDLE) {
107 		errno = ENOENT;
108 		return (-1);
109 	}
110 
111 	/*
112 	 * Create the special /proc agent LWP if it doesn't already exist.
113 	 * Give it the registers of the representative LWP.
114 	 */
115 	(void) Pstop(P, 0);
116 	Psync(P);
117 	if (!(P->status.pr_lwp.pr_flags & PR_AGENT)) {
118 		cmd.cmd = PCAGENT;
119 		(void) memcpy(&cmd.regs, &P->status.pr_lwp.pr_reg[0],
120 		    sizeof (P->status.pr_lwp.pr_reg));
121 		if (write(P->ctlfd, &cmd, sizeof (cmd)) != sizeof (cmd))
122 			goto bad;
123 	}
124 
125 	/* refresh the process status */
126 	(void) Pstopstatus(P, PCNULL, 0);
127 
128 	/* open the agent LWP files */
129 	(void) snprintf(pathname, sizeof (pathname), "%s/%d/lwp/agent/",
130 	    procfs_path, (int)P->pid);
131 	fname = pathname + strlen(pathname);
132 	(void) set_minfd();
133 
134 	/*
135 	 * It is difficult to know how to recover from the two errors
136 	 * that follow.  The agent LWP exists and we need to kill it,
137 	 * but we can't because we need it active in order to kill it.
138 	 * We just hope that these failures never occur.
139 	 */
140 	(void) strcpy(fname, "lwpstatus");
141 	if ((fd = open(pathname, O_RDONLY)) < 0 ||
142 	    (fd = dupfd(fd, 0)) < 0)
143 		goto bad;
144 	P->agentstatfd = fd;
145 
146 	(void) strcpy(fname, "lwpctl");
147 	if ((fd = open(pathname, O_WRONLY)) < 0 ||
148 	    (fd = dupfd(fd, 0)) < 0)
149 		goto bad;
150 	P->agentctlfd = fd;
151 
152 	/*
153 	 * If the agent is currently asleep in a system call or stopped on
154 	 * system call entry, attempt to abort the system call so it's ready to
155 	 * serve.
156 	 */
157 	if ((P->status.pr_lwp.pr_flags & PR_ASLEEP) ||
158 	    ((P->status.pr_lwp.pr_flags & PR_STOPPED) &&
159 	    P->status.pr_lwp.pr_why == PR_SYSENTRY)) {
160 		Pdprintf("Pcreate_agent: aborting agent syscall; lwp is %s\n",
161 		    (P->status.pr_lwp.pr_flags & PR_ASLEEP) ?
162 		    "asleep" : "stopped");
163 		Pabort_agent(P);
164 	}
165 
166 	/* get the agent LWP status */
167 	P->agentcnt++;
168 	if (Pstopstatus(P, PCNULL, 0) != 0) {
169 		Pdestroy_agent(P);
170 		return (-1);
171 	}
172 
173 	return (0);
174 
175 bad:
176 	if (P->agentstatfd >= 0)
177 		(void) close(P->agentstatfd);
178 	if (P->agentctlfd >= 0)
179 		(void) close(P->agentctlfd);
180 	P->agentstatfd = -1;
181 	P->agentctlfd = -1;
182 	/* refresh the process status */
183 	(void) Pstopstatus(P, PCNULL, 0);
184 	return (-1);
185 }
186 
187 /*
188  * Decrement the /proc agent agent reference count.
189  * On last reference, destroy the agent.
190  */
191 void
192 Pdestroy_agent(struct ps_prochandle *P)
193 {
194 	if (P->agentcnt > 1)
195 		P->agentcnt--;
196 	else {
197 		int flags;
198 
199 		Psync(P); /* Flush out any pending changes */
200 
201 		(void) Pstopstatus(P, PCNULL, 0);
202 		flags = P->status.pr_lwp.pr_flags;
203 
204 		/*
205 		 * If the agent is currently asleep in a system call or stopped
206 		 * on system call entry, attempt to abort the system call so we
207 		 * can terminate the agent.
208 		 */
209 		if ((flags & PR_AGENT) && ((flags & PR_ASLEEP) ||
210 		    ((flags & PR_STOPPED) &&
211 		    P->status.pr_lwp.pr_why == PR_SYSENTRY))) {
212 			Pdprintf("Pdestroy_agent: aborting agent syscall\n");
213 			Pabort_agent(P);
214 		}
215 
216 		/*
217 		 * The agent itself is destroyed by forcing it to execute
218 		 * the _lwp_exit(2) system call.  Close our agent descriptors
219 		 * regardless of whether this is successful.
220 		 */
221 		if (pr_lwp_exit(P) != 0) {
222 			Pdprintf("Pdestroy_agent: failed to terminate "
223 			    "agent LWP: %s\n", strerror(errno));
224 		}
225 		(void) close(P->agentctlfd);
226 		(void) close(P->agentstatfd);
227 		P->agentctlfd = -1;
228 		P->agentstatfd = -1;
229 		P->agentcnt = 0;
230 
231 		/*
232 		 * Now that (hopefully) the agent has exited, refresh the
233 		 * status: the representative LWP is no longer the agent.
234 		 */
235 		(void) Pstopstatus(P, PCNULL, 0);
236 	}
237 }
238 
239 /*
240  * Execute the syscall instruction.
241  */
242 static int
243 execute(struct ps_prochandle *P, int sysindex)
244 {
245 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
246 	int washeld = FALSE;
247 	sigset_t hold;		/* mask of held signals */
248 	int cursig;
249 	struct {
250 		long cmd;
251 		siginfo_t siginfo;
252 	} ctl;
253 	int sentry;		/* old value of stop-on-syscall-entry */
254 
255 	sentry = Psysentry(P, sysindex, TRUE);	/* set stop-on-syscall-entry */
256 
257 	/*
258 	 * If not already blocked, block all signals now.
259 	 */
260 	if (memcmp(&P->status.pr_lwp.pr_lwphold, &blockable_sigs,
261 	    sizeof (sigset_t)) != 0) {
262 		hold = P->status.pr_lwp.pr_lwphold;
263 		P->status.pr_lwp.pr_lwphold = blockable_sigs;
264 		P->flags |= SETHOLD;
265 		washeld = TRUE;
266 	}
267 
268 	/*
269 	 * If there is a current signal, remember it and cancel it.
270 	 */
271 	if ((cursig = P->status.pr_lwp.pr_cursig) != 0) {
272 		ctl.cmd = PCSSIG;
273 		ctl.siginfo = P->status.pr_lwp.pr_info;
274 	}
275 
276 	if (Psetrun(P, 0, PRCSIG | PRCFAULT) == -1)
277 		goto bad;
278 
279 	while (P->state == PS_RUN) {
280 		(void) Pwait(P, 0);
281 	}
282 	if (P->state != PS_STOP)
283 		goto bad;
284 
285 	if (cursig)				/* restore cursig */
286 		(void) write(ctlfd, &ctl, sizeof (ctl));
287 	if (washeld) {		/* restore the signal mask if we set it */
288 		P->status.pr_lwp.pr_lwphold = hold;
289 		P->flags |= SETHOLD;
290 	}
291 
292 	(void) Psysentry(P, sysindex, sentry);	/* restore sysentry stop */
293 
294 	if (P->status.pr_lwp.pr_why  == PR_SYSENTRY &&
295 	    P->status.pr_lwp.pr_what == sysindex)
296 		return (0);
297 bad:
298 	return (-1);
299 }
300 
301 
302 /*
303  * Perform system call in controlled process.
304  */
305 int
306 Psyscall(struct ps_prochandle *P,
307     sysret_t *rval,		/* syscall return values */
308     int sysindex,		/* system call index */
309     uint_t nargs,		/* number of arguments to system call */
310     argdes_t *argp)		/* argument descriptor array */
311 {
312 	int agent_created = FALSE;
313 	pstatus_t save_pstatus;
314 	argdes_t *adp;			/* pointer to argument descriptor */
315 	int i;				/* general index value */
316 	int model;			/* data model */
317 	int error = 0;			/* syscall errno */
318 	int Perr = 0;			/* local error number */
319 	int sexit;			/* old value of stop-on-syscall-exit */
320 	prgreg_t sp;			/* adjusted stack pointer */
321 	prgreg_t ap;			/* adjusted argument pointer */
322 	sigset_t unblock;
323 
324 	(void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
325 
326 	rval->sys_rval1 = 0;		/* initialize return values */
327 	rval->sys_rval2 = 0;
328 
329 	if (sysindex <= 0 || sysindex > PRMAXSYS || nargs > MAXARGS)
330 		goto bad1;	/* programming error */
331 
332 	if (P->state == PS_DEAD || P->state == PS_UNDEAD || P->state == PS_IDLE)
333 		goto bad1;	/* dead processes can't perform system calls */
334 
335 	model = P->status.pr_dmodel;
336 #ifndef _LP64
337 	/* We must be a 64-bit process to deal with a 64-bit process */
338 	if (model == PR_MODEL_LP64)
339 		goto bad9;
340 #endif
341 
342 	/*
343 	 * Create the /proc agent LWP in the process to do all the work.
344 	 * (It may already exist; nested create/destroy is permitted
345 	 * by virtue of the reference count.)
346 	 */
347 	if (Pcreate_agent(P) != 0)
348 		goto bad8;
349 
350 	/*
351 	 * Save agent's status to restore on exit.
352 	 */
353 	agent_created = TRUE;
354 	save_pstatus = P->status;
355 
356 	if (P->state != PS_STOP ||		/* check state of LWP */
357 	    (P->status.pr_flags & PR_ASLEEP))
358 		goto bad2;
359 
360 	if (Pscantext(P))			/* bad text ? */
361 		goto bad3;
362 
363 	/*
364 	 * Validate arguments and compute the stack frame parameters.
365 	 * Begin with the current stack pointer.
366 	 */
367 #ifdef _LP64
368 	if (model == PR_MODEL_LP64) {
369 		sp = P->status.pr_lwp.pr_reg[R_SP] + STACK_BIAS;
370 #if defined(__amd64)
371 		/*
372 		 * To offset the expense of computerised subtraction, the AMD64
373 		 * ABI allows a process the use of a 128-byte area beyond the
374 		 * location pointed to by %rsp.  We must advance the agent's
375 		 * stack pointer by at least the size of this region or else it
376 		 * may corrupt this temporary storage.
377 		 */
378 		sp -= STACK_RESERVE64;
379 #endif
380 		sp = PSTACK_ALIGN64(sp);
381 	} else {
382 #endif
383 		sp = (uint32_t)P->status.pr_lwp.pr_reg[R_SP];
384 		sp = PSTACK_ALIGN32(sp);
385 #ifdef _LP64
386 	}
387 #endif
388 
389 	/*
390 	 * For each AT_BYREF argument, compute the necessary
391 	 * stack space and the object's stack address.
392 	 */
393 	for (i = 0, adp = argp; i < nargs; i++, adp++) {
394 		rval->sys_rval1 = i;		/* in case of error */
395 		switch (adp->arg_type) {
396 		default:			/* programming error */
397 			goto bad4;
398 		case AT_BYVAL:			/* simple argument */
399 			break;
400 		case AT_BYREF:			/* must allocate space */
401 			switch (adp->arg_inout) {
402 			case AI_INPUT:
403 			case AI_OUTPUT:
404 			case AI_INOUT:
405 				if (adp->arg_object == NULL)
406 					goto bad5;	/* programming error */
407 				break;
408 			default:		/* programming error */
409 				goto bad6;
410 			}
411 			/* allocate stack space for BYREF argument */
412 			if (adp->arg_size == 0 || adp->arg_size > MAXARGL)
413 				goto bad7;	/* programming error */
414 #ifdef _LP64
415 			if (model == PR_MODEL_LP64)
416 				sp = PSTACK_ALIGN64(sp - adp->arg_size);
417 			else
418 #endif
419 				sp = PSTACK_ALIGN32(sp - adp->arg_size);
420 			adp->arg_value = sp;	/* stack address for object */
421 			break;
422 		}
423 	}
424 	rval->sys_rval1 = 0;			/* in case of error */
425 	/*
426 	 * Point of no return.
427 	 * Perform the system call entry, adjusting %sp.
428 	 * This moves the LWP to the stopped-on-syscall-entry state
429 	 * just before the arguments to the system call are fetched.
430 	 */
431 	ap = Psyscall_setup(P, nargs, sysindex, sp);
432 	P->flags |= SETREGS;	/* set registers before continuing */
433 	Pdprintf("Psyscall(): execute(sysindex = %d)\n", sysindex);
434 
435 	/*
436 	 * Execute the syscall instruction and stop on syscall entry.
437 	 */
438 	if (execute(P, sysindex) != 0 ||
439 	    (!Pissyscall(P, P->status.pr_lwp.pr_reg[R_PC]) &&
440 	    !Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)))
441 		goto bad10;
442 
443 	Pdprintf("Psyscall(): copying arguments\n");
444 
445 	/*
446 	 * The LWP is stopped at syscall entry.
447 	 * Copy objects to stack frame for each argument.
448 	 */
449 	for (i = 0, adp = argp; i < nargs; i++, adp++) {
450 		rval->sys_rval1 = i;		/* in case of error */
451 		if (adp->arg_type != AT_BYVAL &&
452 		    adp->arg_inout != AI_OUTPUT) {
453 			/* copy input byref parameter to process */
454 			if (Pwrite(P, adp->arg_object, adp->arg_size,
455 			    (uintptr_t)adp->arg_value) != adp->arg_size)
456 				goto bad17;
457 		}
458 	}
459 	rval->sys_rval1 = 0;			/* in case of error */
460 
461 	/*
462 	 * The private _libproc_test_fail_copyinargs flag makes the following
463 	 * write to the agent's stack behave as though it had failed. It
464 	 * exists so that the test suite can exercise the failure handling
465 	 * below, including during agent destruction, without requiring a
466 	 * target process whose stack is genuinely unwritable.
467 	 */
468 	if (_libproc_test_fail_copyinargs ||
469 	    Psyscall_copyinargs(P, nargs, argp, ap) != 0) {
470 		/*
471 		 * Constructing the fabricated stack frame failed. That is
472 		 * fatal for a normal system call, but not for _lwp_exit().
473 		 * The frame is only consumed on return to userland, and
474 		 * _lwp_exit() does not return, so the call can safely
475 		 * proceed without it. This matters when destroying an agent
476 		 * whose stack cannot be written at all. The agent inherits
477 		 * its stack from the representative lwp, and if that lwp was
478 		 * caught early in process startup then the area below the
479 		 * stack pointer may be unmapped. A write there through /proc
480 		 * fails, since such writes do not grow the stack. Bailing
481 		 * out here would orphan the agent, and the process could
482 		 * then never be set running again because run-on-last-close
483 		 * is skipped for a process which still has an agent lwp.
484 		 */
485 		if (sysindex != SYS_lwp_exit)
486 			goto bad18;
487 		Pdprintf("Psyscall(): ignoring copyinargs failure for "
488 		    "_lwp_exit()\n");
489 	}
490 
491 	/*
492 	 * Complete the system call.
493 	 * This moves the LWP to the stopped-on-syscall-exit state.
494 	 */
495 	Pdprintf("Psyscall(): set running at sysentry\n");
496 
497 	sexit = Psysexit(P, sysindex, TRUE);	/* catch this syscall exit */
498 	do {
499 		if (Psetrun(P, 0, 0) == -1)
500 			goto bad21;
501 		while (P->state == PS_RUN)
502 			(void) Pwait(P, 0);
503 	} while (P->state == PS_STOP && P->status.pr_lwp.pr_why != PR_SYSEXIT);
504 	(void) Psysexit(P, sysindex, sexit);	/* restore original setting */
505 
506 	/*
507 	 * If the system call was _lwp_exit(), we expect that our last call
508 	 * to Pwait() will yield ENOENT because the LWP no longer exists.
509 	 */
510 	if (sysindex == SYS_lwp_exit && errno == ENOENT) {
511 		Pdprintf("Psyscall(): _lwp_exit successful\n");
512 		rval->sys_rval1 = rval->sys_rval2 = 0;
513 		goto out;
514 	}
515 
516 	if (P->state != PS_STOP || P->status.pr_lwp.pr_why != PR_SYSEXIT)
517 		goto bad22;
518 
519 	if (P->status.pr_lwp.pr_what != sysindex)
520 		goto bad23;
521 
522 	if (!Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)) {
523 		Pdprintf("Pissyscall_prev() failed\n");
524 		goto bad24;
525 	}
526 
527 	Pdprintf("Psyscall(): caught at sysexit\n");
528 
529 	/*
530 	 * For each argument.
531 	 */
532 	for (i = 0, adp = argp; i < nargs; i++, adp++) {
533 		rval->sys_rval1 = i;		/* in case of error */
534 		if (adp->arg_type != AT_BYVAL &&
535 		    adp->arg_inout != AI_INPUT) {
536 			/* copy output byref parameter from process */
537 			if (Pread(P, adp->arg_object, adp->arg_size,
538 			    (uintptr_t)adp->arg_value) != adp->arg_size)
539 				goto bad25;
540 		}
541 	}
542 
543 	if (Psyscall_copyoutargs(P, nargs, argp, ap) != 0)
544 		goto bad26;
545 
546 	/*
547 	 * Get the return values from the syscall.
548 	 */
549 	if (P->status.pr_lwp.pr_errno) {	/* error return */
550 		error = P->status.pr_lwp.pr_errno;
551 		rval->sys_rval1 = -1L;
552 		rval->sys_rval2 = -1L;
553 		Pdprintf("Psyscall(%d) fails with errno %d\n",
554 		    sysindex, error);
555 	} else {				/* normal return */
556 		rval->sys_rval1 = P->status.pr_lwp.pr_rval1;
557 		rval->sys_rval2 = P->status.pr_lwp.pr_rval2;
558 		Pdprintf("Psyscall(%d) returns 0x%lx 0x%lx\n", sysindex,
559 		    P->status.pr_lwp.pr_rval1, P->status.pr_lwp.pr_rval2);
560 	}
561 
562 	goto out;
563 
564 bad26:	Perr++;
565 bad25:	Perr++;
566 bad24:	Perr++;
567 bad23:	Perr++;
568 bad22:	Perr++;
569 bad21:	Perr++;
570 	Perr++;
571 	Perr++;
572 bad18:	Perr++;
573 bad17:	Perr++;
574 	Perr++;
575 	Perr++;
576 	Perr++;
577 	Perr++;
578 	Perr++;
579 	Perr++;
580 bad10:	Perr++;
581 #ifndef _LP64
582 bad9:
583 #endif
584 	Perr++;
585 bad8:	Perr++;
586 bad7:	Perr++;
587 bad6:	Perr++;
588 bad5:	Perr++;
589 bad4:	Perr++;
590 bad3:	Perr++;
591 bad2:	Perr++;
592 bad1:	Perr++;
593 	error = -1;
594 	Pdprintf("Psyscall(%d) fails with local error %d\n", sysindex, Perr);
595 
596 out:
597 	/*
598 	 * Destroy the /proc agent LWP now (or just bump down the ref count).
599 	 */
600 	if (agent_created) {
601 		if (P->state != PS_UNDEAD) {
602 			P->status = save_pstatus;
603 			P->flags |= SETREGS;
604 			Psync(P);
605 		}
606 		Pdestroy_agent(P);
607 	}
608 
609 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
610 	return (error);
611 }
612