1 /* 2 * 32 bit compatibility code for System V IPC 3 * 4 * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 5 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) 6 * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> 7 * Copyright (C) 2000 VA Linux Co 8 * Copyright (C) 2000 Don Dugger <n0ano@valinux.com> 9 * Copyright (C) 2000 Hewlett-Packard Co. 10 * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> 11 * Copyright (C) 2000 Gerhard Tonn (ton@de.ibm.com) 12 * Copyright (C) 2000-2002 Andi Kleen, SuSE Labs (x86-64 port) 13 * Copyright (C) 2000 Silicon Graphics, Inc. 14 * Copyright (C) 2001 IBM 15 * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation 16 * Copyright (C) 2004 Arnd Bergmann (arnd@arndb.de) 17 * 18 * This code is collected from the versions for sparc64, mips64, s390x, ia64, 19 * ppc64 and x86_64, all of which are based on the original sparc64 version 20 * by Jakub Jelinek. 21 * 22 */ 23 #include <linux/compat.h> 24 #include <linux/errno.h> 25 #include <linux/highuid.h> 26 #include <linux/init.h> 27 #include <linux/msg.h> 28 #include <linux/shm.h> 29 #include <linux/slab.h> 30 #include <linux/syscalls.h> 31 32 #include <linux/mutex.h> 33 #include <asm/uaccess.h> 34 35 #include "util.h" 36 37 struct compat_msgbuf { 38 compat_long_t mtype; 39 char mtext[1]; 40 }; 41 42 struct compat_ipc_perm { 43 key_t key; 44 __compat_uid_t uid; 45 __compat_gid_t gid; 46 __compat_uid_t cuid; 47 __compat_gid_t cgid; 48 compat_mode_t mode; 49 unsigned short seq; 50 }; 51 52 struct compat_semid_ds { 53 struct compat_ipc_perm sem_perm; 54 compat_time_t sem_otime; 55 compat_time_t sem_ctime; 56 compat_uptr_t sem_base; 57 compat_uptr_t sem_pending; 58 compat_uptr_t sem_pending_last; 59 compat_uptr_t undo; 60 unsigned short sem_nsems; 61 }; 62 63 struct compat_msqid_ds { 64 struct compat_ipc_perm msg_perm; 65 compat_uptr_t msg_first; 66 compat_uptr_t msg_last; 67 compat_time_t msg_stime; 68 compat_time_t msg_rtime; 69 compat_time_t msg_ctime; 70 compat_ulong_t msg_lcbytes; 71 compat_ulong_t msg_lqbytes; 72 unsigned short msg_cbytes; 73 unsigned short msg_qnum; 74 unsigned short msg_qbytes; 75 compat_ipc_pid_t msg_lspid; 76 compat_ipc_pid_t msg_lrpid; 77 }; 78 79 struct compat_shmid_ds { 80 struct compat_ipc_perm shm_perm; 81 int shm_segsz; 82 compat_time_t shm_atime; 83 compat_time_t shm_dtime; 84 compat_time_t shm_ctime; 85 compat_ipc_pid_t shm_cpid; 86 compat_ipc_pid_t shm_lpid; 87 unsigned short shm_nattch; 88 unsigned short shm_unused; 89 compat_uptr_t shm_unused2; 90 compat_uptr_t shm_unused3; 91 }; 92 93 struct compat_ipc_kludge { 94 compat_uptr_t msgp; 95 compat_long_t msgtyp; 96 }; 97 98 struct compat_shminfo64 { 99 compat_ulong_t shmmax; 100 compat_ulong_t shmmin; 101 compat_ulong_t shmmni; 102 compat_ulong_t shmseg; 103 compat_ulong_t shmall; 104 compat_ulong_t __unused1; 105 compat_ulong_t __unused2; 106 compat_ulong_t __unused3; 107 compat_ulong_t __unused4; 108 }; 109 110 struct compat_shm_info { 111 compat_int_t used_ids; 112 compat_ulong_t shm_tot, shm_rss, shm_swp; 113 compat_ulong_t swap_attempts, swap_successes; 114 }; 115 116 extern int sem_ctls[]; 117 #define sc_semopm (sem_ctls[2]) 118 #define MAXBUF (64*1024) 119 120 static inline int compat_ipc_parse_version(int *cmd) 121 { 122 int version = *cmd & IPC_64; 123 124 /* this is tricky: architectures that have support for the old 125 * ipc structures in 64 bit binaries need to have IPC_64 set 126 * in cmd, the others need to have it cleared */ 127 #ifndef ipc_parse_version 128 *cmd |= IPC_64; 129 #else 130 *cmd &= ~IPC_64; 131 #endif 132 return version; 133 } 134 135 static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64, 136 struct compat_ipc64_perm __user *up64) 137 { 138 int err; 139 140 err = __get_user(p64->uid, &up64->uid); 141 err |= __get_user(p64->gid, &up64->gid); 142 err |= __get_user(p64->mode, &up64->mode); 143 return err; 144 } 145 146 static inline int __get_compat_ipc_perm(struct ipc64_perm *p, 147 struct compat_ipc_perm __user *up) 148 { 149 int err; 150 151 err = __get_user(p->uid, &up->uid); 152 err |= __get_user(p->gid, &up->gid); 153 err |= __get_user(p->mode, &up->mode); 154 return err; 155 } 156 157 static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64, 158 struct compat_ipc64_perm __user *up64) 159 { 160 int err; 161 162 err = __put_user(p64->key, &up64->key); 163 err |= __put_user(p64->uid, &up64->uid); 164 err |= __put_user(p64->gid, &up64->gid); 165 err |= __put_user(p64->cuid, &up64->cuid); 166 err |= __put_user(p64->cgid, &up64->cgid); 167 err |= __put_user(p64->mode, &up64->mode); 168 err |= __put_user(p64->seq, &up64->seq); 169 return err; 170 } 171 172 static inline int __put_compat_ipc_perm(struct ipc64_perm *p, 173 struct compat_ipc_perm __user *up) 174 { 175 int err; 176 __compat_uid_t u; 177 __compat_gid_t g; 178 179 err = __put_user(p->key, &up->key); 180 SET_UID(u, p->uid); 181 err |= __put_user(u, &up->uid); 182 SET_GID(g, p->gid); 183 err |= __put_user(g, &up->gid); 184 SET_UID(u, p->cuid); 185 err |= __put_user(u, &up->cuid); 186 SET_GID(g, p->cgid); 187 err |= __put_user(g, &up->cgid); 188 err |= __put_user(p->mode, &up->mode); 189 err |= __put_user(p->seq, &up->seq); 190 return err; 191 } 192 193 static inline int get_compat_semid64_ds(struct semid64_ds *s64, 194 struct compat_semid64_ds __user *up64) 195 { 196 if (!access_ok (VERIFY_READ, up64, sizeof(*up64))) 197 return -EFAULT; 198 return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); 199 } 200 201 static inline int get_compat_semid_ds(struct semid64_ds *s, 202 struct compat_semid_ds __user *up) 203 { 204 if (!access_ok (VERIFY_READ, up, sizeof(*up))) 205 return -EFAULT; 206 return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm); 207 } 208 209 static inline int put_compat_semid64_ds(struct semid64_ds *s64, 210 struct compat_semid64_ds __user *up64) 211 { 212 int err; 213 214 if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64))) 215 return -EFAULT; 216 err = __put_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm); 217 err |= __put_user(s64->sem_otime, &up64->sem_otime); 218 err |= __put_user(s64->sem_ctime, &up64->sem_ctime); 219 err |= __put_user(s64->sem_nsems, &up64->sem_nsems); 220 return err; 221 } 222 223 static inline int put_compat_semid_ds(struct semid64_ds *s, 224 struct compat_semid_ds __user *up) 225 { 226 int err; 227 228 if (!access_ok (VERIFY_WRITE, up, sizeof(*up))) 229 err = -EFAULT; 230 err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm); 231 err |= __put_user(s->sem_otime, &up->sem_otime); 232 err |= __put_user(s->sem_ctime, &up->sem_ctime); 233 err |= __put_user(s->sem_nsems, &up->sem_nsems); 234 return err; 235 } 236 237 long compat_sys_semctl(int first, int second, int third, void __user *uptr) 238 { 239 union semun fourth; 240 u32 pad; 241 int err, err2; 242 struct semid64_ds s64; 243 struct semid64_ds __user *up64; 244 int version = compat_ipc_parse_version(&third); 245 246 if (!uptr) 247 return -EINVAL; 248 if (get_user(pad, (u32 __user *) uptr)) 249 return -EFAULT; 250 if ((third & (~IPC_64)) == SETVAL) 251 fourth.val = (int) pad; 252 else 253 fourth.__pad = compat_ptr(pad); 254 switch (third & (~IPC_64)) { 255 case IPC_INFO: 256 case IPC_RMID: 257 case SEM_INFO: 258 case GETVAL: 259 case GETPID: 260 case GETNCNT: 261 case GETZCNT: 262 case GETALL: 263 case SETVAL: 264 case SETALL: 265 err = sys_semctl(first, second, third, fourth); 266 break; 267 268 case IPC_STAT: 269 case SEM_STAT: 270 up64 = compat_alloc_user_space(sizeof(s64)); 271 fourth.__pad = up64; 272 err = sys_semctl(first, second, third, fourth); 273 if (err < 0) 274 break; 275 if (copy_from_user(&s64, up64, sizeof(s64))) 276 err2 = -EFAULT; 277 else if (version == IPC_64) 278 err2 = put_compat_semid64_ds(&s64, compat_ptr(pad)); 279 else 280 err2 = put_compat_semid_ds(&s64, compat_ptr(pad)); 281 if (err2) 282 err = -EFAULT; 283 break; 284 285 case IPC_SET: 286 if (version == IPC_64) { 287 err = get_compat_semid64_ds(&s64, compat_ptr(pad)); 288 } else { 289 err = get_compat_semid_ds(&s64, compat_ptr(pad)); 290 } 291 up64 = compat_alloc_user_space(sizeof(s64)); 292 if (copy_to_user(up64, &s64, sizeof(s64))) 293 err = -EFAULT; 294 if (err) 295 break; 296 297 fourth.__pad = up64; 298 err = sys_semctl(first, second, third, fourth); 299 break; 300 301 default: 302 err = -EINVAL; 303 break; 304 } 305 return err; 306 } 307 308 long compat_sys_msgsnd(int first, int second, int third, void __user *uptr) 309 { 310 struct msgbuf __user *p; 311 struct compat_msgbuf __user *up = uptr; 312 long type; 313 314 if (first < 0) 315 return -EINVAL; 316 if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) 317 return -EINVAL; 318 319 p = compat_alloc_user_space(second + sizeof(struct msgbuf)); 320 if (get_user(type, &up->mtype) || 321 put_user(type, &p->mtype) || 322 copy_in_user(p->mtext, up->mtext, second)) 323 return -EFAULT; 324 325 return sys_msgsnd(first, p, second, third); 326 } 327 328 long compat_sys_msgrcv(int first, int second, int msgtyp, int third, 329 int version, void __user *uptr) 330 { 331 struct msgbuf __user *p; 332 struct compat_msgbuf __user *up; 333 long type; 334 int err; 335 336 if (first < 0) 337 return -EINVAL; 338 if (second < 0 || (second >= MAXBUF - sizeof(struct msgbuf))) 339 return -EINVAL; 340 341 if (!version) { 342 struct compat_ipc_kludge ipck; 343 err = -EINVAL; 344 if (!uptr) 345 goto out; 346 err = -EFAULT; 347 if (copy_from_user (&ipck, uptr, sizeof(ipck))) 348 goto out; 349 uptr = compat_ptr(ipck.msgp); 350 msgtyp = ipck.msgtyp; 351 } 352 p = compat_alloc_user_space(second + sizeof(struct msgbuf)); 353 err = sys_msgrcv(first, p, second, msgtyp, third); 354 if (err < 0) 355 goto out; 356 up = uptr; 357 if (get_user(type, &p->mtype) || 358 put_user(type, &up->mtype) || 359 copy_in_user(up->mtext, p->mtext, err)) 360 err = -EFAULT; 361 out: 362 return err; 363 } 364 365 static inline int get_compat_msqid64(struct msqid64_ds *m64, 366 struct compat_msqid64_ds __user *up64) 367 { 368 int err; 369 370 if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) 371 return -EFAULT; 372 err = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm); 373 err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes); 374 return err; 375 } 376 377 static inline int get_compat_msqid(struct msqid64_ds *m, 378 struct compat_msqid_ds __user *up) 379 { 380 int err; 381 382 if (!access_ok(VERIFY_READ, up, sizeof(*up))) 383 return -EFAULT; 384 err = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm); 385 err |= __get_user(m->msg_qbytes, &up->msg_qbytes); 386 return err; 387 } 388 389 static inline int put_compat_msqid64_ds(struct msqid64_ds *m64, 390 struct compat_msqid64_ds __user *up64) 391 { 392 int err; 393 394 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) 395 return -EFAULT; 396 err = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm); 397 err |= __put_user(m64->msg_stime, &up64->msg_stime); 398 err |= __put_user(m64->msg_rtime, &up64->msg_rtime); 399 err |= __put_user(m64->msg_ctime, &up64->msg_ctime); 400 err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes); 401 err |= __put_user(m64->msg_qnum, &up64->msg_qnum); 402 err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes); 403 err |= __put_user(m64->msg_lspid, &up64->msg_lspid); 404 err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid); 405 return err; 406 } 407 408 static inline int put_compat_msqid_ds(struct msqid64_ds *m, 409 struct compat_msqid_ds __user *up) 410 { 411 int err; 412 413 if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) 414 return -EFAULT; 415 err = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm); 416 err |= __put_user(m->msg_stime, &up->msg_stime); 417 err |= __put_user(m->msg_rtime, &up->msg_rtime); 418 err |= __put_user(m->msg_ctime, &up->msg_ctime); 419 err |= __put_user(m->msg_cbytes, &up->msg_cbytes); 420 err |= __put_user(m->msg_qnum, &up->msg_qnum); 421 err |= __put_user(m->msg_qbytes, &up->msg_qbytes); 422 err |= __put_user(m->msg_lspid, &up->msg_lspid); 423 err |= __put_user(m->msg_lrpid, &up->msg_lrpid); 424 return err; 425 } 426 427 long compat_sys_msgctl(int first, int second, void __user *uptr) 428 { 429 int err, err2; 430 struct msqid64_ds m64; 431 int version = compat_ipc_parse_version(&second); 432 void __user *p; 433 434 switch (second & (~IPC_64)) { 435 case IPC_INFO: 436 case IPC_RMID: 437 case MSG_INFO: 438 err = sys_msgctl(first, second, uptr); 439 break; 440 441 case IPC_SET: 442 if (version == IPC_64) { 443 err = get_compat_msqid64(&m64, uptr); 444 } else { 445 err = get_compat_msqid(&m64, uptr); 446 } 447 if (err) 448 break; 449 p = compat_alloc_user_space(sizeof(m64)); 450 if (copy_to_user(p, &m64, sizeof(m64))) 451 err = -EFAULT; 452 else 453 err = sys_msgctl(first, second, p); 454 break; 455 456 case IPC_STAT: 457 case MSG_STAT: 458 p = compat_alloc_user_space(sizeof(m64)); 459 err = sys_msgctl(first, second, p); 460 if (err < 0) 461 break; 462 if (copy_from_user(&m64, p, sizeof(m64))) 463 err2 = -EFAULT; 464 else if (version == IPC_64) 465 err2 = put_compat_msqid64_ds(&m64, uptr); 466 else 467 err2 = put_compat_msqid_ds(&m64, uptr); 468 if (err2) 469 err = -EFAULT; 470 break; 471 472 default: 473 err = -EINVAL; 474 break; 475 } 476 return err; 477 } 478 479 long compat_sys_shmat(int first, int second, compat_uptr_t third, int version, 480 void __user *uptr) 481 { 482 int err; 483 unsigned long raddr; 484 compat_ulong_t __user *uaddr; 485 486 if (version == 1) 487 return -EINVAL; 488 err = do_shmat(first, uptr, second, &raddr); 489 if (err < 0) 490 return err; 491 uaddr = compat_ptr(third); 492 return put_user(raddr, uaddr); 493 } 494 495 static inline int get_compat_shmid64_ds(struct shmid64_ds *s64, 496 struct compat_shmid64_ds __user *up64) 497 { 498 if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) 499 return -EFAULT; 500 return __get_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm); 501 } 502 503 static inline int get_compat_shmid_ds(struct shmid64_ds *s, 504 struct compat_shmid_ds __user *up) 505 { 506 if (!access_ok(VERIFY_READ, up, sizeof(*up))) 507 return -EFAULT; 508 return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm); 509 } 510 511 static inline int put_compat_shmid64_ds(struct shmid64_ds *s64, 512 struct compat_shmid64_ds __user *up64) 513 { 514 int err; 515 516 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) 517 return -EFAULT; 518 err = __put_compat_ipc64_perm(&s64->shm_perm, &up64->shm_perm); 519 err |= __put_user(s64->shm_atime, &up64->shm_atime); 520 err |= __put_user(s64->shm_dtime, &up64->shm_dtime); 521 err |= __put_user(s64->shm_ctime, &up64->shm_ctime); 522 err |= __put_user(s64->shm_segsz, &up64->shm_segsz); 523 err |= __put_user(s64->shm_nattch, &up64->shm_nattch); 524 err |= __put_user(s64->shm_cpid, &up64->shm_cpid); 525 err |= __put_user(s64->shm_lpid, &up64->shm_lpid); 526 return err; 527 } 528 529 static inline int put_compat_shmid_ds(struct shmid64_ds *s, 530 struct compat_shmid_ds __user *up) 531 { 532 int err; 533 534 if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) 535 return -EFAULT; 536 err = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm); 537 err |= __put_user(s->shm_atime, &up->shm_atime); 538 err |= __put_user(s->shm_dtime, &up->shm_dtime); 539 err |= __put_user(s->shm_ctime, &up->shm_ctime); 540 err |= __put_user(s->shm_segsz, &up->shm_segsz); 541 err |= __put_user(s->shm_nattch, &up->shm_nattch); 542 err |= __put_user(s->shm_cpid, &up->shm_cpid); 543 err |= __put_user(s->shm_lpid, &up->shm_lpid); 544 return err; 545 } 546 547 static inline int put_compat_shminfo64(struct shminfo64 *smi, 548 struct compat_shminfo64 __user *up64) 549 { 550 int err; 551 552 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) 553 return -EFAULT; 554 err = __put_user(smi->shmmax, &up64->shmmax); 555 err |= __put_user(smi->shmmin, &up64->shmmin); 556 err |= __put_user(smi->shmmni, &up64->shmmni); 557 err |= __put_user(smi->shmseg, &up64->shmseg); 558 err |= __put_user(smi->shmall, &up64->shmall); 559 return err; 560 } 561 562 static inline int put_compat_shminfo(struct shminfo64 *smi, 563 struct shminfo __user *up) 564 { 565 int err; 566 567 if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) 568 return -EFAULT; 569 err = __put_user(smi->shmmax, &up->shmmax); 570 err |= __put_user(smi->shmmin, &up->shmmin); 571 err |= __put_user(smi->shmmni, &up->shmmni); 572 err |= __put_user(smi->shmseg, &up->shmseg); 573 err |= __put_user(smi->shmall, &up->shmall); 574 return err; 575 } 576 577 static inline int put_compat_shm_info(struct shm_info __user *ip, 578 struct compat_shm_info __user *uip) 579 { 580 int err; 581 struct shm_info si; 582 583 if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) || 584 copy_from_user(&si, ip, sizeof(si))) 585 return -EFAULT; 586 err = __put_user(si.used_ids, &uip->used_ids); 587 err |= __put_user(si.shm_tot, &uip->shm_tot); 588 err |= __put_user(si.shm_rss, &uip->shm_rss); 589 err |= __put_user(si.shm_swp, &uip->shm_swp); 590 err |= __put_user(si.swap_attempts, &uip->swap_attempts); 591 err |= __put_user(si.swap_successes, &uip->swap_successes); 592 return err; 593 } 594 595 long compat_sys_shmctl(int first, int second, void __user *uptr) 596 { 597 void __user *p; 598 struct shmid64_ds s64; 599 struct shminfo64 smi; 600 int err, err2; 601 int version = compat_ipc_parse_version(&second); 602 603 switch (second & (~IPC_64)) { 604 case IPC_RMID: 605 case SHM_LOCK: 606 case SHM_UNLOCK: 607 err = sys_shmctl(first, second, uptr); 608 break; 609 610 case IPC_INFO: 611 p = compat_alloc_user_space(sizeof(smi)); 612 err = sys_shmctl(first, second, p); 613 if (err < 0) 614 break; 615 if (copy_from_user(&smi, p, sizeof(smi))) 616 err2 = -EFAULT; 617 else if (version == IPC_64) 618 err2 = put_compat_shminfo64(&smi, uptr); 619 else 620 err2 = put_compat_shminfo(&smi, uptr); 621 if (err2) 622 err = -EFAULT; 623 break; 624 625 626 case IPC_SET: 627 if (version == IPC_64) { 628 err = get_compat_shmid64_ds(&s64, uptr); 629 } else { 630 err = get_compat_shmid_ds(&s64, uptr); 631 } 632 if (err) 633 break; 634 p = compat_alloc_user_space(sizeof(s64)); 635 if (copy_to_user(p, &s64, sizeof(s64))) 636 err = -EFAULT; 637 else 638 err = sys_shmctl(first, second, p); 639 break; 640 641 case IPC_STAT: 642 case SHM_STAT: 643 p = compat_alloc_user_space(sizeof(s64)); 644 err = sys_shmctl(first, second, p); 645 if (err < 0) 646 break; 647 if (copy_from_user(&s64, p, sizeof(s64))) 648 err2 = -EFAULT; 649 else if (version == IPC_64) 650 err2 = put_compat_shmid64_ds(&s64, uptr); 651 else 652 err2 = put_compat_shmid_ds(&s64, uptr); 653 if (err2) 654 err = -EFAULT; 655 break; 656 657 case SHM_INFO: 658 p = compat_alloc_user_space(sizeof(struct shm_info)); 659 err = sys_shmctl(first, second, p); 660 if (err < 0) 661 break; 662 err2 = put_compat_shm_info(p, uptr); 663 if (err2) 664 err = -EFAULT; 665 break; 666 667 default: 668 err = -EINVAL; 669 break; 670 } 671 return err; 672 } 673 674 long compat_sys_semtimedop(int semid, struct sembuf __user *tsems, 675 unsigned nsops, const struct compat_timespec __user *timeout) 676 { 677 struct timespec __user *ts64 = NULL; 678 if (timeout) { 679 struct timespec ts; 680 ts64 = compat_alloc_user_space(sizeof(*ts64)); 681 if (get_compat_timespec(&ts, timeout)) 682 return -EFAULT; 683 if (copy_to_user(ts64, &ts, sizeof(ts))) 684 return -EFAULT; 685 } 686 return sys_semtimedop(semid, tsems, nsops, ts64); 687 } 688