Commit 26edcf41db01e810ab2a4791b77222f5dc621ef4

Authored by ths
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  
... ...