Brad Bishop | 08902b0 | 2019-08-20 09:16:51 -0400 | [diff] [blame] | 1 | From 8104018ba4c66e568d2583a3a0ee940851ee7471 Mon Sep 17 00:00:00 2001 |
| 2 | From: Daniel P. Berrangé <berrange@redhat.com> |
| 3 | Date: Tue, 23 Jul 2019 17:50:00 +0200 |
| 4 | Subject: [PATCH] linux-user: fix to handle variably sized SIOCGSTAMP with new |
| 5 | kernels |
| 6 | MIME-Version: 1.0 |
| 7 | Content-Type: text/plain; charset=UTF-8 |
| 8 | Content-Transfer-Encoding: 8bit |
| 9 | |
| 10 | The SIOCGSTAMP symbol was previously defined in the |
| 11 | asm-generic/sockios.h header file. QEMU sees that header |
| 12 | indirectly via sys/socket.h |
| 13 | |
| 14 | In linux kernel commit 0768e17073dc527ccd18ed5f96ce85f9985e9115 |
| 15 | the asm-generic/sockios.h header no longer defines SIOCGSTAMP. |
| 16 | Instead it provides only SIOCGSTAMP_OLD, which only uses a |
| 17 | 32-bit time_t on 32-bit architectures. |
| 18 | |
| 19 | The linux/sockios.h header then defines SIOCGSTAMP using |
| 20 | either SIOCGSTAMP_OLD or SIOCGSTAMP_NEW as appropriate. If |
| 21 | SIOCGSTAMP_NEW is used, then the tv_sec field is 64-bit even |
| 22 | on 32-bit architectures |
| 23 | |
| 24 | To cope with this we must now convert the old and new type from |
| 25 | the target to the host one. |
| 26 | |
| 27 | Signed-off-by: Daniel P. Berrangé <berrange@redhat.com> |
| 28 | Signed-off-by: Laurent Vivier <laurent@vivier.eu> |
| 29 | Reviewed-by: Arnd Bergmann <arnd@arndb.de> |
| 30 | Message-Id: <20190718130641.15294-1-laurent@vivier.eu> |
| 31 | Signed-off-by: Laurent Vivier <laurent@vivier.eu> |
| 32 | Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com> |
| 33 | --- |
| 34 | Upstream-Status: Backport [upstream commit: 6d5d5dde9adb5acb32e6b8e3dfbf47fff0f308d2] |
| 35 | |
| 36 | linux-user/ioctls.h | 21 +++++- |
| 37 | linux-user/syscall.c | 140 +++++++++++++++++++++++++++++-------- |
| 38 | linux-user/syscall_defs.h | 30 +++++++- |
| 39 | linux-user/syscall_types.h | 6 -- |
| 40 | 4 files changed, 159 insertions(+), 38 deletions(-) |
| 41 | |
| 42 | diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h |
| 43 | index ae8951625f..e6a27ad9d6 100644 |
| 44 | --- a/linux-user/ioctls.h |
| 45 | +++ b/linux-user/ioctls.h |
| 46 | @@ -219,8 +219,25 @@ |
| 47 | IOCTL(SIOCGRARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq))) |
| 48 | IOCTL(SIOCGIWNAME, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_char_ifreq))) |
| 49 | IOCTL(SIOCGPGRP, IOC_R, MK_PTR(TYPE_INT)) /* pid_t */ |
| 50 | - IOCTL(SIOCGSTAMP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timeval))) |
| 51 | - IOCTL(SIOCGSTAMPNS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_timespec))) |
| 52 | + |
| 53 | + /* |
| 54 | + * We can't use IOCTL_SPECIAL() because it will set |
| 55 | + * host_cmd to XXX_OLD and XXX_NEW and these macros |
| 56 | + * are not defined with kernel prior to 5.2. |
| 57 | + * We must set host_cmd to the same value as in target_cmd |
| 58 | + * otherwise the consistency check in syscall_init() |
| 59 | + * will trigger an error. |
| 60 | + * host_cmd is ignored by the do_ioctl_XXX() helpers. |
| 61 | + * FIXME: create a macro to define this kind of entry |
| 62 | + */ |
| 63 | + { TARGET_SIOCGSTAMP_OLD, TARGET_SIOCGSTAMP_OLD, |
| 64 | + "SIOCGSTAMP_OLD", IOC_R, do_ioctl_SIOCGSTAMP }, |
| 65 | + { TARGET_SIOCGSTAMPNS_OLD, TARGET_SIOCGSTAMPNS_OLD, |
| 66 | + "SIOCGSTAMPNS_OLD", IOC_R, do_ioctl_SIOCGSTAMPNS }, |
| 67 | + { TARGET_SIOCGSTAMP_NEW, TARGET_SIOCGSTAMP_NEW, |
| 68 | + "SIOCGSTAMP_NEW", IOC_R, do_ioctl_SIOCGSTAMP }, |
| 69 | + { TARGET_SIOCGSTAMPNS_NEW, TARGET_SIOCGSTAMPNS_NEW, |
| 70 | + "SIOCGSTAMPNS_NEW", IOC_R, do_ioctl_SIOCGSTAMPNS }, |
| 71 | |
| 72 | IOCTL(RNDGETENTCNT, IOC_R, MK_PTR(TYPE_INT)) |
| 73 | IOCTL(RNDADDTOENTCNT, IOC_W, MK_PTR(TYPE_INT)) |
| 74 | diff --git a/linux-user/syscall.c b/linux-user/syscall.c |
| 75 | index 96cd4bf86d..6df480e13d 100644 |
| 76 | --- a/linux-user/syscall.c |
| 77 | +++ b/linux-user/syscall.c |
| 78 | @@ -37,6 +37,7 @@ |
| 79 | #include <sched.h> |
| 80 | #include <sys/timex.h> |
| 81 | #include <sys/socket.h> |
| 82 | +#include <linux/sockios.h> |
| 83 | #include <sys/un.h> |
| 84 | #include <sys/uio.h> |
| 85 | #include <poll.h> |
| 86 | @@ -1139,8 +1140,9 @@ static inline abi_long copy_from_user_timeval(struct timeval *tv, |
| 87 | { |
| 88 | struct target_timeval *target_tv; |
| 89 | |
| 90 | - if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) |
| 91 | + if (!lock_user_struct(VERIFY_READ, target_tv, target_tv_addr, 1)) { |
| 92 | return -TARGET_EFAULT; |
| 93 | + } |
| 94 | |
| 95 | __get_user(tv->tv_sec, &target_tv->tv_sec); |
| 96 | __get_user(tv->tv_usec, &target_tv->tv_usec); |
| 97 | @@ -1155,8 +1157,26 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr, |
| 98 | { |
| 99 | struct target_timeval *target_tv; |
| 100 | |
| 101 | - if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) |
| 102 | + if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) { |
| 103 | + return -TARGET_EFAULT; |
| 104 | + } |
| 105 | + |
| 106 | + __put_user(tv->tv_sec, &target_tv->tv_sec); |
| 107 | + __put_user(tv->tv_usec, &target_tv->tv_usec); |
| 108 | + |
| 109 | + unlock_user_struct(target_tv, target_tv_addr, 1); |
| 110 | + |
| 111 | + return 0; |
| 112 | +} |
| 113 | + |
| 114 | +static inline abi_long copy_to_user_timeval64(abi_ulong target_tv_addr, |
| 115 | + const struct timeval *tv) |
| 116 | +{ |
| 117 | + struct target__kernel_sock_timeval *target_tv; |
| 118 | + |
| 119 | + if (!lock_user_struct(VERIFY_WRITE, target_tv, target_tv_addr, 0)) { |
| 120 | return -TARGET_EFAULT; |
| 121 | + } |
| 122 | |
| 123 | __put_user(tv->tv_sec, &target_tv->tv_sec); |
| 124 | __put_user(tv->tv_usec, &target_tv->tv_usec); |
| 125 | @@ -1166,6 +1186,48 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr, |
| 126 | return 0; |
| 127 | } |
| 128 | |
| 129 | +static inline abi_long target_to_host_timespec(struct timespec *host_ts, |
| 130 | + abi_ulong target_addr) |
| 131 | +{ |
| 132 | + struct target_timespec *target_ts; |
| 133 | + |
| 134 | + if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) { |
| 135 | + return -TARGET_EFAULT; |
| 136 | + } |
| 137 | + __get_user(host_ts->tv_sec, &target_ts->tv_sec); |
| 138 | + __get_user(host_ts->tv_nsec, &target_ts->tv_nsec); |
| 139 | + unlock_user_struct(target_ts, target_addr, 0); |
| 140 | + return 0; |
| 141 | +} |
| 142 | + |
| 143 | +static inline abi_long host_to_target_timespec(abi_ulong target_addr, |
| 144 | + struct timespec *host_ts) |
| 145 | +{ |
| 146 | + struct target_timespec *target_ts; |
| 147 | + |
| 148 | + if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) { |
| 149 | + return -TARGET_EFAULT; |
| 150 | + } |
| 151 | + __put_user(host_ts->tv_sec, &target_ts->tv_sec); |
| 152 | + __put_user(host_ts->tv_nsec, &target_ts->tv_nsec); |
| 153 | + unlock_user_struct(target_ts, target_addr, 1); |
| 154 | + return 0; |
| 155 | +} |
| 156 | + |
| 157 | +static inline abi_long host_to_target_timespec64(abi_ulong target_addr, |
| 158 | + struct timespec *host_ts) |
| 159 | +{ |
| 160 | + struct target__kernel_timespec *target_ts; |
| 161 | + |
| 162 | + if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) { |
| 163 | + return -TARGET_EFAULT; |
| 164 | + } |
| 165 | + __put_user(host_ts->tv_sec, &target_ts->tv_sec); |
| 166 | + __put_user(host_ts->tv_nsec, &target_ts->tv_nsec); |
| 167 | + unlock_user_struct(target_ts, target_addr, 1); |
| 168 | + return 0; |
| 169 | +} |
| 170 | + |
| 171 | static inline abi_long copy_from_user_timezone(struct timezone *tz, |
| 172 | abi_ulong target_tz_addr) |
| 173 | { |
| 174 | @@ -4790,6 +4852,54 @@ static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp, |
| 175 | return get_errno(safe_ioctl(fd, ie->host_cmd, sig)); |
| 176 | } |
| 177 | |
| 178 | +static abi_long do_ioctl_SIOCGSTAMP(const IOCTLEntry *ie, uint8_t *buf_temp, |
| 179 | + int fd, int cmd, abi_long arg) |
| 180 | +{ |
| 181 | + struct timeval tv; |
| 182 | + abi_long ret; |
| 183 | + |
| 184 | + ret = get_errno(safe_ioctl(fd, SIOCGSTAMP, &tv)); |
| 185 | + if (is_error(ret)) { |
| 186 | + return ret; |
| 187 | + } |
| 188 | + |
| 189 | + if (cmd == (int)TARGET_SIOCGSTAMP_OLD) { |
| 190 | + if (copy_to_user_timeval(arg, &tv)) { |
| 191 | + return -TARGET_EFAULT; |
| 192 | + } |
| 193 | + } else { |
| 194 | + if (copy_to_user_timeval64(arg, &tv)) { |
| 195 | + return -TARGET_EFAULT; |
| 196 | + } |
| 197 | + } |
| 198 | + |
| 199 | + return ret; |
| 200 | +} |
| 201 | + |
| 202 | +static abi_long do_ioctl_SIOCGSTAMPNS(const IOCTLEntry *ie, uint8_t *buf_temp, |
| 203 | + int fd, int cmd, abi_long arg) |
| 204 | +{ |
| 205 | + struct timespec ts; |
| 206 | + abi_long ret; |
| 207 | + |
| 208 | + ret = get_errno(safe_ioctl(fd, SIOCGSTAMPNS, &ts)); |
| 209 | + if (is_error(ret)) { |
| 210 | + return ret; |
| 211 | + } |
| 212 | + |
| 213 | + if (cmd == (int)TARGET_SIOCGSTAMPNS_OLD) { |
| 214 | + if (host_to_target_timespec(arg, &ts)) { |
| 215 | + return -TARGET_EFAULT; |
| 216 | + } |
| 217 | + } else{ |
| 218 | + if (host_to_target_timespec64(arg, &ts)) { |
| 219 | + return -TARGET_EFAULT; |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + return ret; |
| 224 | +} |
| 225 | + |
| 226 | #ifdef TIOCGPTPEER |
| 227 | static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp, |
| 228 | int fd, int cmd, abi_long arg) |
| 229 | @@ -6160,32 +6270,6 @@ static inline abi_long target_ftruncate64(void *cpu_env, abi_long arg1, |
| 230 | } |
| 231 | #endif |
| 232 | |
| 233 | -static inline abi_long target_to_host_timespec(struct timespec *host_ts, |
| 234 | - abi_ulong target_addr) |
| 235 | -{ |
| 236 | - struct target_timespec *target_ts; |
| 237 | - |
| 238 | - if (!lock_user_struct(VERIFY_READ, target_ts, target_addr, 1)) |
| 239 | - return -TARGET_EFAULT; |
| 240 | - __get_user(host_ts->tv_sec, &target_ts->tv_sec); |
| 241 | - __get_user(host_ts->tv_nsec, &target_ts->tv_nsec); |
| 242 | - unlock_user_struct(target_ts, target_addr, 0); |
| 243 | - return 0; |
| 244 | -} |
| 245 | - |
| 246 | -static inline abi_long host_to_target_timespec(abi_ulong target_addr, |
| 247 | - struct timespec *host_ts) |
| 248 | -{ |
| 249 | - struct target_timespec *target_ts; |
| 250 | - |
| 251 | - if (!lock_user_struct(VERIFY_WRITE, target_ts, target_addr, 0)) |
| 252 | - return -TARGET_EFAULT; |
| 253 | - __put_user(host_ts->tv_sec, &target_ts->tv_sec); |
| 254 | - __put_user(host_ts->tv_nsec, &target_ts->tv_nsec); |
| 255 | - unlock_user_struct(target_ts, target_addr, 1); |
| 256 | - return 0; |
| 257 | -} |
| 258 | - |
| 259 | static inline abi_long target_to_host_itimerspec(struct itimerspec *host_itspec, |
| 260 | abi_ulong target_addr) |
| 261 | { |
| 262 | diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h |
| 263 | index 12c8407144..c918419306 100644 |
| 264 | --- a/linux-user/syscall_defs.h |
| 265 | +++ b/linux-user/syscall_defs.h |
| 266 | @@ -208,16 +208,34 @@ struct target_linger { |
| 267 | abi_int l_linger; /* How long to linger for */ |
| 268 | }; |
| 269 | |
| 270 | +#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32) |
| 271 | +struct target_timeval { |
| 272 | + abi_long tv_sec; |
| 273 | + abi_int tv_usec; |
| 274 | +}; |
| 275 | +#define target__kernel_sock_timeval target_timeval |
| 276 | +#else |
| 277 | struct target_timeval { |
| 278 | abi_long tv_sec; |
| 279 | abi_long tv_usec; |
| 280 | }; |
| 281 | |
| 282 | +struct target__kernel_sock_timeval { |
| 283 | + abi_llong tv_sec; |
| 284 | + abi_llong tv_usec; |
| 285 | +}; |
| 286 | +#endif |
| 287 | + |
| 288 | struct target_timespec { |
| 289 | abi_long tv_sec; |
| 290 | abi_long tv_nsec; |
| 291 | }; |
| 292 | |
| 293 | +struct target__kernel_timespec { |
| 294 | + abi_llong tv_sec; |
| 295 | + abi_llong tv_nsec; |
| 296 | +}; |
| 297 | + |
| 298 | struct target_timezone { |
| 299 | abi_int tz_minuteswest; |
| 300 | abi_int tz_dsttime; |
| 301 | @@ -743,8 +761,16 @@ struct target_pollfd { |
| 302 | #define TARGET_SIOCATMARK 0x8905 |
| 303 | #define TARGET_SIOCGPGRP 0x8904 |
| 304 | #endif |
| 305 | -#define TARGET_SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ |
| 306 | -#define TARGET_SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ |
| 307 | +#if defined(TARGET_SH4) |
| 308 | +#define TARGET_SIOCGSTAMP_OLD TARGET_IOR('s', 100, struct target_timeval) |
| 309 | +#define TARGET_SIOCGSTAMPNS_OLD TARGET_IOR('s', 101, struct target_timespec) |
| 310 | +#else |
| 311 | +#define TARGET_SIOCGSTAMP_OLD 0x8906 |
| 312 | +#define TARGET_SIOCGSTAMPNS_OLD 0x8907 |
| 313 | +#endif |
| 314 | + |
| 315 | +#define TARGET_SIOCGSTAMP_NEW TARGET_IOR(0x89, 0x06, abi_llong[2]) |
| 316 | +#define TARGET_SIOCGSTAMPNS_NEW TARGET_IOR(0x89, 0x07, abi_llong[2]) |
| 317 | |
| 318 | /* Networking ioctls */ |
| 319 | #define TARGET_SIOCADDRT 0x890B /* add routing table entry */ |
| 320 | diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h |
| 321 | index b98a23b0f1..4e36983826 100644 |
| 322 | --- a/linux-user/syscall_types.h |
| 323 | +++ b/linux-user/syscall_types.h |
| 324 | @@ -14,12 +14,6 @@ STRUCT(serial_icounter_struct, |
| 325 | STRUCT(sockaddr, |
| 326 | TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 14)) |
| 327 | |
| 328 | -STRUCT(timeval, |
| 329 | - MK_ARRAY(TYPE_LONG, 2)) |
| 330 | - |
| 331 | -STRUCT(timespec, |
| 332 | - MK_ARRAY(TYPE_LONG, 2)) |
| 333 | - |
| 334 | STRUCT(rtentry, |
| 335 | TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), |
| 336 | TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID, |
| 337 | -- |
| 338 | 2.21.0 |
| 339 | |