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