Commit 5a4a898d81406cdda342ec2bce5ca14d2070ccb3

Authored by bellard
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:
... ...