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/syscalls.h> 30 #include <linux/ptrace.h> 31 32 #include <linux/mutex.h> 33 #include <linux/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 static inline int compat_ipc_parse_version(int *cmd) 117 { 118 #ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION 119 int version = *cmd & IPC_64; 120 121 /* this is tricky: architectures that have support for the old 122 * ipc structures in 64 bit binaries need to have IPC_64 set 123 * in cmd, the others need to have it cleared */ 124 #ifndef ipc_parse_version 125 *cmd |= IPC_64; 126 #else 127 *cmd &= ~IPC_64; 128 #endif 129 return version; 130 #else 131 /* With the asm-generic APIs, we always use the 64-bit versions. */ 132 return IPC_64; 133 #endif 134 } 135 136 static inline int __get_compat_ipc64_perm(struct ipc64_perm *p64, 137 struct compat_ipc64_perm __user *up64) 138 { 139 int err; 140 141 err = __get_user(p64->uid, &up64->uid); 142 err |= __get_user(p64->gid, &up64->gid); 143 err |= __get_user(p64->mode, &up64->mode); 144 return err; 145 } 146 147 static inline int __get_compat_ipc_perm(struct ipc64_perm *p, 148 struct compat_ipc_perm __user *up) 149 { 150 int err; 151 152 err = __get_user(p->uid, &up->uid); 153 err |= __get_user(p->gid, &up->gid); 154 err |= __get_user(p->mode, &up->mode); 155 return err; 156 } 157 158 static inline int __put_compat_ipc64_perm(struct ipc64_perm *p64, 159 struct compat_ipc64_perm __user *up64) 160 { 161 int err; 162 163 err = __put_user(p64->key, &up64->key); 164 err |= __put_user(p64->uid, &up64->uid); 165 err |= __put_user(p64->gid, &up64->gid); 166 err |= __put_user(p64->cuid, &up64->cuid); 167 err |= __put_user(p64->cgid, &up64->cgid); 168 err |= __put_user(p64->mode, &up64->mode); 169 err |= __put_user(p64->seq, &up64->seq); 170 return err; 171 } 172 173 static inline int __put_compat_ipc_perm(struct ipc64_perm *p, 174 struct compat_ipc_perm __user *uip) 175 { 176 int err; 177 __compat_uid_t u; 178 __compat_gid_t g; 179 180 err = __put_user(p->key, &uip->key); 181 SET_UID(u, p->uid); 182 err |= __put_user(u, &uip->uid); 183 SET_GID(g, p->gid); 184 err |= __put_user(g, &uip->gid); 185 SET_UID(u, p->cuid); 186 err |= __put_user(u, &uip->cuid); 187 SET_GID(g, p->cgid); 188 err |= __put_user(g, &uip->cgid); 189 err |= __put_user(p->mode, &uip->mode); 190 err |= __put_user(p->seq, &uip->seq); 191 return err; 192 } 193 194 static inline int get_compat_semid64_ds(struct semid64_ds *sem64, 195 struct compat_semid64_ds __user *up64) 196 { 197 if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) 198 return -EFAULT; 199 return __get_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm); 200 } 201 202 static inline int get_compat_semid_ds(struct semid64_ds *s, 203 struct compat_semid_ds __user *up) 204 { 205 if (!access_ok(VERIFY_READ, up, sizeof(*up))) 206 return -EFAULT; 207 return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm); 208 } 209 210 static inline int put_compat_semid64_ds(struct semid64_ds *sem64, 211 struct compat_semid64_ds __user *up64) 212 { 213 int err; 214 215 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) 216 return -EFAULT; 217 err = __put_compat_ipc64_perm(&sem64->sem_perm, &up64->sem_perm); 218 err |= __put_user(sem64->sem_otime, &up64->sem_otime); 219 err |= __put_user(sem64->sem_ctime, &up64->sem_ctime); 220 err |= __put_user(sem64->sem_nsems, &up64->sem_nsems); 221 return err; 222 } 223 224 static inline int put_compat_semid_ds(struct semid64_ds *s, 225 struct compat_semid_ds __user *up) 226 { 227 int err; 228 229 if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) 230 return -EFAULT; 231 err = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm); 232 err |= __put_user(s->sem_otime, &up->sem_otime); 233 err |= __put_user(s->sem_ctime, &up->sem_ctime); 234 err |= __put_user(s->sem_nsems, &up->sem_nsems); 235 return err; 236 } 237 238 static long do_compat_semctl(int first, int second, int third, u32 pad) 239 { 240 unsigned long fourth; 241 int err, err2; 242 struct semid64_ds sem64; 243 struct semid64_ds __user *up64; 244 int version = compat_ipc_parse_version(&third); 245 246 memset(&sem64, 0, sizeof(sem64)); 247 248 if ((third & (~IPC_64)) == SETVAL) 249 #ifdef __BIG_ENDIAN 250 fourth = (unsigned long)pad << 32; 251 #else 252 fourth = pad; 253 #endif 254 else 255 fourth = (unsigned long)compat_ptr(pad); 256 switch (third & (~IPC_64)) { 257 case IPC_INFO: 258 case IPC_RMID: 259 case SEM_INFO: 260 case GETVAL: 261 case GETPID: 262 case GETNCNT: 263 case GETZCNT: 264 case GETALL: 265 case SETVAL: 266 case SETALL: 267 err = sys_semctl(first, second, third, fourth); 268 break; 269 270 case IPC_STAT: 271 case SEM_STAT: 272 up64 = compat_alloc_user_space(sizeof(sem64)); 273 fourth = (unsigned long)up64; 274 err = sys_semctl(first, second, third, fourth); 275 if (err < 0) 276 break; 277 if (copy_from_user(&sem64, up64, sizeof(sem64))) 278 err2 = -EFAULT; 279 else if (version == IPC_64) 280 err2 = put_compat_semid64_ds(&sem64, compat_ptr(pad)); 281 else 282 err2 = put_compat_semid_ds(&sem64, compat_ptr(pad)); 283 if (err2) 284 err = -EFAULT; 285 break; 286 287 case IPC_SET: 288 if (version == IPC_64) 289 err = get_compat_semid64_ds(&sem64, compat_ptr(pad)); 290 else 291 err = get_compat_semid_ds(&sem64, compat_ptr(pad)); 292 293 up64 = compat_alloc_user_space(sizeof(sem64)); 294 if (copy_to_user(up64, &sem64, sizeof(sem64))) 295 err = -EFAULT; 296 if (err) 297 break; 298 299 fourth = (unsigned long)up64; 300 err = sys_semctl(first, second, third, fourth); 301 break; 302 303 default: 304 err = -EINVAL; 305 break; 306 } 307 return err; 308 } 309 310 static long compat_do_msg_fill(void __user *dest, struct msg_msg *msg, size_t bufsz) 311 { 312 struct compat_msgbuf __user *msgp = dest; 313 size_t msgsz; 314 315 if (put_user(msg->m_type, &msgp->mtype)) 316 return -EFAULT; 317 318 msgsz = (bufsz > msg->m_ts) ? msg->m_ts : bufsz; 319 if (store_msg(msgp->mtext, msg, msgsz)) 320 return -EFAULT; 321 return msgsz; 322 } 323 324 #ifndef COMPAT_SHMLBA 325 #define COMPAT_SHMLBA SHMLBA 326 #endif 327 328 #ifdef CONFIG_ARCH_WANT_OLD_COMPAT_IPC 329 COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second, 330 u32, third, compat_uptr_t, ptr, u32, fifth) 331 { 332 int version; 333 u32 pad; 334 335 version = call >> 16; /* hack for backward compatibility */ 336 call &= 0xffff; 337 338 switch (call) { 339 case SEMOP: 340 /* struct sembuf is the same on 32 and 64bit :)) */ 341 return sys_semtimedop(first, compat_ptr(ptr), second, NULL); 342 case SEMTIMEDOP: 343 return compat_sys_semtimedop(first, compat_ptr(ptr), second, 344 compat_ptr(fifth)); 345 case SEMGET: 346 return sys_semget(first, second, third); 347 case SEMCTL: 348 if (!ptr) 349 return -EINVAL; 350 if (get_user(pad, (u32 __user *) compat_ptr(ptr))) 351 return -EFAULT; 352 return do_compat_semctl(first, second, third, pad); 353 354 case MSGSND: { 355 struct compat_msgbuf __user *up = compat_ptr(ptr); 356 compat_long_t type; 357 358 if (first < 0 || second < 0) 359 return -EINVAL; 360 361 if (get_user(type, &up->mtype)) 362 return -EFAULT; 363 364 return do_msgsnd(first, type, up->mtext, second, third); 365 } 366 case MSGRCV: { 367 void __user *uptr = compat_ptr(ptr); 368 369 if (first < 0 || second < 0) 370 return -EINVAL; 371 372 if (!version) { 373 struct compat_ipc_kludge ipck; 374 if (!uptr) 375 return -EINVAL; 376 if (copy_from_user(&ipck, uptr, sizeof(ipck))) 377 return -EFAULT; 378 uptr = compat_ptr(ipck.msgp); 379 fifth = ipck.msgtyp; 380 } 381 return do_msgrcv(first, uptr, second, (s32)fifth, third, 382 compat_do_msg_fill); 383 } 384 case MSGGET: 385 return sys_msgget(first, second); 386 case MSGCTL: 387 return compat_sys_msgctl(first, second, compat_ptr(ptr)); 388 389 case SHMAT: { 390 int err; 391 unsigned long raddr; 392 393 if (version == 1) 394 return -EINVAL; 395 err = do_shmat(first, compat_ptr(ptr), second, &raddr, 396 COMPAT_SHMLBA); 397 if (err < 0) 398 return err; 399 return put_user(raddr, (compat_ulong_t *)compat_ptr(third)); 400 } 401 case SHMDT: 402 return sys_shmdt(compat_ptr(ptr)); 403 case SHMGET: 404 return sys_shmget(first, (unsigned)second, third); 405 case SHMCTL: 406 return compat_sys_shmctl(first, second, compat_ptr(ptr)); 407 } 408 409 return -ENOSYS; 410 } 411 #endif 412 413 COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg) 414 { 415 return do_compat_semctl(semid, semnum, cmd, arg); 416 } 417 418 COMPAT_SYSCALL_DEFINE4(msgsnd, int, msqid, compat_uptr_t, msgp, 419 compat_ssize_t, msgsz, int, msgflg) 420 { 421 struct compat_msgbuf __user *up = compat_ptr(msgp); 422 compat_long_t mtype; 423 424 if (get_user(mtype, &up->mtype)) 425 return -EFAULT; 426 return do_msgsnd(msqid, mtype, up->mtext, (ssize_t)msgsz, msgflg); 427 } 428 429 COMPAT_SYSCALL_DEFINE5(msgrcv, int, msqid, compat_uptr_t, msgp, 430 compat_ssize_t, msgsz, compat_long_t, msgtyp, int, msgflg) 431 { 432 return do_msgrcv(msqid, compat_ptr(msgp), (ssize_t)msgsz, (long)msgtyp, 433 msgflg, compat_do_msg_fill); 434 } 435 436 static inline int get_compat_msqid64(struct msqid64_ds *m64, 437 struct compat_msqid64_ds __user *up64) 438 { 439 int err; 440 441 if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) 442 return -EFAULT; 443 err = __get_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm); 444 err |= __get_user(m64->msg_qbytes, &up64->msg_qbytes); 445 return err; 446 } 447 448 static inline int get_compat_msqid(struct msqid64_ds *m, 449 struct compat_msqid_ds __user *up) 450 { 451 int err; 452 453 if (!access_ok(VERIFY_READ, up, sizeof(*up))) 454 return -EFAULT; 455 err = __get_compat_ipc_perm(&m->msg_perm, &up->msg_perm); 456 err |= __get_user(m->msg_qbytes, &up->msg_qbytes); 457 return err; 458 } 459 460 static inline int put_compat_msqid64_ds(struct msqid64_ds *m64, 461 struct compat_msqid64_ds __user *up64) 462 { 463 int err; 464 465 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) 466 return -EFAULT; 467 err = __put_compat_ipc64_perm(&m64->msg_perm, &up64->msg_perm); 468 err |= __put_user(m64->msg_stime, &up64->msg_stime); 469 err |= __put_user(m64->msg_rtime, &up64->msg_rtime); 470 err |= __put_user(m64->msg_ctime, &up64->msg_ctime); 471 err |= __put_user(m64->msg_cbytes, &up64->msg_cbytes); 472 err |= __put_user(m64->msg_qnum, &up64->msg_qnum); 473 err |= __put_user(m64->msg_qbytes, &up64->msg_qbytes); 474 err |= __put_user(m64->msg_lspid, &up64->msg_lspid); 475 err |= __put_user(m64->msg_lrpid, &up64->msg_lrpid); 476 return err; 477 } 478 479 static inline int put_compat_msqid_ds(struct msqid64_ds *m, 480 struct compat_msqid_ds __user *up) 481 { 482 int err; 483 484 if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) 485 return -EFAULT; 486 err = __put_compat_ipc_perm(&m->msg_perm, &up->msg_perm); 487 err |= __put_user(m->msg_stime, &up->msg_stime); 488 err |= __put_user(m->msg_rtime, &up->msg_rtime); 489 err |= __put_user(m->msg_ctime, &up->msg_ctime); 490 err |= __put_user(m->msg_cbytes, &up->msg_cbytes); 491 err |= __put_user(m->msg_qnum, &up->msg_qnum); 492 err |= __put_user(m->msg_qbytes, &up->msg_qbytes); 493 err |= __put_user(m->msg_lspid, &up->msg_lspid); 494 err |= __put_user(m->msg_lrpid, &up->msg_lrpid); 495 return err; 496 } 497 498 COMPAT_SYSCALL_DEFINE3(msgctl, int, first, int, second, void __user *, uptr) 499 { 500 int err, err2; 501 struct msqid64_ds m64; 502 int version = compat_ipc_parse_version(&second); 503 void __user *p; 504 505 memset(&m64, 0, sizeof(m64)); 506 507 switch (second & (~IPC_64)) { 508 case IPC_INFO: 509 case IPC_RMID: 510 case MSG_INFO: 511 err = sys_msgctl(first, second, uptr); 512 break; 513 514 case IPC_SET: 515 if (version == IPC_64) 516 err = get_compat_msqid64(&m64, uptr); 517 else 518 err = get_compat_msqid(&m64, uptr); 519 520 if (err) 521 break; 522 p = compat_alloc_user_space(sizeof(m64)); 523 if (copy_to_user(p, &m64, sizeof(m64))) 524 err = -EFAULT; 525 else 526 err = sys_msgctl(first, second, p); 527 break; 528 529 case IPC_STAT: 530 case MSG_STAT: 531 p = compat_alloc_user_space(sizeof(m64)); 532 err = sys_msgctl(first, second, p); 533 if (err < 0) 534 break; 535 if (copy_from_user(&m64, p, sizeof(m64))) 536 err2 = -EFAULT; 537 else if (version == IPC_64) 538 err2 = put_compat_msqid64_ds(&m64, uptr); 539 else 540 err2 = put_compat_msqid_ds(&m64, uptr); 541 if (err2) 542 err = -EFAULT; 543 break; 544 545 default: 546 err = -EINVAL; 547 break; 548 } 549 return err; 550 } 551 552 COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg) 553 { 554 unsigned long ret; 555 long err; 556 557 err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA); 558 if (err) 559 return err; 560 force_successful_syscall_return(); 561 return (long)ret; 562 } 563 564 static inline int get_compat_shmid64_ds(struct shmid64_ds *sem64, 565 struct compat_shmid64_ds __user *up64) 566 { 567 if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) 568 return -EFAULT; 569 return __get_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm); 570 } 571 572 static inline int get_compat_shmid_ds(struct shmid64_ds *s, 573 struct compat_shmid_ds __user *up) 574 { 575 if (!access_ok(VERIFY_READ, up, sizeof(*up))) 576 return -EFAULT; 577 return __get_compat_ipc_perm(&s->shm_perm, &up->shm_perm); 578 } 579 580 static inline int put_compat_shmid64_ds(struct shmid64_ds *sem64, 581 struct compat_shmid64_ds __user *up64) 582 { 583 int err; 584 585 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) 586 return -EFAULT; 587 err = __put_compat_ipc64_perm(&sem64->shm_perm, &up64->shm_perm); 588 err |= __put_user(sem64->shm_atime, &up64->shm_atime); 589 err |= __put_user(sem64->shm_dtime, &up64->shm_dtime); 590 err |= __put_user(sem64->shm_ctime, &up64->shm_ctime); 591 err |= __put_user(sem64->shm_segsz, &up64->shm_segsz); 592 err |= __put_user(sem64->shm_nattch, &up64->shm_nattch); 593 err |= __put_user(sem64->shm_cpid, &up64->shm_cpid); 594 err |= __put_user(sem64->shm_lpid, &up64->shm_lpid); 595 return err; 596 } 597 598 static inline int put_compat_shmid_ds(struct shmid64_ds *s, 599 struct compat_shmid_ds __user *up) 600 { 601 int err; 602 603 if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) 604 return -EFAULT; 605 err = __put_compat_ipc_perm(&s->shm_perm, &up->shm_perm); 606 err |= __put_user(s->shm_atime, &up->shm_atime); 607 err |= __put_user(s->shm_dtime, &up->shm_dtime); 608 err |= __put_user(s->shm_ctime, &up->shm_ctime); 609 err |= __put_user(s->shm_segsz, &up->shm_segsz); 610 err |= __put_user(s->shm_nattch, &up->shm_nattch); 611 err |= __put_user(s->shm_cpid, &up->shm_cpid); 612 err |= __put_user(s->shm_lpid, &up->shm_lpid); 613 return err; 614 } 615 616 static inline int put_compat_shminfo64(struct shminfo64 *smi, 617 struct compat_shminfo64 __user *up64) 618 { 619 int err; 620 621 if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) 622 return -EFAULT; 623 if (smi->shmmax > INT_MAX) 624 smi->shmmax = INT_MAX; 625 err = __put_user(smi->shmmax, &up64->shmmax); 626 err |= __put_user(smi->shmmin, &up64->shmmin); 627 err |= __put_user(smi->shmmni, &up64->shmmni); 628 err |= __put_user(smi->shmseg, &up64->shmseg); 629 err |= __put_user(smi->shmall, &up64->shmall); 630 return err; 631 } 632 633 static inline int put_compat_shminfo(struct shminfo64 *smi, 634 struct shminfo __user *up) 635 { 636 int err; 637 638 if (!access_ok(VERIFY_WRITE, up, sizeof(*up))) 639 return -EFAULT; 640 if (smi->shmmax > INT_MAX) 641 smi->shmmax = INT_MAX; 642 err = __put_user(smi->shmmax, &up->shmmax); 643 err |= __put_user(smi->shmmin, &up->shmmin); 644 err |= __put_user(smi->shmmni, &up->shmmni); 645 err |= __put_user(smi->shmseg, &up->shmseg); 646 err |= __put_user(smi->shmall, &up->shmall); 647 return err; 648 } 649 650 static inline int put_compat_shm_info(struct shm_info __user *ip, 651 struct compat_shm_info __user *uip) 652 { 653 int err; 654 struct shm_info si; 655 656 if (!access_ok(VERIFY_WRITE, uip, sizeof(*uip)) || 657 copy_from_user(&si, ip, sizeof(si))) 658 return -EFAULT; 659 err = __put_user(si.used_ids, &uip->used_ids); 660 err |= __put_user(si.shm_tot, &uip->shm_tot); 661 err |= __put_user(si.shm_rss, &uip->shm_rss); 662 err |= __put_user(si.shm_swp, &uip->shm_swp); 663 err |= __put_user(si.swap_attempts, &uip->swap_attempts); 664 err |= __put_user(si.swap_successes, &uip->swap_successes); 665 return err; 666 } 667 668 COMPAT_SYSCALL_DEFINE3(shmctl, int, first, int, second, void __user *, uptr) 669 { 670 void __user *p; 671 struct shmid64_ds sem64; 672 struct shminfo64 smi; 673 int err, err2; 674 int version = compat_ipc_parse_version(&second); 675 676 memset(&sem64, 0, sizeof(sem64)); 677 678 switch (second & (~IPC_64)) { 679 case IPC_RMID: 680 case SHM_LOCK: 681 case SHM_UNLOCK: 682 err = sys_shmctl(first, second, uptr); 683 break; 684 685 case IPC_INFO: 686 p = compat_alloc_user_space(sizeof(smi)); 687 err = sys_shmctl(first, second, p); 688 if (err < 0) 689 break; 690 if (copy_from_user(&smi, p, sizeof(smi))) 691 err2 = -EFAULT; 692 else if (version == IPC_64) 693 err2 = put_compat_shminfo64(&smi, uptr); 694 else 695 err2 = put_compat_shminfo(&smi, uptr); 696 if (err2) 697 err = -EFAULT; 698 break; 699 700 701 case IPC_SET: 702 if (version == IPC_64) 703 err = get_compat_shmid64_ds(&sem64, uptr); 704 else 705 err = get_compat_shmid_ds(&sem64, uptr); 706 707 if (err) 708 break; 709 p = compat_alloc_user_space(sizeof(sem64)); 710 if (copy_to_user(p, &sem64, sizeof(sem64))) 711 err = -EFAULT; 712 else 713 err = sys_shmctl(first, second, p); 714 break; 715 716 case IPC_STAT: 717 case SHM_STAT: 718 p = compat_alloc_user_space(sizeof(sem64)); 719 err = sys_shmctl(first, second, p); 720 if (err < 0) 721 break; 722 if (copy_from_user(&sem64, p, sizeof(sem64))) 723 err2 = -EFAULT; 724 else if (version == IPC_64) 725 err2 = put_compat_shmid64_ds(&sem64, uptr); 726 else 727 err2 = put_compat_shmid_ds(&sem64, uptr); 728 if (err2) 729 err = -EFAULT; 730 break; 731 732 case SHM_INFO: 733 p = compat_alloc_user_space(sizeof(struct shm_info)); 734 err = sys_shmctl(first, second, p); 735 if (err < 0) 736 break; 737 err2 = put_compat_shm_info(p, uptr); 738 if (err2) 739 err = -EFAULT; 740 break; 741 742 default: 743 err = -EINVAL; 744 break; 745 } 746 return err; 747 } 748 749 COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, 750 unsigned, nsops, 751 const struct compat_timespec __user *, timeout) 752 { 753 struct timespec __user *ts64; 754 if (compat_convert_timespec(&ts64, timeout)) 755 return -EFAULT; 756 return sys_semtimedop(semid, tsems, nsops, ts64); 757 } 758