diff mbox series

[PULL,18/40] linux-user: Fix types in uaccess.c

Message ID 20210216161658.29881-19-peter.maydell@linaro.org (mailing list archive)
State New, archived
Headers show
Series [PULL,01/40] tcg: Introduce target-specific page data for user-only | expand

Commit Message

Peter Maydell Feb. 16, 2021, 4:16 p.m. UTC
From: Richard Henderson <richard.henderson@linaro.org>

For copy_*_user, only 0 and -TARGET_EFAULT are returned; no need
to involve abi_long.  Use size_t for lengths.  Use bool for the
lock_user copy argument.  Use ssize_t for target_strlen, because
we can't overflow the host memory space.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Message-id: 20210212184902.1251044-19-richard.henderson@linaro.org
[PMM: moved fix for ifdef error to previous commit]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/qemu.h    | 12 +++++-------
 linux-user/uaccess.c | 45 ++++++++++++++++++++++----------------------
 2 files changed, 28 insertions(+), 29 deletions(-)

Comments

Laurent Vivier Feb. 19, 2021, 9:21 a.m. UTC | #1
Hi Richard,

I think this commit is the cause of CID 1446711.

There is no concistancy between the various declarations of unlock_user():

bsd-user/qemu.h

static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
                               long len)

include/exec/softmmu-semi.h

static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
                                target_ulong len)
...
#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)

linux-user/qemu.h

#ifndef DEBUG_REMAP
static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len)
{ }
#else
void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
#endif

To take a signed long here allows to unconditionnaly call the unlock_user() function after the
syscall and not to copy the buffer if the value is negative.

Thanks,
Laurent

Le 16/02/2021 à 17:16, Peter Maydell a écrit :
> From: Richard Henderson <richard.henderson@linaro.org>
> 
> For copy_*_user, only 0 and -TARGET_EFAULT are returned; no need
> to involve abi_long.  Use size_t for lengths.  Use bool for the
> lock_user copy argument.  Use ssize_t for target_strlen, because
> we can't overflow the host memory space.
> 
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> Message-id: 20210212184902.1251044-19-richard.henderson@linaro.org
> [PMM: moved fix for ifdef error to previous commit]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  linux-user/qemu.h    | 12 +++++-------
>  linux-user/uaccess.c | 45 ++++++++++++++++++++++----------------------
>  2 files changed, 28 insertions(+), 29 deletions(-)
> 
> diff --git a/linux-user/qemu.h b/linux-user/qemu.h
> index 971af97a2fb..d25a5dafc0f 100644
> --- a/linux-user/qemu.h
> +++ b/linux-user/qemu.h
> @@ -7,8 +7,6 @@
>  #include "exec/cpu_ldst.h"
>  
>  #undef DEBUG_REMAP
> -#ifdef DEBUG_REMAP
> -#endif /* DEBUG_REMAP */
>  
>  #include "exec/user/abitypes.h"
>  
> @@ -629,8 +627,8 @@ static inline bool access_ok(CPUState *cpu, int type,
>   * buffers between the target and host.  These internally perform
>   * locking/unlocking of the memory.
>   */
> -abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
> -abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
> +int copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
> +int copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
>  
>  /* Functions for accessing guest memory.  The tget and tput functions
>     read/write single values, byteswapping as necessary.  The lock_user function
> @@ -640,13 +638,13 @@ abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
>  
>  /* Lock an area of guest memory into the host.  If copy is true then the
>     host area will have the same contents as the guest.  */
> -void *lock_user(int type, abi_ulong guest_addr, long len, int copy);
> +void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy);
>  
>  /* Unlock an area of guest memory.  The first LEN bytes must be
>     flushed back to guest memory. host_ptr = NULL is explicitly
>     allowed and does nothing. */
>  #ifndef DEBUG_REMAP
> -static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len)
> +static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len)
>  { }
>  #else
>  void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
> @@ -654,7 +652,7 @@ void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
>  
>  /* Return the length of a string in target memory or -TARGET_EFAULT if
>     access error. */
> -abi_long target_strlen(abi_ulong gaddr);
> +ssize_t target_strlen(abi_ulong gaddr);
>  
>  /* Like lock_user but for null terminated strings.  */
>  void *lock_user_string(abi_ulong guest_addr);
> diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c
> index bba012ed159..76af6a92b11 100644
> --- a/linux-user/uaccess.c
> +++ b/linux-user/uaccess.c
> @@ -4,7 +4,7 @@
>  
>  #include "qemu.h"
>  
> -void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
> +void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy)
>  {
>      if (!access_ok_untagged(type, guest_addr, len)) {
>          return NULL;
> @@ -26,7 +26,7 @@ void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
>  }
>  
>  #ifdef DEBUG_REMAP
> -void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
> +void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len);
>  {
>      if (!host_ptr) {
>          return;
> @@ -34,7 +34,7 @@ void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
>      if (host_ptr == g2h_untagged(guest_addr)) {
>          return;
>      }
> -    if (len > 0) {
> +    if (len != 0) {
>          memcpy(g2h_untagged(guest_addr), host_ptr, len);
>      }
>      g_free(host_ptr);
> @@ -43,53 +43,53 @@ void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
>  
>  void *lock_user_string(abi_ulong guest_addr)
>  {
> -    abi_long len = target_strlen(guest_addr);
> +    ssize_t len = target_strlen(guest_addr);
>      if (len < 0) {
>          return NULL;
>      }
> -    return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
> +    return lock_user(VERIFY_READ, guest_addr, (size_t)len + 1, 1);
>  }
>  
>  /* copy_from_user() and copy_to_user() are usually used to copy data
>   * buffers between the target and host.  These internally perform
>   * locking/unlocking of the memory.
>   */
> -abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
> +int copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
>  {
> -    abi_long ret = 0;
> -    void *ghptr;
> +    int ret = 0;
> +    void *ghptr = lock_user(VERIFY_READ, gaddr, len, 1);
>  
> -    if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) {
> +    if (ghptr) {
>          memcpy(hptr, ghptr, len);
>          unlock_user(ghptr, gaddr, 0);
> -    } else
> +    } else {
>          ret = -TARGET_EFAULT;
> -
> +    }
>      return ret;
>  }
>  
> -
> -abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
> +int copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
>  {
> -    abi_long ret = 0;
> -    void *ghptr;
> +    int ret = 0;
> +    void *ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0);
>  
> -    if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) {
> +    if (ghptr) {
>          memcpy(ghptr, hptr, len);
>          unlock_user(ghptr, gaddr, len);
> -    } else
> +    } else {
>          ret = -TARGET_EFAULT;
> +    }
>  
>      return ret;
>  }
>  
>  /* Return the length of a string in target memory or -TARGET_EFAULT if
>     access error  */
> -abi_long target_strlen(abi_ulong guest_addr1)
> +ssize_t target_strlen(abi_ulong guest_addr1)
>  {
>      uint8_t *ptr;
>      abi_ulong guest_addr;
> -    int max_len, len;
> +    size_t max_len, len;
>  
>      guest_addr = guest_addr1;
>      for(;;) {
> @@ -101,11 +101,12 @@ abi_long target_strlen(abi_ulong guest_addr1)
>          unlock_user(ptr, guest_addr, 0);
>          guest_addr += len;
>          /* we don't allow wrapping or integer overflow */
> -        if (guest_addr == 0 || 
> -            (guest_addr - guest_addr1) > 0x7fffffff)
> +        if (guest_addr == 0 || (guest_addr - guest_addr1) > 0x7fffffff) {
>              return -TARGET_EFAULT;
> -        if (len != max_len)
> +        }
> +        if (len != max_len) {
>              break;
> +        }
>      }
>      return guest_addr - guest_addr1;
>  }
>
Peter Maydell March 10, 2021, 3:48 p.m. UTC | #2
On Fri, 19 Feb 2021 at 09:21, Laurent Vivier <laurent@vivier.eu> wrote:
>
> Hi Richard,
>
> I think this commit is the cause of CID 1446711.
>
> There is no concistancy between the various declarations of unlock_user():
>
> bsd-user/qemu.h
>
> static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
>                                long len)
>
> include/exec/softmmu-semi.h
>
> static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
>                                 target_ulong len)
> ...
> #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
>
> linux-user/qemu.h
>
> #ifndef DEBUG_REMAP
> static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len)
> { }
> #else
> void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
> #endif
>
> To take a signed long here allows to unconditionnaly call the unlock_user() function after the
> syscall and not to copy the buffer if the value is negative.

Hi; what was the conclusion here about how best to fix the Coverity issue?

To save people looking it up, Coverity complains because in the
TARGET_NR_readlinkat case for linux-user we do:
            void *p2;
            p  = lock_user_string(arg2);
            p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
            if (!p || !p2) {
                ret = -TARGET_EFAULT;
            } else if (is_proc_myself((const char *)p, "exe")) {
                char real[PATH_MAX], *temp;
                temp = realpath(exec_path, real);
                ret = temp == NULL ? get_errno(-1) : strlen(real) ;
                snprintf((char *)p2, arg4, "%s", real);
            } else {
                ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
            }
            unlock_user(p2, arg3, ret);
            unlock_user(p, arg2, 0);

and in the "ret = -TARGET_EFAULT" and also the get_errno(readlinkat(...))
codepaths we can set ret to a negative number, which Coverity thinks
is suspicious given that unlock_user()'s new prototype says it
is an unsigned value. It's correct to be suspicious, because we really
did change from doing a >=0 to a !=0 check on the length.

Unless we really want to audit all the unlock_user() callsites,
going back to the previous semantics seems sensible.

thanks
-- PMM
Laurent Vivier March 10, 2021, 4:34 p.m. UTC | #3
Le 10/03/2021 à 16:48, Peter Maydell a écrit :
> On Fri, 19 Feb 2021 at 09:21, Laurent Vivier <laurent@vivier.eu> wrote:
>>
>> Hi Richard,
>>
>> I think this commit is the cause of CID 1446711.
>>
>> There is no concistancy between the various declarations of unlock_user():
>>
>> bsd-user/qemu.h
>>
>> static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
>>                                long len)
>>
>> include/exec/softmmu-semi.h
>>
>> static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
>>                                 target_ulong len)
>> ...
>> #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
>>
>> linux-user/qemu.h
>>
>> #ifndef DEBUG_REMAP
>> static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len)
>> { }
>> #else
>> void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
>> #endif
>>
>> To take a signed long here allows to unconditionnaly call the unlock_user() function after the
>> syscall and not to copy the buffer if the value is negative.
> 
> Hi; what was the conclusion here about how best to fix the Coverity issue?

For what I know, there is no conclusion.

> To save people looking it up, Coverity complains because in the
> TARGET_NR_readlinkat case for linux-user we do:
>             void *p2;
>             p  = lock_user_string(arg2);
>             p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
>             if (!p || !p2) {
>                 ret = -TARGET_EFAULT;
>             } else if (is_proc_myself((const char *)p, "exe")) {
>                 char real[PATH_MAX], *temp;
>                 temp = realpath(exec_path, real);
>                 ret = temp == NULL ? get_errno(-1) : strlen(real) ;
>                 snprintf((char *)p2, arg4, "%s", real);
>             } else {
>                 ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
>             }
>             unlock_user(p2, arg3, ret);
>             unlock_user(p, arg2, 0);
> 
> and in the "ret = -TARGET_EFAULT" and also the get_errno(readlinkat(...))
> codepaths we can set ret to a negative number, which Coverity thinks
> is suspicious given that unlock_user()'s new prototype says it
> is an unsigned value. It's correct to be suspicious, because we really
> did change from doing a >=0 to a !=0 check on the length.
> 
> Unless we really want to audit all the unlock_user() callsites,
> going back to the previous semantics seems sensible.

I agree with that.

Thanks,
Laurent
Richard Henderson March 11, 2021, 1:25 p.m. UTC | #4
On 3/10/21 10:34 AM, Laurent Vivier wrote:
> Le 10/03/2021 à 16:48, Peter Maydell a écrit :
>> On Fri, 19 Feb 2021 at 09:21, Laurent Vivier <laurent@vivier.eu> wrote:
>>>
>>> Hi Richard,
>>>
>>> I think this commit is the cause of CID 1446711.
>>>
>>> There is no concistancy between the various declarations of unlock_user():
>>>
>>> bsd-user/qemu.h
>>>
>>> static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
>>>                                 long len)
>>>
>>> include/exec/softmmu-semi.h
>>>
>>> static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
>>>                                  target_ulong len)
>>> ...
>>> #define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
>>>
>>> linux-user/qemu.h
>>>
>>> #ifndef DEBUG_REMAP
>>> static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len)
>>> { }
>>> #else
>>> void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
>>> #endif
>>>
>>> To take a signed long here allows to unconditionnaly call the unlock_user() function after the
>>> syscall and not to copy the buffer if the value is negative.
>>
>> Hi; what was the conclusion here about how best to fix the Coverity issue?
> 
> For what I know, there is no conclusion.
> 
>> To save people looking it up, Coverity complains because in the
>> TARGET_NR_readlinkat case for linux-user we do:
>>              void *p2;
>>              p  = lock_user_string(arg2);
>>              p2 = lock_user(VERIFY_WRITE, arg3, arg4, 0);
>>              if (!p || !p2) {
>>                  ret = -TARGET_EFAULT;
>>              } else if (is_proc_myself((const char *)p, "exe")) {
>>                  char real[PATH_MAX], *temp;
>>                  temp = realpath(exec_path, real);
>>                  ret = temp == NULL ? get_errno(-1) : strlen(real) ;
>>                  snprintf((char *)p2, arg4, "%s", real);
>>              } else {
>>                  ret = get_errno(readlinkat(arg1, path(p), p2, arg4));
>>              }
>>              unlock_user(p2, arg3, ret);
>>              unlock_user(p, arg2, 0);
>>
>> and in the "ret = -TARGET_EFAULT" and also the get_errno(readlinkat(...))
>> codepaths we can set ret to a negative number, which Coverity thinks
>> is suspicious given that unlock_user()'s new prototype says it
>> is an unsigned value. It's correct to be suspicious, because we really
>> did change from doing a >=0 to a !=0 check on the length.
>>
>> Unless we really want to audit all the unlock_user() callsites,
>> going back to the previous semantics seems sensible.
> 
> I agree with that.

This passing of an errno to unlock_user is... horrible.  I guess we have to 
revert to the signed type.


r~
diff mbox series

Patch

diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 971af97a2fb..d25a5dafc0f 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -7,8 +7,6 @@ 
 #include "exec/cpu_ldst.h"
 
 #undef DEBUG_REMAP
-#ifdef DEBUG_REMAP
-#endif /* DEBUG_REMAP */
 
 #include "exec/user/abitypes.h"
 
@@ -629,8 +627,8 @@  static inline bool access_ok(CPUState *cpu, int type,
  * buffers between the target and host.  These internally perform
  * locking/unlocking of the memory.
  */
-abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
-abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
+int copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
+int copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
 
 /* Functions for accessing guest memory.  The tget and tput functions
    read/write single values, byteswapping as necessary.  The lock_user function
@@ -640,13 +638,13 @@  abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
 
 /* Lock an area of guest memory into the host.  If copy is true then the
    host area will have the same contents as the guest.  */
-void *lock_user(int type, abi_ulong guest_addr, long len, int copy);
+void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy);
 
 /* Unlock an area of guest memory.  The first LEN bytes must be
    flushed back to guest memory. host_ptr = NULL is explicitly
    allowed and does nothing. */
 #ifndef DEBUG_REMAP
-static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, long len)
+static inline void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len)
 { }
 #else
 void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
@@ -654,7 +652,7 @@  void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
 
 /* Return the length of a string in target memory or -TARGET_EFAULT if
    access error. */
-abi_long target_strlen(abi_ulong gaddr);
+ssize_t target_strlen(abi_ulong gaddr);
 
 /* Like lock_user but for null terminated strings.  */
 void *lock_user_string(abi_ulong guest_addr);
diff --git a/linux-user/uaccess.c b/linux-user/uaccess.c
index bba012ed159..76af6a92b11 100644
--- a/linux-user/uaccess.c
+++ b/linux-user/uaccess.c
@@ -4,7 +4,7 @@ 
 
 #include "qemu.h"
 
-void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
+void *lock_user(int type, abi_ulong guest_addr, size_t len, bool copy)
 {
     if (!access_ok_untagged(type, guest_addr, len)) {
         return NULL;
@@ -26,7 +26,7 @@  void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
 }
 
 #ifdef DEBUG_REMAP
-void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
+void unlock_user(void *host_ptr, abi_ulong guest_addr, size_t len);
 {
     if (!host_ptr) {
         return;
@@ -34,7 +34,7 @@  void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
     if (host_ptr == g2h_untagged(guest_addr)) {
         return;
     }
-    if (len > 0) {
+    if (len != 0) {
         memcpy(g2h_untagged(guest_addr), host_ptr, len);
     }
     g_free(host_ptr);
@@ -43,53 +43,53 @@  void unlock_user(void *host_ptr, abi_ulong guest_addr, long len);
 
 void *lock_user_string(abi_ulong guest_addr)
 {
-    abi_long len = target_strlen(guest_addr);
+    ssize_t len = target_strlen(guest_addr);
     if (len < 0) {
         return NULL;
     }
-    return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
+    return lock_user(VERIFY_READ, guest_addr, (size_t)len + 1, 1);
 }
 
 /* copy_from_user() and copy_to_user() are usually used to copy data
  * buffers between the target and host.  These internally perform
  * locking/unlocking of the memory.
  */
-abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
+int copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
 {
-    abi_long ret = 0;
-    void *ghptr;
+    int ret = 0;
+    void *ghptr = lock_user(VERIFY_READ, gaddr, len, 1);
 
-    if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) {
+    if (ghptr) {
         memcpy(hptr, ghptr, len);
         unlock_user(ghptr, gaddr, 0);
-    } else
+    } else {
         ret = -TARGET_EFAULT;
-
+    }
     return ret;
 }
 
-
-abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
+int copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
 {
-    abi_long ret = 0;
-    void *ghptr;
+    int ret = 0;
+    void *ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0);
 
-    if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) {
+    if (ghptr) {
         memcpy(ghptr, hptr, len);
         unlock_user(ghptr, gaddr, len);
-    } else
+    } else {
         ret = -TARGET_EFAULT;
+    }
 
     return ret;
 }
 
 /* Return the length of a string in target memory or -TARGET_EFAULT if
    access error  */
-abi_long target_strlen(abi_ulong guest_addr1)
+ssize_t target_strlen(abi_ulong guest_addr1)
 {
     uint8_t *ptr;
     abi_ulong guest_addr;
-    int max_len, len;
+    size_t max_len, len;
 
     guest_addr = guest_addr1;
     for(;;) {
@@ -101,11 +101,12 @@  abi_long target_strlen(abi_ulong guest_addr1)
         unlock_user(ptr, guest_addr, 0);
         guest_addr += len;
         /* we don't allow wrapping or integer overflow */
-        if (guest_addr == 0 || 
-            (guest_addr - guest_addr1) > 0x7fffffff)
+        if (guest_addr == 0 || (guest_addr - guest_addr1) > 0x7fffffff) {
             return -TARGET_EFAULT;
-        if (len != max_len)
+        }
+        if (len != max_len) {
             break;
+        }
     }
     return guest_addr - guest_addr1;
 }