1 /*- 2 * Copyright (c) 2000 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/param.h> 32 #include <sys/mman.h> 33 #include <sys/proc.h> 34 #include <sys/sysproto.h> 35 #include <sys/systm.h> 36 #include <sys/unistd.h> 37 #include <sys/resource.h> 38 #include <sys/resourcevar.h> 39 40 #include <machine/frame.h> 41 #include <machine/psl.h> 42 #include <machine/segments.h> 43 #include <machine/sysarch.h> 44 45 #include <vm/vm.h> 46 #include <sys/lock.h> 47 #include <vm/pmap.h> 48 #include <vm/vm_map.h> 49 50 #include <i386/linux/linux.h> 51 #include <i386/linux/linux_proto.h> 52 #include <compat/linux/linux_ipc.h> 53 #include <compat/linux/linux_signal.h> 54 #include <compat/linux/linux_util.h> 55 56 struct linux_descriptor { 57 unsigned int entry_number; 58 unsigned long base_addr; 59 unsigned int limit; 60 unsigned int seg_32bit:1; 61 unsigned int contents:2; 62 unsigned int read_exec_only:1; 63 unsigned int limit_in_pages:1; 64 unsigned int seg_not_present:1; 65 unsigned int useable:1; 66 }; 67 68 struct linux_select_argv { 69 int nfds; 70 fd_set *readfds; 71 fd_set *writefds; 72 fd_set *exceptfds; 73 struct timeval *timeout; 74 }; 75 76 int 77 linux_to_bsd_sigaltstack(int lsa) 78 { 79 int bsa = 0; 80 81 if (lsa & LINUX_SS_DISABLE) 82 bsa |= SS_DISABLE; 83 if (lsa & LINUX_SS_ONSTACK) 84 bsa |= SS_ONSTACK; 85 return (bsa); 86 } 87 88 int 89 bsd_to_linux_sigaltstack(int bsa) 90 { 91 int lsa = 0; 92 93 if (bsa & SS_DISABLE) 94 lsa |= LINUX_SS_DISABLE; 95 if (bsa & SS_ONSTACK) 96 lsa |= LINUX_SS_ONSTACK; 97 return (lsa); 98 } 99 100 int 101 linux_execve(struct proc *p, struct linux_execve_args *args) 102 { 103 struct execve_args bsd; 104 caddr_t sg; 105 106 sg = stackgap_init(); 107 CHECKALTEXIST(p, &sg, args->path); 108 109 #ifdef DEBUG 110 if (ldebug(execve)) 111 printf(ARGS(execve, "%s"), args->path); 112 #endif 113 114 bsd.fname = args->path; 115 bsd.argv = args->argp; 116 bsd.envv = args->envp; 117 return (execve(p, &bsd)); 118 } 119 120 int 121 linux_ipc(struct proc *p, struct linux_ipc_args *args) 122 { 123 switch (args->what) { 124 case LINUX_SEMOP: 125 return (linux_semop(p, args)); 126 case LINUX_SEMGET: 127 return (linux_semget(p, args)); 128 case LINUX_SEMCTL: 129 return (linux_semctl(p, args)); 130 case LINUX_MSGSND: 131 return (linux_msgsnd(p, args)); 132 case LINUX_MSGRCV: 133 return (linux_msgrcv(p, args)); 134 case LINUX_MSGGET: 135 return (linux_msgget(p, args)); 136 case LINUX_MSGCTL: 137 return (linux_msgctl(p, args)); 138 case LINUX_SHMAT: 139 return (linux_shmat(p, args)); 140 case LINUX_SHMDT: 141 return (linux_shmdt(p, args)); 142 case LINUX_SHMGET: 143 return (linux_shmget(p, args)); 144 case LINUX_SHMCTL: 145 return (linux_shmctl(p, args)); 146 } 147 148 uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); 149 return (ENOSYS); 150 } 151 152 int 153 linux_select(struct proc *p, struct linux_select_args *args) 154 { 155 struct linux_select_argv linux_args; 156 struct linux_newselect_args newsel; 157 int error; 158 159 #ifdef SELECT_DEBUG 160 if (ldebug(select)) 161 printf(ARGS(select, "%x"), args->ptr); 162 #endif 163 164 error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 165 if (error) 166 return (error); 167 168 newsel.nfds = linux_args.nfds; 169 newsel.readfds = linux_args.readfds; 170 newsel.writefds = linux_args.writefds; 171 newsel.exceptfds = linux_args.exceptfds; 172 newsel.timeout = linux_args.timeout; 173 return (linux_newselect(p, &newsel)); 174 } 175 176 int 177 linux_fork(struct proc *p, struct linux_fork_args *args) 178 { 179 int error; 180 181 #ifdef DEBUG 182 if (ldebug(fork)) 183 printf(ARGS(fork, "")); 184 #endif 185 186 if ((error = fork(p, (struct fork_args *)args)) != 0) 187 return (error); 188 189 if (p->p_retval[1] == 1) 190 p->p_retval[0] = 0; 191 return (0); 192 } 193 194 int 195 linux_vfork(struct proc *p, struct linux_vfork_args *args) 196 { 197 int error; 198 199 #ifdef DEBUG 200 if (ldebug(vfork)) 201 printf(ARGS(vfork, "")); 202 #endif 203 204 if ((error = vfork(p, (struct vfork_args *)args)) != 0) 205 return (error); 206 /* Are we the child? */ 207 if (p->p_retval[1] == 1) 208 p->p_retval[0] = 0; 209 return (0); 210 } 211 212 #define CLONE_VM 0x100 213 #define CLONE_FS 0x200 214 #define CLONE_FILES 0x400 215 #define CLONE_SIGHAND 0x800 216 #define CLONE_PID 0x1000 217 218 int 219 linux_clone(struct proc *p, struct linux_clone_args *args) 220 { 221 int error, ff = RFPROC | RFSTOPPED; 222 struct proc *p2; 223 int exit_signal; 224 vm_offset_t start; 225 226 #ifdef DEBUG 227 if (ldebug(clone)) { 228 printf(ARGS(clone, "flags %x, stack %x"), 229 (unsigned int)args->flags, (unsigned int)args->stack); 230 if (args->flags & CLONE_PID) 231 printf(LMSG("CLONE_PID not yet supported")); 232 } 233 #endif 234 235 if (!args->stack) 236 return (EINVAL); 237 238 exit_signal = args->flags & 0x000000ff; 239 if (exit_signal >= LINUX_NSIG) 240 return (EINVAL); 241 242 if (exit_signal <= LINUX_SIGTBLSZ) 243 exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)]; 244 245 /* RFTHREAD probably not necessary here, but it shouldn't hurt */ 246 ff |= RFTHREAD; 247 248 if (args->flags & CLONE_VM) 249 ff |= RFMEM; 250 if (args->flags & CLONE_SIGHAND) 251 ff |= RFSIGSHARE; 252 if (!(args->flags & CLONE_FILES)) 253 ff |= RFFDG; 254 255 error = 0; 256 start = 0; 257 258 if ((error = fork1(p, ff, &p2)) != 0) 259 return (error); 260 261 PROC_LOCK(p2); 262 p2->p_sigparent = exit_signal; 263 PROC_UNLOCK(p2); 264 p2->p_md.md_regs->tf_esp = (unsigned int)args->stack; 265 266 #ifdef DEBUG 267 if (ldebug(clone)) 268 printf(LMSG("clone: successful rfork to %ld"), 269 (long)p2->p_pid); 270 #endif 271 272 /* 273 * Make this runnable after we are finished with it. 274 */ 275 mtx_lock_spin(&sched_lock); 276 p2->p_stat = SRUN; 277 setrunqueue(p2); 278 mtx_unlock_spin(&sched_lock); 279 280 p->p_retval[0] = p2->p_pid; 281 p->p_retval[1] = 0; 282 return (0); 283 } 284 285 /* XXX move */ 286 struct linux_mmap_argv { 287 linux_caddr_t addr; 288 int len; 289 int prot; 290 int flags; 291 int fd; 292 int pos; 293 }; 294 295 #define STACK_SIZE (2 * 1024 * 1024) 296 #define GUARD_SIZE (4 * PAGE_SIZE) 297 298 int 299 linux_mmap(struct proc *p, struct linux_mmap_args *args) 300 { 301 struct mmap_args /* { 302 caddr_t addr; 303 size_t len; 304 int prot; 305 int flags; 306 int fd; 307 long pad; 308 off_t pos; 309 } */ bsd_args; 310 int error; 311 struct linux_mmap_argv linux_args; 312 313 error = copyin(args->ptr, &linux_args, sizeof(linux_args)); 314 if (error) 315 return (error); 316 317 #ifdef DEBUG 318 if (ldebug(mmap)) 319 printf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"), 320 (void *)linux_args.addr, linux_args.len, linux_args.prot, 321 linux_args.flags, linux_args.fd, linux_args.pos); 322 #endif 323 324 bsd_args.flags = 0; 325 if (linux_args.flags & LINUX_MAP_SHARED) 326 bsd_args.flags |= MAP_SHARED; 327 if (linux_args.flags & LINUX_MAP_PRIVATE) 328 bsd_args.flags |= MAP_PRIVATE; 329 if (linux_args.flags & LINUX_MAP_FIXED) 330 bsd_args.flags |= MAP_FIXED; 331 if (linux_args.flags & LINUX_MAP_ANON) 332 bsd_args.flags |= MAP_ANON; 333 else 334 bsd_args.flags |= MAP_NOSYNC; 335 if (linux_args.flags & LINUX_MAP_GROWSDOWN) { 336 bsd_args.flags |= MAP_STACK; 337 338 /* The linux MAP_GROWSDOWN option does not limit auto 339 * growth of the region. Linux mmap with this option 340 * takes as addr the inital BOS, and as len, the initial 341 * region size. It can then grow down from addr without 342 * limit. However, linux threads has an implicit internal 343 * limit to stack size of STACK_SIZE. Its just not 344 * enforced explicitly in linux. But, here we impose 345 * a limit of (STACK_SIZE - GUARD_SIZE) on the stack 346 * region, since we can do this with our mmap. 347 * 348 * Our mmap with MAP_STACK takes addr as the maximum 349 * downsize limit on BOS, and as len the max size of 350 * the region. It them maps the top SGROWSIZ bytes, 351 * and autgrows the region down, up to the limit 352 * in addr. 353 * 354 * If we don't use the MAP_STACK option, the effect 355 * of this code is to allocate a stack region of a 356 * fixed size of (STACK_SIZE - GUARD_SIZE). 357 */ 358 359 /* This gives us TOS */ 360 bsd_args.addr = linux_args.addr + linux_args.len; 361 362 if (bsd_args.addr > p->p_vmspace->vm_maxsaddr) { 363 /* Some linux apps will attempt to mmap 364 * thread stacks near the top of their 365 * address space. If their TOS is greater 366 * than vm_maxsaddr, vm_map_growstack() 367 * will confuse the thread stack with the 368 * process stack and deliver a SEGV if they 369 * attempt to grow the thread stack past their 370 * current stacksize rlimit. To avoid this, 371 * adjust vm_maxsaddr upwards to reflect 372 * the current stacksize rlimit rather 373 * than the maximum possible stacksize. 374 * It would be better to adjust the 375 * mmap'ed region, but some apps do not check 376 * mmap's return value. 377 */ 378 mtx_assert(&Giant, MA_OWNED); 379 p->p_vmspace->vm_maxsaddr = (char *)USRSTACK - 380 p->p_rlimit[RLIMIT_STACK].rlim_cur; 381 } 382 383 /* This gives us our maximum stack size */ 384 if (linux_args.len > STACK_SIZE - GUARD_SIZE) 385 bsd_args.len = linux_args.len; 386 else 387 bsd_args.len = STACK_SIZE - GUARD_SIZE; 388 389 /* This gives us a new BOS. If we're using VM_STACK, then 390 * mmap will just map the top SGROWSIZ bytes, and let 391 * the stack grow down to the limit at BOS. If we're 392 * not using VM_STACK we map the full stack, since we 393 * don't have a way to autogrow it. 394 */ 395 bsd_args.addr -= bsd_args.len; 396 } else { 397 bsd_args.addr = linux_args.addr; 398 bsd_args.len = linux_args.len; 399 } 400 401 bsd_args.prot = linux_args.prot | PROT_READ; /* always required */ 402 if (linux_args.flags & LINUX_MAP_ANON) 403 bsd_args.fd = -1; 404 else 405 bsd_args.fd = linux_args.fd; 406 bsd_args.pos = linux_args.pos; 407 bsd_args.pad = 0; 408 409 #ifdef DEBUG 410 if (ldebug(mmap)) 411 printf("-> (%p, %d, %d, 0x%08x, %d, %d)\n", 412 (void *)bsd_args.addr, bsd_args.len, bsd_args.prot, 413 bsd_args.flags, bsd_args.fd, (int)bsd_args.pos); 414 #endif 415 416 return (mmap(p, &bsd_args)); 417 } 418 419 int 420 linux_pipe(struct proc *p, struct linux_pipe_args *args) 421 { 422 int error; 423 int reg_edx; 424 425 #ifdef DEBUG 426 if (ldebug(pipe)) 427 printf(ARGS(pipe, "*")); 428 #endif 429 430 reg_edx = p->p_retval[1]; 431 error = pipe(p, 0); 432 if (error) { 433 p->p_retval[1] = reg_edx; 434 return (error); 435 } 436 437 error = copyout(p->p_retval, args->pipefds, 2*sizeof(int)); 438 if (error) { 439 p->p_retval[1] = reg_edx; 440 return (error); 441 } 442 443 p->p_retval[1] = reg_edx; 444 p->p_retval[0] = 0; 445 return (0); 446 } 447 448 int 449 linux_ioperm(struct proc *p, struct linux_ioperm_args *args) 450 { 451 struct sysarch_args sa; 452 struct i386_ioperm_args *iia; 453 caddr_t sg; 454 455 sg = stackgap_init(); 456 iia = stackgap_alloc(&sg, sizeof(struct i386_ioperm_args)); 457 iia->start = args->start; 458 iia->length = args->length; 459 iia->enable = args->enable; 460 sa.op = I386_SET_IOPERM; 461 sa.parms = (char *)iia; 462 return (sysarch(p, &sa)); 463 } 464 465 int 466 linux_iopl(struct proc *p, struct linux_iopl_args *args) 467 { 468 int error; 469 470 if (args->level < 0 || args->level > 3) 471 return (EINVAL); 472 if ((error = suser(p)) != 0) 473 return (error); 474 if (securelevel > 0) 475 return (EPERM); 476 p->p_md.md_regs->tf_eflags = (p->p_md.md_regs->tf_eflags & ~PSL_IOPL) | 477 (args->level * (PSL_IOPL / 3)); 478 return (0); 479 } 480 481 int 482 linux_modify_ldt(p, uap) 483 struct proc *p; 484 struct linux_modify_ldt_args *uap; 485 { 486 int error; 487 caddr_t sg; 488 struct sysarch_args args; 489 struct i386_ldt_args *ldt; 490 struct linux_descriptor ld; 491 union descriptor *desc; 492 493 sg = stackgap_init(); 494 495 if (uap->ptr == NULL) 496 return (EINVAL); 497 498 switch (uap->func) { 499 case 0x00: /* read_ldt */ 500 ldt = stackgap_alloc(&sg, sizeof(*ldt)); 501 ldt->start = 0; 502 ldt->descs = uap->ptr; 503 ldt->num = uap->bytecount / sizeof(union descriptor); 504 args.op = I386_GET_LDT; 505 args.parms = (char*)ldt; 506 error = sysarch(p, &args); 507 p->p_retval[0] *= sizeof(union descriptor); 508 break; 509 case 0x01: /* write_ldt */ 510 case 0x11: /* write_ldt */ 511 if (uap->bytecount != sizeof(ld)) 512 return (EINVAL); 513 514 error = copyin(uap->ptr, &ld, sizeof(ld)); 515 if (error) 516 return (error); 517 518 ldt = stackgap_alloc(&sg, sizeof(*ldt)); 519 desc = stackgap_alloc(&sg, sizeof(*desc)); 520 ldt->start = ld.entry_number; 521 ldt->descs = desc; 522 ldt->num = 1; 523 desc->sd.sd_lolimit = (ld.limit & 0x0000ffff); 524 desc->sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16; 525 desc->sd.sd_lobase = (ld.base_addr & 0x00ffffff); 526 desc->sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24; 527 desc->sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) | 528 (ld.contents << 2); 529 desc->sd.sd_dpl = 3; 530 desc->sd.sd_p = (ld.seg_not_present ^ 1); 531 desc->sd.sd_xx = 0; 532 desc->sd.sd_def32 = ld.seg_32bit; 533 desc->sd.sd_gran = ld.limit_in_pages; 534 args.op = I386_SET_LDT; 535 args.parms = (char*)ldt; 536 error = sysarch(p, &args); 537 break; 538 default: 539 error = EINVAL; 540 break; 541 } 542 543 if (error == EOPNOTSUPP) { 544 printf("linux: modify_ldt needs kernel option USER_LDT\n"); 545 error = ENOSYS; 546 } 547 548 return (error); 549 } 550 551 int 552 linux_sigaction(struct proc *p, struct linux_sigaction_args *args) 553 { 554 linux_osigaction_t osa; 555 linux_sigaction_t act, oact; 556 int error; 557 558 #ifdef DEBUG 559 if (ldebug(sigaction)) 560 printf(ARGS(sigaction, "%d, %p, %p"), 561 args->sig, (void *)args->nsa, (void *)args->osa); 562 #endif 563 564 if (args->nsa != NULL) { 565 error = copyin(args->nsa, &osa, sizeof(linux_osigaction_t)); 566 if (error) 567 return (error); 568 act.lsa_handler = osa.lsa_handler; 569 act.lsa_flags = osa.lsa_flags; 570 act.lsa_restorer = osa.lsa_restorer; 571 LINUX_SIGEMPTYSET(act.lsa_mask); 572 act.lsa_mask.__bits[0] = osa.lsa_mask; 573 } 574 575 error = linux_do_sigaction(p, args->sig, args->nsa ? &act : NULL, 576 args->osa ? &oact : NULL); 577 578 if (args->osa != NULL && !error) { 579 osa.lsa_handler = oact.lsa_handler; 580 osa.lsa_flags = oact.lsa_flags; 581 osa.lsa_restorer = oact.lsa_restorer; 582 osa.lsa_mask = oact.lsa_mask.__bits[0]; 583 error = copyout(&osa, args->osa, sizeof(linux_osigaction_t)); 584 } 585 586 return (error); 587 } 588 589 /* 590 * Linux has two extra args, restart and oldmask. We dont use these, 591 * but it seems that "restart" is actually a context pointer that 592 * enables the signal to happen with a different register set. 593 */ 594 int 595 linux_sigsuspend(struct proc *p, struct linux_sigsuspend_args *args) 596 { 597 struct sigsuspend_args bsd; 598 sigset_t *sigmask; 599 linux_sigset_t mask; 600 caddr_t sg = stackgap_init(); 601 602 #ifdef DEBUG 603 if (ldebug(sigsuspend)) 604 printf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask); 605 #endif 606 607 sigmask = stackgap_alloc(&sg, sizeof(sigset_t)); 608 LINUX_SIGEMPTYSET(mask); 609 mask.__bits[0] = args->mask; 610 linux_to_bsd_sigset(&mask, sigmask); 611 bsd.sigmask = sigmask; 612 return (sigsuspend(p, &bsd)); 613 } 614 615 int 616 linux_rt_sigsuspend(p, uap) 617 struct proc *p; 618 struct linux_rt_sigsuspend_args *uap; 619 { 620 linux_sigset_t lmask; 621 sigset_t *bmask; 622 struct sigsuspend_args bsd; 623 caddr_t sg = stackgap_init(); 624 int error; 625 626 #ifdef DEBUG 627 if (ldebug(rt_sigsuspend)) 628 printf(ARGS(rt_sigsuspend, "%p, %d"), 629 (void *)uap->newset, uap->sigsetsize); 630 #endif 631 632 if (uap->sigsetsize != sizeof(linux_sigset_t)) 633 return (EINVAL); 634 635 error = copyin(uap->newset, &lmask, sizeof(linux_sigset_t)); 636 if (error) 637 return (error); 638 639 bmask = stackgap_alloc(&sg, sizeof(sigset_t)); 640 linux_to_bsd_sigset(&lmask, bmask); 641 bsd.sigmask = bmask; 642 return (sigsuspend(p, &bsd)); 643 } 644 645 int 646 linux_pause(struct proc *p, struct linux_pause_args *args) 647 { 648 struct sigsuspend_args bsd; 649 sigset_t *sigmask; 650 caddr_t sg = stackgap_init(); 651 652 #ifdef DEBUG 653 if (ldebug(pause)) 654 printf(ARGS(pause, "")); 655 #endif 656 657 sigmask = stackgap_alloc(&sg, sizeof(sigset_t)); 658 PROC_LOCK(p); 659 *sigmask = p->p_sigmask; 660 PROC_UNLOCK(p); 661 bsd.sigmask = sigmask; 662 return (sigsuspend(p, &bsd)); 663 } 664 665 int 666 linux_sigaltstack(p, uap) 667 struct proc *p; 668 struct linux_sigaltstack_args *uap; 669 { 670 struct sigaltstack_args bsd; 671 stack_t *ss, *oss; 672 linux_stack_t lss; 673 int error; 674 caddr_t sg = stackgap_init(); 675 676 #ifdef DEBUG 677 if (ldebug(sigaltstack)) 678 printf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss); 679 #endif 680 681 if (uap->uss == NULL) { 682 ss = NULL; 683 } else { 684 error = copyin(uap->uss, &lss, sizeof(linux_stack_t)); 685 if (error) 686 return (error); 687 688 ss = stackgap_alloc(&sg, sizeof(stack_t)); 689 ss->ss_sp = lss.ss_sp; 690 ss->ss_size = lss.ss_size; 691 ss->ss_flags = linux_to_bsd_sigaltstack(lss.ss_flags); 692 } 693 oss = (uap->uoss != NULL) 694 ? stackgap_alloc(&sg, sizeof(stack_t)) 695 : NULL; 696 697 bsd.ss = ss; 698 bsd.oss = oss; 699 error = sigaltstack(p, &bsd); 700 701 if (!error && oss != NULL) { 702 lss.ss_sp = oss->ss_sp; 703 lss.ss_size = oss->ss_size; 704 lss.ss_flags = bsd_to_linux_sigaltstack(oss->ss_flags); 705 error = copyout(&lss, uap->uoss, sizeof(linux_stack_t)); 706 } 707 708 return (error); 709 } 710