Commit 26edcf41db01e810ab2a4791b77222f5dc621ef4
1 parent
01ba9816
copy_from_user_fdset() update, by Thayne Harbaugh.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3779 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
75 additions
and
76 deletions
linux-user/syscall.c
... | ... | @@ -443,50 +443,66 @@ abi_long do_brk(abi_ulong new_brk) |
443 | 443 | } |
444 | 444 | } |
445 | 445 | |
446 | -static inline fd_set *target_to_host_fds(fd_set *fds, | |
447 | - abi_long *target_fds, int n) | |
446 | +static inline abi_long copy_from_user_fdset(fd_set *fds, | |
447 | + abi_ulong target_fds_addr, | |
448 | + int n) | |
448 | 449 | { |
449 | -#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) | |
450 | - return (fd_set *)target_fds; | |
451 | -#else | |
452 | - int i, b; | |
453 | - if (target_fds) { | |
454 | - FD_ZERO(fds); | |
455 | - for(i = 0;i < n; i++) { | |
456 | - b = (tswapl(target_fds[i / TARGET_ABI_BITS]) >> | |
457 | - (i & (TARGET_ABI_BITS - 1))) & 1; | |
458 | - if (b) | |
459 | - FD_SET(i, fds); | |
450 | + int i, nw, j, k; | |
451 | + abi_ulong b, *target_fds; | |
452 | + | |
453 | + nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; | |
454 | + if (!(target_fds = lock_user(VERIFY_READ, | |
455 | + target_fds_addr, | |
456 | + sizeof(abi_ulong) * nw, | |
457 | + 1))) | |
458 | + return -TARGET_EFAULT; | |
459 | + | |
460 | + FD_ZERO(fds); | |
461 | + k = 0; | |
462 | + for (i = 0; i < nw; i++) { | |
463 | + /* grab the abi_ulong */ | |
464 | + __get_user(b, &target_fds[i]); | |
465 | + for (j = 0; j < TARGET_ABI_BITS; j++) { | |
466 | + /* check the bit inside the abi_ulong */ | |
467 | + if ((b >> j) & 1) | |
468 | + FD_SET(k, fds); | |
469 | + k++; | |
460 | 470 | } |
461 | - return fds; | |
462 | - } else { | |
463 | - return NULL; | |
464 | 471 | } |
465 | -#endif | |
472 | + | |
473 | + unlock_user(target_fds, target_fds_addr, 0); | |
474 | + | |
475 | + return 0; | |
466 | 476 | } |
467 | 477 | |
468 | -static inline void host_to_target_fds(abi_long *target_fds, | |
469 | - fd_set *fds, int n) | |
478 | +static inline abi_long copy_to_user_fdset(abi_ulong target_fds_addr, | |
479 | + const fd_set *fds, | |
480 | + int n) | |
470 | 481 | { |
471 | -#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN) | |
472 | - /* nothing to do */ | |
473 | -#else | |
474 | 482 | int i, nw, j, k; |
475 | 483 | abi_long v; |
484 | + abi_ulong *target_fds; | |
476 | 485 | |
477 | - if (target_fds) { | |
478 | - nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; | |
479 | - k = 0; | |
480 | - for(i = 0;i < nw; i++) { | |
481 | - v = 0; | |
482 | - for(j = 0; j < TARGET_ABI_BITS; j++) { | |
483 | - v |= ((FD_ISSET(k, fds) != 0) << j); | |
484 | - k++; | |
485 | - } | |
486 | - target_fds[i] = tswapl(v); | |
486 | + nw = (n + TARGET_ABI_BITS - 1) / TARGET_ABI_BITS; | |
487 | + if (!(target_fds = lock_user(VERIFY_WRITE, | |
488 | + target_fds_addr, | |
489 | + sizeof(abi_ulong) * nw, | |
490 | + 0))) | |
491 | + return -TARGET_EFAULT; | |
492 | + | |
493 | + k = 0; | |
494 | + for (i = 0; i < nw; i++) { | |
495 | + v = 0; | |
496 | + for (j = 0; j < TARGET_ABI_BITS; j++) { | |
497 | + v |= ((FD_ISSET(k, fds) != 0) << j); | |
498 | + k++; | |
487 | 499 | } |
500 | + __put_user(v, &target_fds[i]); | |
488 | 501 | } |
489 | -#endif | |
502 | + | |
503 | + unlock_user(target_fds, target_fds_addr, sizeof(abi_ulong) * nw); | |
504 | + | |
505 | + return 0; | |
490 | 506 | } |
491 | 507 | |
492 | 508 | #if defined(__alpha__) |
... | ... | @@ -565,74 +581,57 @@ static inline abi_long host_to_target_timeval(abi_ulong target_addr, |
565 | 581 | |
566 | 582 | /* do_select() must return target values and target errnos. */ |
567 | 583 | static abi_long do_select(int n, |
568 | - abi_ulong rfd_p, abi_ulong wfd_p, | |
569 | - abi_ulong efd_p, abi_ulong target_tv) | |
584 | + abi_ulong rfd_addr, abi_ulong wfd_addr, | |
585 | + abi_ulong efd_addr, abi_ulong target_tv_addr) | |
570 | 586 | { |
571 | 587 | fd_set rfds, wfds, efds; |
572 | 588 | fd_set *rfds_ptr, *wfds_ptr, *efds_ptr; |
573 | - abi_long *target_rfds, *target_wfds, *target_efds; | |
574 | 589 | struct timeval tv, *tv_ptr; |
575 | 590 | abi_long ret; |
576 | - int ok; | |
577 | 591 | |
578 | - if (rfd_p) { | |
579 | - target_rfds = lock_user(VERIFY_WRITE, rfd_p, sizeof(abi_long) * n, 1); | |
580 | - if (!target_rfds) { | |
581 | - ret = -TARGET_EFAULT; | |
582 | - goto end; | |
583 | - } | |
584 | - rfds_ptr = target_to_host_fds(&rfds, target_rfds, n); | |
592 | + if (rfd_addr) { | |
593 | + if (copy_from_user_fdset(&rfds, rfd_addr, n)) | |
594 | + return -TARGET_EFAULT; | |
595 | + rfds_ptr = &rfds; | |
585 | 596 | } else { |
586 | - target_rfds = NULL; | |
587 | 597 | rfds_ptr = NULL; |
588 | 598 | } |
589 | - if (wfd_p) { | |
590 | - target_wfds = lock_user(VERIFY_WRITE, wfd_p, sizeof(abi_long) * n, 1); | |
591 | - if (!target_wfds) { | |
592 | - ret = -TARGET_EFAULT; | |
593 | - goto end; | |
594 | - } | |
595 | - wfds_ptr = target_to_host_fds(&wfds, target_wfds, n); | |
599 | + if (wfd_addr) { | |
600 | + if (copy_from_user_fdset(&wfds, wfd_addr, n)) | |
601 | + return -TARGET_EFAULT; | |
602 | + wfds_ptr = &wfds; | |
596 | 603 | } else { |
597 | - target_wfds = NULL; | |
598 | 604 | wfds_ptr = NULL; |
599 | 605 | } |
600 | - if (efd_p) { | |
601 | - target_efds = lock_user(VERIFY_WRITE, efd_p, sizeof(abi_long) * n, 1); | |
602 | - if (!target_efds) { | |
603 | - ret = -TARGET_EFAULT; | |
604 | - goto end; | |
605 | - } | |
606 | - efds_ptr = target_to_host_fds(&efds, target_efds, n); | |
606 | + if (efd_addr) { | |
607 | + if (copy_from_user_fdset(&efds, efd_addr, n)) | |
608 | + return -TARGET_EFAULT; | |
609 | + efds_ptr = &efds; | |
607 | 610 | } else { |
608 | - target_efds = NULL; | |
609 | 611 | efds_ptr = NULL; |
610 | 612 | } |
611 | 613 | |
612 | - if (target_tv) { | |
613 | - target_to_host_timeval(&tv, target_tv); | |
614 | + if (target_tv_addr) { | |
615 | + target_to_host_timeval(&tv, target_tv_addr); | |
614 | 616 | tv_ptr = &tv; |
615 | 617 | } else { |
616 | 618 | tv_ptr = NULL; |
617 | 619 | } |
620 | + | |
618 | 621 | ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr)); |
619 | - ok = !is_error(ret); | |
620 | 622 | |
621 | - if (ok) { | |
622 | - host_to_target_fds(target_rfds, rfds_ptr, n); | |
623 | - host_to_target_fds(target_wfds, wfds_ptr, n); | |
624 | - host_to_target_fds(target_efds, efds_ptr, n); | |
623 | + if (!is_error(ret)) { | |
624 | + if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) | |
625 | + return -TARGET_EFAULT; | |
626 | + if (wfd_addr && copy_to_user_fdset(wfd_addr, &wfds, n)) | |
627 | + return -TARGET_EFAULT; | |
628 | + if (efd_addr && copy_to_user_fdset(efd_addr, &efds, n)) | |
629 | + return -TARGET_EFAULT; | |
625 | 630 | |
626 | - if (target_tv) { | |
627 | - host_to_target_timeval(target_tv, &tv); | |
628 | - } | |
631 | + if (target_tv_addr) | |
632 | + host_to_target_timeval(target_tv_addr, &tv); | |
629 | 633 | } |
630 | 634 | |
631 | -end: | |
632 | - unlock_user(target_rfds, rfd_p, ok ? sizeof(abi_long) * n : 0); | |
633 | - unlock_user(target_wfds, wfd_p, ok ? sizeof(abi_long) * n : 0); | |
634 | - unlock_user(target_efds, efd_p, ok ? sizeof(abi_long) * n : 0); | |
635 | - | |
636 | 635 | return ret; |
637 | 636 | } |
638 | 637 | ... | ... |