Commit 5a4a898d81406cdda342ec2bce5ca14d2070ccb3
1 parent
745cacc7
improved cmsg handling - improved shm memory code
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3600 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
72 additions
and
42 deletions
linux-user/syscall.c
| ... | ... | @@ -669,12 +669,22 @@ static inline abi_long host_to_target_sockaddr(abi_ulong target_addr, |
| 669 | 669 | } |
| 670 | 670 | |
| 671 | 671 | /* ??? Should this also swap msgh->name? */ |
| 672 | -static inline void target_to_host_cmsg(struct msghdr *msgh, | |
| 673 | - struct target_msghdr *target_msgh) | |
| 672 | +static inline abi_long target_to_host_cmsg(struct msghdr *msgh, | |
| 673 | + struct target_msghdr *target_msgh) | |
| 674 | 674 | { |
| 675 | 675 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); |
| 676 | - struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); | |
| 676 | + abi_long msg_controllen; | |
| 677 | + abi_ulong target_cmsg_addr; | |
| 678 | + struct target_cmsghdr *target_cmsg; | |
| 677 | 679 | socklen_t space = 0; |
| 680 | + | |
| 681 | + msg_controllen = tswapl(target_msgh->msg_controllen); | |
| 682 | + if (msg_controllen < sizeof (struct target_cmsghdr)) | |
| 683 | + goto the_end; | |
| 684 | + target_cmsg_addr = tswapl(target_msgh->msg_control); | |
| 685 | + target_cmsg = lock_user(VERIFY_READ, target_cmsg_addr, msg_controllen, 1); | |
| 686 | + if (!target_cmsg) | |
| 687 | + return -TARGET_EFAULT; | |
| 678 | 688 | |
| 679 | 689 | while (cmsg && target_cmsg) { |
| 680 | 690 | void *data = CMSG_DATA(cmsg); |
| ... | ... | @@ -709,18 +719,30 @@ static inline void target_to_host_cmsg(struct msghdr *msgh, |
| 709 | 719 | cmsg = CMSG_NXTHDR(msgh, cmsg); |
| 710 | 720 | target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); |
| 711 | 721 | } |
| 712 | - | |
| 722 | + unlock_user(target_cmsg, target_cmsg_addr, 0); | |
| 723 | + the_end: | |
| 713 | 724 | msgh->msg_controllen = space; |
| 725 | + return 0; | |
| 714 | 726 | } |
| 715 | 727 | |
| 716 | 728 | /* ??? Should this also swap msgh->name? */ |
| 717 | -static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, | |
| 718 | - struct msghdr *msgh) | |
| 729 | +static inline abi_long host_to_target_cmsg(struct target_msghdr *target_msgh, | |
| 730 | + struct msghdr *msgh) | |
| 719 | 731 | { |
| 720 | 732 | struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh); |
| 721 | - struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh); | |
| 733 | + abi_long msg_controllen; | |
| 734 | + abi_ulong target_cmsg_addr; | |
| 735 | + struct target_cmsghdr *target_cmsg; | |
| 722 | 736 | socklen_t space = 0; |
| 723 | 737 | |
| 738 | + msg_controllen = tswapl(target_msgh->msg_controllen); | |
| 739 | + if (msg_controllen < sizeof (struct target_cmsghdr)) | |
| 740 | + goto the_end; | |
| 741 | + target_cmsg_addr = tswapl(target_msgh->msg_control); | |
| 742 | + target_cmsg = lock_user(VERIFY_WRITE, target_cmsg_addr, msg_controllen, 0); | |
| 743 | + if (!target_cmsg) | |
| 744 | + return -TARGET_EFAULT; | |
| 745 | + | |
| 724 | 746 | while (cmsg && target_cmsg) { |
| 725 | 747 | void *data = CMSG_DATA(cmsg); |
| 726 | 748 | void *target_data = TARGET_CMSG_DATA(target_cmsg); |
| ... | ... | @@ -728,7 +750,7 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, |
| 728 | 750 | int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr)); |
| 729 | 751 | |
| 730 | 752 | space += TARGET_CMSG_SPACE(len); |
| 731 | - if (space > tswapl(target_msgh->msg_controllen)) { | |
| 753 | + if (space > msg_controllen) { | |
| 732 | 754 | space -= TARGET_CMSG_SPACE(len); |
| 733 | 755 | gemu_log("Target cmsg overflow\n"); |
| 734 | 756 | break; |
| ... | ... | @@ -753,8 +775,10 @@ static inline void host_to_target_cmsg(struct target_msghdr *target_msgh, |
| 753 | 775 | cmsg = CMSG_NXTHDR(msgh, cmsg); |
| 754 | 776 | target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg); |
| 755 | 777 | } |
| 756 | - | |
| 757 | - msgh->msg_controllen = tswapl(space); | |
| 778 | + unlock_user(target_cmsg, target_cmsg_addr, space); | |
| 779 | + the_end: | |
| 780 | + target_msgh->msg_controllen = tswapl(space); | |
| 781 | + return 0; | |
| 758 | 782 | } |
| 759 | 783 | |
| 760 | 784 | /* do_setsockopt() Must return target values and target errnos. */ |
| ... | ... | @@ -1109,12 +1133,13 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, |
| 1109 | 1133 | msg.msg_iov = vec; |
| 1110 | 1134 | |
| 1111 | 1135 | if (send) { |
| 1112 | - target_to_host_cmsg(&msg, msgp); | |
| 1113 | - ret = get_errno(sendmsg(fd, &msg, flags)); | |
| 1136 | + ret = target_to_host_cmsg(&msg, msgp); | |
| 1137 | + if (ret == 0) | |
| 1138 | + ret = get_errno(sendmsg(fd, &msg, flags)); | |
| 1114 | 1139 | } else { |
| 1115 | 1140 | ret = get_errno(recvmsg(fd, &msg, flags)); |
| 1116 | 1141 | if (!is_error(ret)) |
| 1117 | - host_to_target_cmsg(msgp, &msg); | |
| 1142 | + ret = host_to_target_cmsg(msgp, &msg); | |
| 1118 | 1143 | } |
| 1119 | 1144 | unlock_iovec(vec, target_vec, count, !send); |
| 1120 | 1145 | unlock_user_struct(msgp, target_msg, send ? 0 : 1); |
| ... | ... | @@ -1409,8 +1434,8 @@ static abi_long do_socketcall(int num, abi_ulong vptr) |
| 1409 | 1434 | #define N_SHM_REGIONS 32 |
| 1410 | 1435 | |
| 1411 | 1436 | static struct shm_region { |
| 1412 | - uint32_t start; | |
| 1413 | - uint32_t size; | |
| 1437 | + abi_ulong start; | |
| 1438 | + abi_ulong size; | |
| 1414 | 1439 | } shm_regions[N_SHM_REGIONS]; |
| 1415 | 1440 | |
| 1416 | 1441 | struct target_ipc_perm |
| ... | ... | @@ -1776,7 +1801,6 @@ static abi_long do_ipc(unsigned int call, int first, |
| 1776 | 1801 | { |
| 1777 | 1802 | int version; |
| 1778 | 1803 | abi_long ret = 0; |
| 1779 | - unsigned long raddr; | |
| 1780 | 1804 | struct shmid_ds shm_info; |
| 1781 | 1805 | int i; |
| 1782 | 1806 | |
| ... | ... | @@ -1831,32 +1855,38 @@ static abi_long do_ipc(unsigned int call, int first, |
| 1831 | 1855 | break; |
| 1832 | 1856 | |
| 1833 | 1857 | case IPCOP_shmat: |
| 1834 | - /* SHM_* flags are the same on all linux platforms */ | |
| 1835 | - ret = get_errno((long) shmat(first, (void *) ptr, second)); | |
| 1836 | - if (is_error(ret)) | |
| 1837 | - break; | |
| 1838 | - raddr = ret; | |
| 1839 | - /* find out the length of the shared memory segment */ | |
| 1840 | - | |
| 1841 | - ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); | |
| 1842 | - if (is_error(ret)) { | |
| 1843 | - /* can't get length, bail out */ | |
| 1844 | - shmdt((void *) raddr); | |
| 1845 | - break; | |
| 1846 | - } | |
| 1847 | - page_set_flags(raddr, raddr + shm_info.shm_segsz, | |
| 1848 | - PAGE_VALID | PAGE_READ | | |
| 1849 | - ((second & SHM_RDONLY)? 0: PAGE_WRITE)); | |
| 1850 | - for (i = 0; i < N_SHM_REGIONS; ++i) { | |
| 1851 | - if (shm_regions[i].start == 0) { | |
| 1852 | - shm_regions[i].start = raddr; | |
| 1853 | - shm_regions[i].size = shm_info.shm_segsz; | |
| 1858 | + { | |
| 1859 | + abi_ulong raddr; | |
| 1860 | + void *host_addr; | |
| 1861 | + /* SHM_* flags are the same on all linux platforms */ | |
| 1862 | + host_addr = shmat(first, (void *)g2h(ptr), second); | |
| 1863 | + if (host_addr == (void *)-1) { | |
| 1864 | + ret = get_errno((long)host_addr); | |
| 1854 | 1865 | break; |
| 1855 | - } | |
| 1856 | - } | |
| 1857 | - if (put_user(raddr, third, abi_ulong)) | |
| 1858 | - return -TARGET_EFAULT; | |
| 1859 | - ret = 0; | |
| 1866 | + } | |
| 1867 | + raddr = h2g((unsigned long)host_addr); | |
| 1868 | + /* find out the length of the shared memory segment */ | |
| 1869 | + | |
| 1870 | + ret = get_errno(shmctl(first, IPC_STAT, &shm_info)); | |
| 1871 | + if (is_error(ret)) { | |
| 1872 | + /* can't get length, bail out */ | |
| 1873 | + shmdt(host_addr); | |
| 1874 | + break; | |
| 1875 | + } | |
| 1876 | + page_set_flags(raddr, raddr + shm_info.shm_segsz, | |
| 1877 | + PAGE_VALID | PAGE_READ | | |
| 1878 | + ((second & SHM_RDONLY)? 0: PAGE_WRITE)); | |
| 1879 | + for (i = 0; i < N_SHM_REGIONS; ++i) { | |
| 1880 | + if (shm_regions[i].start == 0) { | |
| 1881 | + shm_regions[i].start = raddr; | |
| 1882 | + shm_regions[i].size = shm_info.shm_segsz; | |
| 1883 | + break; | |
| 1884 | + } | |
| 1885 | + } | |
| 1886 | + if (put_user(raddr, third, abi_ulong)) | |
| 1887 | + return -TARGET_EFAULT; | |
| 1888 | + ret = 0; | |
| 1889 | + } | |
| 1860 | 1890 | break; |
| 1861 | 1891 | case IPCOP_shmdt: |
| 1862 | 1892 | for (i = 0; i < N_SHM_REGIONS; ++i) { |
| ... | ... | @@ -1866,7 +1896,7 @@ static abi_long do_ipc(unsigned int call, int first, |
| 1866 | 1896 | break; |
| 1867 | 1897 | } |
| 1868 | 1898 | } |
| 1869 | - ret = get_errno(shmdt((void *) ptr)); | |
| 1899 | + ret = get_errno(shmdt((void *)g2h(ptr))); | |
| 1870 | 1900 | break; |
| 1871 | 1901 | |
| 1872 | 1902 | case IPCOP_shmget: | ... | ... |