This uses __get_user()/__put_user() for copy_{to,from}_user_timespec().
It checks and handles return values.
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c	2007-11-20 13:21:38.000000000 -0700
+++ qemu/linux-user/syscall.c	2007-11-20 13:51:28.000000000 -0700
@@ -3026,28 +3026,36 @@
 }
 #endif
 
-static inline abi_long target_to_host_timespec(struct timespec *host_ts,
-                                               abi_ulong target_addr)
+static inline abi_long copy_from_user_timespec(struct timespec *host_ts,
+                                               abi_ulong target_ts_addr)
 {
     struct target_timespec *target_ts;
 
-    if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1))
+    if (!lock_user_struct(VERIFY_READ, target_ts, target_ts_addr, 1))
         return -TARGET_EFAULT;
-    host_ts->tv_sec = tswapl(target_ts->tv_sec);
-    host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
-    unlock_user_struct(target_ts, target_addr, 0);
+
+    __get_user(host_ts->tv_sec, &target_ts->tv_sec);
+    __get_user(host_ts->tv_nsec, &target_ts->tv_nsec);
+
+    unlock_user_struct(target_ts, target_ts_addr, 0);
+
+    return 0;
 }
 
-static inline abi_long host_to_target_timespec(abi_ulong target_addr,
-                                               struct timespec *host_ts)
+static inline abi_long copy_to_user_timespec(abi_ulong target_ts_addr,
+                                             const struct timespec *host_ts)
 {
     struct target_timespec *target_ts;
 
-    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0))
+    if (!lock_user_struct(VERIFY_WRITE, target_ts, target_ts_addr, 0))
         return -TARGET_EFAULT;
-    target_ts->tv_sec = tswapl(host_ts->tv_sec);
-    target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
-    unlock_user_struct(target_ts, target_addr, 1);
+
+    __put_user(host_ts->tv_sec, &target_ts->tv_sec);
+    __put_user(host_ts->tv_nsec, &target_ts->tv_nsec);
+
+    unlock_user_struct(target_ts, target_ts_addr, 1);
+
+    return 0;
 }
 
 /* do_syscall() should always have a single exit point at the end so
@@ -3855,7 +3863,8 @@
             unlock_user(p, arg1, 0);
             if (arg3) {
                 puts = &uts;
-                target_to_host_timespec(puts, arg3);
+                if (copy_from_user_timespec(puts, arg3))
+                    goto efault;
             } else {
                 puts = NULL;
             }
@@ -4807,17 +4816,21 @@
             struct timespec ts;
             ret = get_errno(sched_rr_get_interval(arg1, &ts));
             if (!is_error(ret)) {
-                host_to_target_timespec(arg2, &ts);
+                if (copy_to_user_timespec(arg2, &ts))
+                    goto efault;
             }
         }
         break;
     case TARGET_NR_nanosleep:
         {
             struct timespec req, rem;
-            target_to_host_timespec(&req, arg1);
+
+            if (copy_from_user_timespec(&req, arg1))
+                goto efault;
             ret = get_errno(nanosleep(&req, &rem));
-            if (is_error(ret) && arg2) {
-                host_to_target_timespec(arg2, &rem);
+            if (!is_error(ret) && arg2) {
+                if (copy_to_user_timespec(arg2, &rem))
+                    goto efault;
             }
         }
         break;
@@ -5491,7 +5504,8 @@
         struct timespec ts;
         ret = get_errno(clock_gettime(arg1, &ts));
         if (!is_error(ret)) {
-            host_to_target_timespec(arg2, &ts);
+            if (copy_to_user_timespec(arg2, &ts))
+                goto efault;
         }
         break;
     }
@@ -5502,7 +5516,8 @@
         struct timespec ts;
         ret = get_errno(clock_getres(arg1, &ts));
         if (!is_error(ret)) {
-            host_to_target_timespec(arg2, &ts);
+            if (copy_to_user_timespec(arg2, &ts))
+                goto efault;
         }
         break;
     }
@@ -5535,8 +5550,10 @@
     case TARGET_NR_utimensat:
         {
             struct timespec ts[2];
-            target_to_host_timespec(ts, arg3);
-            target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+
+            if (copy_from_user_timespec(ts, arg3)
+                || copy_from_user_timespec(ts+1, arg3+sizeof(struct target_timespec)))
+                goto efault;
             if (!arg2)
                 ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4));
             else {

Reply via email to