xref: /illumos-gate/usr/src/lib/libproc/common/Psyscall.c (revision a5f69788de7ac07553de47f7fec8c05a9a94c105)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
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[100];
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) sprintf(pathname, "/proc/%d/lwp/agent/", (int)P->pid);
127 	fname = pathname + strlen(pathname);
128 	(void) set_minfd();
129 
130 	/*
131 	 * It is difficult to know how to recover from the two errors
132 	 * that follow.  The agent LWP exists and we need to kill it,
133 	 * but we can't because we need it active in order to kill it.
134 	 * We just hope that these failures never occur.
135 	 */
136 	(void) strcpy(fname, "lwpstatus");
137 	if ((fd = open(pathname, O_RDONLY)) < 0 ||
138 	    (fd = dupfd(fd, 0)) < 0)
139 		goto bad;
140 	P->agentstatfd = fd;
141 
142 	(void) strcpy(fname, "lwpctl");
143 	if ((fd = open(pathname, O_WRONLY)) < 0 ||
144 	    (fd = dupfd(fd, 0)) < 0)
145 		goto bad;
146 	P->agentctlfd = fd;
147 
148 	/*
149 	 * If the agent is currently asleep in a system call, attempt
150 	 * to abort the system call so it's ready to serve.
151 	 */
152 	if (P->status.pr_lwp.pr_flags & PR_ASLEEP) {
153 		dprintf("Pcreate_agent: aborting agent syscall\n");
154 		Pabort_agent(P);
155 	}
156 
157 	/* get the agent LWP status */
158 	P->agentcnt++;
159 	if (Pstopstatus(P, PCNULL, 0) != 0) {
160 		Pdestroy_agent(P);
161 		return (-1);
162 	}
163 
164 	return (0);
165 
166 bad:
167 	if (P->agentstatfd >= 0)
168 		(void) close(P->agentstatfd);
169 	if (P->agentctlfd >= 0)
170 		(void) close(P->agentctlfd);
171 	P->agentstatfd = -1;
172 	P->agentctlfd = -1;
173 	/* refresh the process status */
174 	(void) Pstopstatus(P, PCNULL, 0);
175 	return (-1);
176 }
177 
178 /*
179  * Decrement the /proc agent agent reference count.
180  * On last reference, destroy the agent.
181  */
182 void
183 Pdestroy_agent(struct ps_prochandle *P)
184 {
185 	if (P->agentcnt > 1)
186 		P->agentcnt--;
187 	else {
188 		int flags;
189 
190 		Psync(P); /* Flush out any pending changes */
191 
192 		(void) Pstopstatus(P, PCNULL, 0);
193 		flags = P->status.pr_lwp.pr_flags;
194 
195 		/*
196 		 * If the agent is currently asleep in a system call, attempt
197 		 * to abort the system call so we can terminate the agent.
198 		 */
199 		if ((flags & (PR_AGENT|PR_ASLEEP)) == (PR_AGENT|PR_ASLEEP)) {
200 			dprintf("Pdestroy_agent: aborting agent syscall\n");
201 			Pabort_agent(P);
202 		}
203 
204 		/*
205 		 * The agent itself is destroyed by forcing it to execute
206 		 * the _lwp_exit(2) system call.  Close our agent descriptors
207 		 * regardless of whether this is successful.
208 		 */
209 		(void) pr_lwp_exit(P);
210 		(void) close(P->agentctlfd);
211 		(void) close(P->agentstatfd);
212 		P->agentctlfd = -1;
213 		P->agentstatfd = -1;
214 		P->agentcnt = 0;
215 
216 		/*
217 		 * Now that (hopefully) the agent has exited, refresh the
218 		 * status: the representative LWP is no longer the agent.
219 		 */
220 		(void) Pstopstatus(P, PCNULL, 0);
221 	}
222 }
223 
224 /*
225  * Execute the syscall instruction.
226  */
227 static int
228 execute(struct ps_prochandle *P, int sysindex)
229 {
230 	int ctlfd = (P->agentctlfd >= 0)? P->agentctlfd : P->ctlfd;
231 	int washeld = FALSE;
232 	sigset_t hold;		/* mask of held signals */
233 	int cursig;
234 	struct {
235 		long cmd;
236 		siginfo_t siginfo;
237 	} ctl;
238 	int sentry;		/* old value of stop-on-syscall-entry */
239 
240 	sentry = Psysentry(P, sysindex, TRUE);	/* set stop-on-syscall-entry */
241 
242 	/*
243 	 * If not already blocked, block all signals now.
244 	 */
245 	if (memcmp(&P->status.pr_lwp.pr_lwphold, &blockable_sigs,
246 	    sizeof (sigset_t)) != 0) {
247 		hold = P->status.pr_lwp.pr_lwphold;
248 		P->status.pr_lwp.pr_lwphold = blockable_sigs;
249 		P->flags |= SETHOLD;
250 		washeld = TRUE;
251 	}
252 
253 	/*
254 	 * If there is a current signal, remember it and cancel it.
255 	 */
256 	if ((cursig = P->status.pr_lwp.pr_cursig) != 0) {
257 		ctl.cmd = PCSSIG;
258 		ctl.siginfo = P->status.pr_lwp.pr_info;
259 	}
260 
261 	if (Psetrun(P, 0, PRCSIG | PRCFAULT) == -1)
262 		goto bad;
263 
264 	while (P->state == PS_RUN) {
265 		(void) Pwait(P, 0);
266 	}
267 	if (P->state != PS_STOP)
268 		goto bad;
269 
270 	if (cursig)				/* restore cursig */
271 		(void) write(ctlfd, &ctl, sizeof (ctl));
272 	if (washeld) {		/* restore the signal mask if we set it */
273 		P->status.pr_lwp.pr_lwphold = hold;
274 		P->flags |= SETHOLD;
275 	}
276 
277 	(void) Psysentry(P, sysindex, sentry);	/* restore sysentry stop */
278 
279 	if (P->status.pr_lwp.pr_why  == PR_SYSENTRY &&
280 	    P->status.pr_lwp.pr_what == sysindex)
281 		return (0);
282 bad:
283 	return (-1);
284 }
285 
286 
287 /*
288  * Perform system call in controlled process.
289  */
290 int
291 Psyscall(struct ps_prochandle *P,
292 	sysret_t *rval,		/* syscall return values */
293 	int sysindex,		/* system call index */
294 	uint_t nargs,		/* number of arguments to system call */
295 	argdes_t *argp)		/* argument descriptor array */
296 {
297 	int agent_created = FALSE;
298 	pstatus_t save_pstatus;
299 	argdes_t *adp;			/* pointer to argument descriptor */
300 	int i;				/* general index value */
301 	int model;			/* data model */
302 	int error = 0;			/* syscall errno */
303 	int Perr = 0;			/* local error number */
304 	int sexit;			/* old value of stop-on-syscall-exit */
305 	prgreg_t sp;			/* adjusted stack pointer */
306 	prgreg_t ap;			/* adjusted argument pointer */
307 	sigset_t unblock;
308 
309 	(void) sigprocmask(SIG_BLOCK, &blockable_sigs, &unblock);
310 
311 	rval->sys_rval1 = 0;		/* initialize return values */
312 	rval->sys_rval2 = 0;
313 
314 	if (sysindex <= 0 || sysindex > PRMAXSYS || nargs > MAXARGS)
315 		goto bad1;	/* programming error */
316 
317 	if (P->state == PS_DEAD || P->state == PS_UNDEAD || P->state == PS_IDLE)
318 		goto bad1;	/* dead processes can't perform system calls */
319 
320 	model = P->status.pr_dmodel;
321 #ifndef _LP64
322 	/* We must be a 64-bit process to deal with a 64-bit process */
323 	if (model == PR_MODEL_LP64)
324 		goto bad9;
325 #endif
326 
327 	/*
328 	 * Create the /proc agent LWP in the process to do all the work.
329 	 * (It may already exist; nested create/destroy is permitted
330 	 * by virtue of the reference count.)
331 	 */
332 	if (Pcreate_agent(P) != 0)
333 		goto bad8;
334 
335 	/*
336 	 * Save agent's status to restore on exit.
337 	 */
338 	agent_created = TRUE;
339 	save_pstatus = P->status;
340 
341 	if (P->state != PS_STOP ||		/* check state of LWP */
342 	    (P->status.pr_flags & PR_ASLEEP))
343 		goto bad2;
344 
345 	if (Pscantext(P))			/* bad text ? */
346 		goto bad3;
347 
348 	/*
349 	 * Validate arguments and compute the stack frame parameters.
350 	 * Begin with the current stack pointer.
351 	 */
352 #ifdef _LP64
353 	if (model == PR_MODEL_LP64) {
354 		sp = P->status.pr_lwp.pr_reg[R_SP] + STACK_BIAS;
355 		sp = PSTACK_ALIGN64(sp);
356 	} else {
357 #endif
358 		sp = (uint32_t)P->status.pr_lwp.pr_reg[R_SP];
359 		sp = PSTACK_ALIGN32(sp);
360 #ifdef _LP64
361 	}
362 #endif
363 
364 	/*
365 	 * For each AT_BYREF argument, compute the necessary
366 	 * stack space and the object's stack address.
367 	 */
368 	for (i = 0, adp = argp; i < nargs; i++, adp++) {
369 		rval->sys_rval1 = i;		/* in case of error */
370 		switch (adp->arg_type) {
371 		default:			/* programming error */
372 			goto bad4;
373 		case AT_BYVAL:			/* simple argument */
374 			break;
375 		case AT_BYREF:			/* must allocate space */
376 			switch (adp->arg_inout) {
377 			case AI_INPUT:
378 			case AI_OUTPUT:
379 			case AI_INOUT:
380 				if (adp->arg_object == NULL)
381 					goto bad5;	/* programming error */
382 				break;
383 			default:		/* programming error */
384 				goto bad6;
385 			}
386 			/* allocate stack space for BYREF argument */
387 			if (adp->arg_size == 0 || adp->arg_size > MAXARGL)
388 				goto bad7;	/* programming error */
389 #ifdef _LP64
390 			if (model == PR_MODEL_LP64)
391 				sp = PSTACK_ALIGN64(sp - adp->arg_size);
392 			else
393 #endif
394 				sp = PSTACK_ALIGN32(sp - adp->arg_size);
395 			adp->arg_value = sp;	/* stack address for object */
396 			break;
397 		}
398 	}
399 	rval->sys_rval1 = 0;			/* in case of error */
400 	/*
401 	 * Point of no return.
402 	 * Perform the system call entry, adjusting %sp.
403 	 * This moves the LWP to the stopped-on-syscall-entry state
404 	 * just before the arguments to the system call are fetched.
405 	 */
406 	ap = Psyscall_setup(P, nargs, sysindex, sp);
407 	P->flags |= SETREGS;	/* set registers before continuing */
408 	dprintf("Psyscall(): execute(sysindex = %d)\n", sysindex);
409 
410 	/*
411 	 * Execute the syscall instruction and stop on syscall entry.
412 	 */
413 	if (execute(P, sysindex) != 0 ||
414 	    (!Pissyscall(P, P->status.pr_lwp.pr_reg[R_PC]) &&
415 	    !Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)))
416 		goto bad10;
417 
418 	dprintf("Psyscall(): copying arguments\n");
419 
420 	/*
421 	 * The LWP is stopped at syscall entry.
422 	 * Copy objects to stack frame for each argument.
423 	 */
424 	for (i = 0, adp = argp; i < nargs; i++, adp++) {
425 		rval->sys_rval1 = i;		/* in case of error */
426 		if (adp->arg_type != AT_BYVAL &&
427 		    adp->arg_inout != AI_OUTPUT) {
428 			/* copy input byref parameter to process */
429 			if (Pwrite(P, adp->arg_object, adp->arg_size,
430 			    (uintptr_t)adp->arg_value) != adp->arg_size)
431 				goto bad17;
432 		}
433 	}
434 	rval->sys_rval1 = 0;			/* in case of error */
435 	if (Psyscall_copyinargs(P, nargs, argp, ap) != 0)
436 		goto bad18;
437 
438 	/*
439 	 * Complete the system call.
440 	 * This moves the LWP to the stopped-on-syscall-exit state.
441 	 */
442 	dprintf("Psyscall(): set running at sysentry\n");
443 
444 	sexit = Psysexit(P, sysindex, TRUE);	/* catch this syscall exit */
445 	do {
446 		if (Psetrun(P, 0, 0) == -1)
447 			goto bad21;
448 		while (P->state == PS_RUN)
449 			(void) Pwait(P, 0);
450 	} while (P->state == PS_STOP && P->status.pr_lwp.pr_why != PR_SYSEXIT);
451 	(void) Psysexit(P, sysindex, sexit);	/* restore original setting */
452 
453 	/*
454 	 * If the system call was _lwp_exit(), we expect that our last call
455 	 * to Pwait() will yield ENOENT because the LWP no longer exists.
456 	 */
457 	if (sysindex == SYS_lwp_exit && errno == ENOENT) {
458 		dprintf("Psyscall(): _lwp_exit successful\n");
459 		rval->sys_rval1 = rval->sys_rval2 = 0;
460 		goto out;
461 	}
462 
463 	if (P->state != PS_STOP || P->status.pr_lwp.pr_why != PR_SYSEXIT)
464 		goto bad22;
465 
466 	if (P->status.pr_lwp.pr_what != sysindex)
467 		goto bad23;
468 
469 	if (!Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC], NULL)) {
470 		dprintf("Pissyscall_prev() failed\n");
471 		goto bad24;
472 	}
473 
474 	dprintf("Psyscall(): caught at sysexit\n");
475 
476 	/*
477 	 * For each argument.
478 	 */
479 	for (i = 0, adp = argp; i < nargs; i++, adp++) {
480 		rval->sys_rval1 = i;		/* in case of error */
481 		if (adp->arg_type != AT_BYVAL &&
482 		    adp->arg_inout != AI_INPUT) {
483 			/* copy output byref parameter from process */
484 			if (Pread(P, adp->arg_object, adp->arg_size,
485 			    (uintptr_t)adp->arg_value) != adp->arg_size)
486 				goto bad25;
487 		}
488 	}
489 
490 	if (Psyscall_copyoutargs(P, nargs, argp, ap) != 0)
491 		goto bad26;
492 
493 	/*
494 	 * Get the return values from the syscall.
495 	 */
496 	if (P->status.pr_lwp.pr_errno) {	/* error return */
497 		error = P->status.pr_lwp.pr_errno;
498 		rval->sys_rval1 = -1L;
499 		rval->sys_rval2 = -1L;
500 		dprintf("Psyscall(%d) fails with errno %d\n",
501 		    sysindex, error);
502 	} else {				/* normal return */
503 		rval->sys_rval1 = P->status.pr_lwp.pr_rval1;
504 		rval->sys_rval2 = P->status.pr_lwp.pr_rval2;
505 		dprintf("Psyscall(%d) returns 0x%lx 0x%lx\n", sysindex,
506 		    P->status.pr_lwp.pr_rval1, P->status.pr_lwp.pr_rval2);
507 	}
508 
509 	goto out;
510 
511 bad26:	Perr++;
512 bad25:	Perr++;
513 bad24:	Perr++;
514 bad23:	Perr++;
515 bad22:	Perr++;
516 bad21:	Perr++;
517 	Perr++;
518 	Perr++;
519 bad18:	Perr++;
520 bad17:	Perr++;
521 	Perr++;
522 	Perr++;
523 	Perr++;
524 	Perr++;
525 	Perr++;
526 	Perr++;
527 bad10:	Perr++;
528 bad9:	Perr++;
529 bad8:	Perr++;
530 bad7:	Perr++;
531 bad6:	Perr++;
532 bad5:	Perr++;
533 bad4:	Perr++;
534 bad3:	Perr++;
535 bad2:	Perr++;
536 bad1:	Perr++;
537 	error = -1;
538 	dprintf("Psyscall(%d) fails with local error %d\n", sysindex, Perr);
539 
540 out:
541 	/*
542 	 * Destroy the /proc agent LWP now (or just bump down the ref count).
543 	 */
544 	if (agent_created) {
545 		if (P->state != PS_UNDEAD) {
546 			P->status = save_pstatus;
547 			P->flags |= SETREGS;
548 			Psync(P);
549 		}
550 		Pdestroy_agent(P);
551 	}
552 
553 	(void) sigprocmask(SIG_SETMASK, &unblock, NULL);
554 	return (error);
555 }
556