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