diff mbox

[01/16] linux-user: translate the result of getsockopt SO_TYPE

Message ID 1402849113-11402-2-git-send-email-paul@archlinuxmips.org
State New
Headers show

Commit Message

Paul Burton June 15, 2014, 4:18 p.m. UTC
QEMU previously passed the result of the host syscall directly to the
target program. This is a problem if the host & target have different
representations of socket types, as is the case when running a MIPS
target program on an x86 host. Introduce a host_to_target_sock_type
helper function mirroring the existing target_to_host_sock_type, and
call it to translate the value provided by getsockopt when called for
the SO_TYPE option.

Signed-off-by: Paul Burton <paul@archlinuxmips.org>
---
 linux-user/syscall.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

Comments

Riku Voipio June 21, 2014, 9:39 a.m. UTC | #1
On Sun, Jun 15, 2014 at 05:18:18PM +0100, Paul Burton wrote:
> QEMU previously passed the result of the host syscall directly to the
> target program. This is a problem if the host & target have different
> representations of socket types, as is the case when running a MIPS
> target program on an x86 host. Introduce a host_to_target_sock_type
> helper function mirroring the existing target_to_host_sock_type, and
> call it to translate the value provided by getsockopt when called for
> the SO_TYPE option.
> 
> Signed-off-by: Paul Burton <paul@archlinuxmips.org>
> ---
>  linux-user/syscall.c | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
> 
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 6efeeff..3921cff 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -592,6 +592,35 @@ char *target_strerror(int err)
>      return strerror(target_to_host_errno(err));
>  }
>  
> +static inline int host_to_target_sock_type(int host_type)
> +{
> +    int target_type;
> +
> +    switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
> +    case SOCK_DGRAM:
> +        target_type = TARGET_SOCK_DGRAM;
> +        break;
> +    case SOCK_STREAM:
> +        target_type = TARGET_SOCK_STREAM;
> +        break;
> +    default:
> +        target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
> +        break;
> +    }
> +
> +#if defined(SOCK_CLOEXEC)
> +    if (host_type & SOCK_CLOEXEC)
> +        target_type |= TARGET_SOCK_CLOEXEC;
> +#endif
> +
> +#if defined(SOCK_NONBLOCK)
> +    if (host_type & SOCK_NONBLOCK)
> +        target_type |= TARGET_SOCK_NONBLOCK;
> +#endif
> +
> +    return target_type;
> +}
> +
>  static abi_ulong target_brk;
>  static abi_ulong target_original_brk;
>  static abi_ulong brk_page;
> @@ -1526,6 +1555,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
>      abi_long ret;
>      int len, val;
>      socklen_t lv;
> +    int (*translate_result)(int val) = NULL;
>  
>      switch(level) {
>      case TARGET_SOL_SOCKET:
> @@ -1578,6 +1608,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
>              optname = SO_REUSEADDR;
>              goto int_case;
>          case TARGET_SO_TYPE:
> +            translate_result = host_to_target_sock_type;
>              optname = SO_TYPE;
>              goto int_case;
>          case TARGET_SO_ERROR:
> @@ -1636,6 +1667,8 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
>          ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
>          if (ret < 0)
>              return ret;
> +        if (translate_result)
> +            val = translate_result(val);

perhaps instead:

        if (optname == SO_TYPE)
            val = host_to_target_sock_type(val);

Then we avoid the need of function pointer. 

>          if (len > lv)
>              len = lv;
>          if (len == 4) {
> -- 
> 2.0.0
>
Paul Burton June 21, 2014, 5:39 p.m. UTC | #2
On Sat, Jun 21, 2014 at 12:39:12PM +0300, Riku Voipio wrote:
> > @@ -1526,6 +1555,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
> >      abi_long ret;
> >      int len, val;
> >      socklen_t lv;
> > +    int (*translate_result)(int val) = NULL;
> >  
> >      switch(level) {
> >      case TARGET_SOL_SOCKET:
> > @@ -1578,6 +1608,7 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
> >              optname = SO_REUSEADDR;
> >              goto int_case;
> >          case TARGET_SO_TYPE:
> > +            translate_result = host_to_target_sock_type;
> >              optname = SO_TYPE;
> >              goto int_case;
> >          case TARGET_SO_ERROR:
> > @@ -1636,6 +1667,8 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
> >          ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
> >          if (ret < 0)
> >              return ret;
> > +        if (translate_result)
> > +            val = translate_result(val);
> 
> perhaps instead:
> 
>         if (optname == SO_TYPE)
>             val = host_to_target_sock_type(val);
> 
> Then we avoid the need of function pointer.

Fair enough, perhaps I was making it too generic for my own good :)

Thanks,
    Paul
diff mbox

Patch

diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 6efeeff..3921cff 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -592,6 +592,35 @@  char *target_strerror(int err)
     return strerror(target_to_host_errno(err));
 }
 
+static inline int host_to_target_sock_type(int host_type)
+{
+    int target_type;
+
+    switch (host_type & 0xf /* SOCK_TYPE_MASK */) {
+    case SOCK_DGRAM:
+        target_type = TARGET_SOCK_DGRAM;
+        break;
+    case SOCK_STREAM:
+        target_type = TARGET_SOCK_STREAM;
+        break;
+    default:
+        target_type = host_type & 0xf /* SOCK_TYPE_MASK */;
+        break;
+    }
+
+#if defined(SOCK_CLOEXEC)
+    if (host_type & SOCK_CLOEXEC)
+        target_type |= TARGET_SOCK_CLOEXEC;
+#endif
+
+#if defined(SOCK_NONBLOCK)
+    if (host_type & SOCK_NONBLOCK)
+        target_type |= TARGET_SOCK_NONBLOCK;
+#endif
+
+    return target_type;
+}
+
 static abi_ulong target_brk;
 static abi_ulong target_original_brk;
 static abi_ulong brk_page;
@@ -1526,6 +1555,7 @@  static abi_long do_getsockopt(int sockfd, int level, int optname,
     abi_long ret;
     int len, val;
     socklen_t lv;
+    int (*translate_result)(int val) = NULL;
 
     switch(level) {
     case TARGET_SOL_SOCKET:
@@ -1578,6 +1608,7 @@  static abi_long do_getsockopt(int sockfd, int level, int optname,
             optname = SO_REUSEADDR;
             goto int_case;
         case TARGET_SO_TYPE:
+            translate_result = host_to_target_sock_type;
             optname = SO_TYPE;
             goto int_case;
         case TARGET_SO_ERROR:
@@ -1636,6 +1667,8 @@  static abi_long do_getsockopt(int sockfd, int level, int optname,
         ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
         if (ret < 0)
             return ret;
+        if (translate_result)
+            val = translate_result(val);
         if (len > lv)
             len = lv;
         if (len == 4) {