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