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 | ... | ... |