Psyscall.c revision 2712:f74a135872bc
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#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <ctype.h>
32#include <fcntl.h>
33#include <string.h>
34#include <memory.h>
35#include <errno.h>
36#include <dirent.h>
37#include <limits.h>
38#include <signal.h>
39#include <sys/types.h>
40#include <sys/uio.h>
41#include <sys/stat.h>
42#include <sys/resource.h>
43#include <sys/param.h>
44#include <sys/stack.h>
45#include <sys/fault.h>
46#include <sys/syscall.h>
47#include <sys/sysmacros.h>
48
49#include "libproc.h"
50#include "Pcontrol.h"
51#include "Putil.h"
52#include "P32ton.h"
53#include "Pisadep.h"
54
55extern sigset_t blockable_sigs;
56
57static void
58Pabort_agent(struct ps_prochandle *P)
59{
60	int sysnum = P->status.pr_lwp.pr_syscall;
61	int stop;
62
63	dprintf("agent LWP is asleep in syscall %d\n", sysnum);
64	(void) Pstop(P, 0);
65	stop = Psysexit(P, sysnum, TRUE);
66
67	if (Psetrun(P, 0, PRSABORT) == 0) {
68		while (Pwait(P, 0) == -1 && errno == EINTR)
69			continue;
70		(void) Psysexit(P, sysnum, stop);
71		dprintf("agent LWP system call aborted\n");
72	}
73}
74
75/*
76 * Create the /proc agent LWP for further operations.
77 */
78int
79Pcreate_agent(struct ps_prochandle *P)
80{
81	int fd;
82	char pathname[PATH_MAX];
83	char *fname;
84	struct {
85		long	cmd;
86		prgregset_t regs;
87	} cmd;
88
89	/*
90	 * If not first reference, we already have the /proc agent LWP active.
91	 */
92	if (P->agentcnt > 0) {
93		P->agentcnt++;
94		return (0);
95	}
96
97	/*
98	 * The agent is not available for use as a mortician or as an
99	 * obstetrician.
100	 */
101	if (P->state == PS_DEAD || P->state == PS_UNDEAD ||
102	    P->state == PS_IDLE) {
103		errno = ENOENT;
104		return (-1);
105	}
106
107	/*
108	 * Create the special /proc agent LWP if it doesn't already exist.
109	 * Give it the registers of the representative LWP.
110	 */
111	(void) Pstop(P, 0);
112	Psync(P);
113	if (!(P->status.pr_lwp.pr_flags & PR_AGENT)) {
114		cmd.cmd = PCAGENT;
115		(void) memcpy(&cmd.regs, &P->status.pr_lwp.pr_reg[0],
116		    sizeof (P->status.pr_lwp.pr_reg));
117		if (write(P->ctlfd, &cmd, sizeof (cmd)) != sizeof (cmd))
118			goto bad;
119	}
120
121	/* refresh the process status */
122	(void) Pstopstatus(P, PCNULL, 0);
123
124	/* open the agent LWP files */
125	(void) snprintf(pathname, sizeof (pathname), "%s/%d/lwp/agent/",
126	    procfs_path, (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
166bad:
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 */
182void
183Pdestroy_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 */
227static int
228execute(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);
282bad:
283	return (-1);
284}
285
286
287/*
288 * Perform system call in controlled process.
289 */
290int
291Psyscall(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
511bad26:	Perr++;
512bad25:	Perr++;
513bad24:	Perr++;
514bad23:	Perr++;
515bad22:	Perr++;
516bad21:	Perr++;
517	Perr++;
518	Perr++;
519bad18:	Perr++;
520bad17:	Perr++;
521	Perr++;
522	Perr++;
523	Perr++;
524	Perr++;
525	Perr++;
526	Perr++;
527bad10:	Perr++;
528bad9:	Perr++;
529bad8:	Perr++;
530bad7:	Perr++;
531bad6:	Perr++;
532bad5:	Perr++;
533bad4:	Perr++;
534bad3:	Perr++;
535bad2:	Perr++;
536bad1:	Perr++;
537	error = -1;
538	dprintf("Psyscall(%d) fails with local error %d\n", sysindex, Perr);
539
540out:
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