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