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