diff options
| author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2006-11-07 04:02:44 -0500 |
|---|---|---|
| committer | Ralf Baechle <ralf@linux-mips.org> | 2006-12-04 17:43:12 -0500 |
| commit | 05e4396651ca1cac51d8da9ff4992741c9dc1e39 (patch) | |
| tree | 15881e19dfd7550dbe26245a356a10a979577086 | |
| parent | 9567772f14f6d2692ea88ddc111a5a6b352fd512 (diff) | |
[MIPS] Use SYSVIPC_COMPAT to fix various problems on N32
N32 SysV IPC system calls should use 32-bit compatible code.
arch/mips/kernel/linux32.c have similar compatible code for O32, but
ipc/compat.c seems more complete. We can use it for both N32 and O32.
This patch should fix these problems (and other possible problems):
http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=1149188824.6986.6.camel%40diimka-laptop
http://www.linux-mips.org/cgi-bin/mesg.cgi?a=linux-mips&i=44C6B829.8050508%40caviumnetworks.com
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
| -rw-r--r-- | arch/mips/Kconfig | 5 | ||||
| -rw-r--r-- | arch/mips/kernel/linux32.c | 578 | ||||
| -rw-r--r-- | arch/mips/kernel/scall64-n32.S | 14 | ||||
| -rw-r--r-- | include/asm-mips/compat.h | 68 |
4 files changed, 103 insertions, 562 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 27f83e642968..2308c8ef0218 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
| @@ -1940,6 +1940,11 @@ config COMPAT | |||
| 1940 | depends on MIPS32_COMPAT | 1940 | depends on MIPS32_COMPAT |
| 1941 | default y | 1941 | default y |
| 1942 | 1942 | ||
| 1943 | config SYSVIPC_COMPAT | ||
| 1944 | bool | ||
| 1945 | depends on COMPAT && SYSVIPC | ||
| 1946 | default y | ||
| 1947 | |||
| 1943 | config MIPS32_O32 | 1948 | config MIPS32_O32 |
| 1944 | bool "Kernel support for o32 binaries" | 1949 | bool "Kernel support for o32 binaries" |
| 1945 | depends on MIPS32_COMPAT | 1950 | depends on MIPS32_COMPAT |
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 7a3ebbeba1f3..b061c9aa6302 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c | |||
| @@ -382,531 +382,6 @@ asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid, | |||
| 382 | return ret; | 382 | return ret; |
| 383 | } | 383 | } |
| 384 | 384 | ||
| 385 | struct msgbuf32 { s32 mtype; char mtext[1]; }; | ||
| 386 | |||
| 387 | struct ipc_perm32 | ||
| 388 | { | ||
| 389 | key_t key; | ||
| 390 | __compat_uid_t uid; | ||
| 391 | __compat_gid_t gid; | ||
| 392 | __compat_uid_t cuid; | ||
| 393 | __compat_gid_t cgid; | ||
| 394 | compat_mode_t mode; | ||
| 395 | unsigned short seq; | ||
| 396 | }; | ||
| 397 | |||
| 398 | struct ipc64_perm32 { | ||
| 399 | key_t key; | ||
| 400 | __compat_uid_t uid; | ||
| 401 | __compat_gid_t gid; | ||
| 402 | __compat_uid_t cuid; | ||
| 403 | __compat_gid_t cgid; | ||
| 404 | compat_mode_t mode; | ||
| 405 | unsigned short seq; | ||
| 406 | unsigned short __pad1; | ||
| 407 | unsigned int __unused1; | ||
| 408 | unsigned int __unused2; | ||
| 409 | }; | ||
| 410 | |||
| 411 | struct semid_ds32 { | ||
| 412 | struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */ | ||
| 413 | compat_time_t sem_otime; /* last semop time */ | ||
| 414 | compat_time_t sem_ctime; /* last change time */ | ||
| 415 | u32 sem_base; /* ptr to first semaphore in array */ | ||
| 416 | u32 sem_pending; /* pending operations to be processed */ | ||
| 417 | u32 sem_pending_last; /* last pending operation */ | ||
| 418 | u32 undo; /* undo requests on this array */ | ||
| 419 | unsigned short sem_nsems; /* no. of semaphores in array */ | ||
| 420 | }; | ||
| 421 | |||
| 422 | struct semid64_ds32 { | ||
| 423 | struct ipc64_perm32 sem_perm; | ||
| 424 | compat_time_t sem_otime; | ||
| 425 | compat_time_t sem_ctime; | ||
| 426 | unsigned int sem_nsems; | ||
| 427 | unsigned int __unused1; | ||
| 428 | unsigned int __unused2; | ||
| 429 | }; | ||
| 430 | |||
| 431 | struct msqid_ds32 | ||
| 432 | { | ||
| 433 | struct ipc_perm32 msg_perm; | ||
| 434 | u32 msg_first; | ||
| 435 | u32 msg_last; | ||
| 436 | compat_time_t msg_stime; | ||
| 437 | compat_time_t msg_rtime; | ||
| 438 | compat_time_t msg_ctime; | ||
| 439 | u32 wwait; | ||
| 440 | u32 rwait; | ||
| 441 | unsigned short msg_cbytes; | ||
| 442 | unsigned short msg_qnum; | ||
| 443 | unsigned short msg_qbytes; | ||
| 444 | compat_ipc_pid_t msg_lspid; | ||
| 445 | compat_ipc_pid_t msg_lrpid; | ||
| 446 | }; | ||
| 447 | |||
| 448 | struct msqid64_ds32 { | ||
| 449 | struct ipc64_perm32 msg_perm; | ||
| 450 | compat_time_t msg_stime; | ||
| 451 | unsigned int __unused1; | ||
| 452 | compat_time_t msg_rtime; | ||
| 453 | unsigned int __unused2; | ||
| 454 | compat_time_t msg_ctime; | ||
| 455 | unsigned int __unused3; | ||
| 456 | unsigned int msg_cbytes; | ||
| 457 | unsigned int msg_qnum; | ||
| 458 | unsigned int msg_qbytes; | ||
| 459 | compat_pid_t msg_lspid; | ||
| 460 | compat_pid_t msg_lrpid; | ||
| 461 | unsigned int __unused4; | ||
| 462 | unsigned int __unused5; | ||
| 463 | }; | ||
| 464 | |||
| 465 | struct shmid_ds32 { | ||
| 466 | struct ipc_perm32 shm_perm; | ||
| 467 | int shm_segsz; | ||
| 468 | compat_time_t shm_atime; | ||
| 469 | compat_time_t shm_dtime; | ||
| 470 | compat_time_t shm_ctime; | ||
| 471 | compat_ipc_pid_t shm_cpid; | ||
| 472 | compat_ipc_pid_t shm_lpid; | ||
| 473 | unsigned short shm_nattch; | ||
| 474 | }; | ||
| 475 | |||
| 476 | struct shmid64_ds32 { | ||
| 477 | struct ipc64_perm32 shm_perm; | ||
| 478 | compat_size_t shm_segsz; | ||
| 479 | compat_time_t shm_atime; | ||
| 480 | compat_time_t shm_dtime; | ||
| 481 | compat_time_t shm_ctime; | ||
| 482 | compat_pid_t shm_cpid; | ||
| 483 | compat_pid_t shm_lpid; | ||
| 484 | unsigned int shm_nattch; | ||
| 485 | unsigned int __unused1; | ||
| 486 | unsigned int __unused2; | ||
| 487 | }; | ||
| 488 | |||
| 489 | struct ipc_kludge32 { | ||
| 490 | u32 msgp; | ||
| 491 | s32 msgtyp; | ||
| 492 | }; | ||
| 493 | |||
| 494 | static int | ||
| 495 | do_sys32_semctl(int first, int second, int third, void __user *uptr) | ||
| 496 | { | ||
| 497 | union semun fourth; | ||
| 498 | u32 pad; | ||
| 499 | int err, err2; | ||
| 500 | struct semid64_ds s; | ||
| 501 | mm_segment_t old_fs; | ||
| 502 | |||
| 503 | if (!uptr) | ||
| 504 | return -EINVAL; | ||
| 505 | err = -EFAULT; | ||
| 506 | if (get_user (pad, (u32 __user *)uptr)) | ||
| 507 | return err; | ||
| 508 | if ((third & ~IPC_64) == SETVAL) | ||
| 509 | fourth.val = (int)pad; | ||
| 510 | else | ||
| 511 | fourth.__pad = (void __user *)A(pad); | ||
| 512 | switch (third & ~IPC_64) { | ||
| 513 | case IPC_INFO: | ||
| 514 | case IPC_RMID: | ||
| 515 | case IPC_SET: | ||
| 516 | case SEM_INFO: | ||
| 517 | case GETVAL: | ||
| 518 | case GETPID: | ||
| 519 | case GETNCNT: | ||
| 520 | case GETZCNT: | ||
| 521 | case GETALL: | ||
| 522 | case SETVAL: | ||
| 523 | case SETALL: | ||
| 524 | err = sys_semctl (first, second, third, fourth); | ||
| 525 | break; | ||
| 526 | |||
| 527 | case IPC_STAT: | ||
| 528 | case SEM_STAT: | ||
| 529 | fourth.__pad = (struct semid64_ds __user *)&s; | ||
| 530 | old_fs = get_fs(); | ||
| 531 | set_fs(KERNEL_DS); | ||
| 532 | err = sys_semctl(first, second, third | IPC_64, fourth); | ||
| 533 | set_fs(old_fs); | ||
| 534 | |||
| 535 | if (third & IPC_64) { | ||
| 536 | struct semid64_ds32 __user *usp64 = (struct semid64_ds32 __user *) A(pad); | ||
| 537 | |||
| 538 | if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) { | ||
| 539 | err = -EFAULT; | ||
| 540 | break; | ||
| 541 | } | ||
| 542 | err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key); | ||
| 543 | err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid); | ||
| 544 | err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid); | ||
| 545 | err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid); | ||
| 546 | err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid); | ||
| 547 | err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode); | ||
| 548 | err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq); | ||
| 549 | err2 |= __put_user(s.sem_otime, &usp64->sem_otime); | ||
| 550 | err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime); | ||
| 551 | err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems); | ||
| 552 | } else { | ||
| 553 | struct semid_ds32 __user *usp32 = (struct semid_ds32 __user *) A(pad); | ||
| 554 | |||
| 555 | if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) { | ||
| 556 | err = -EFAULT; | ||
| 557 | break; | ||
| 558 | } | ||
| 559 | err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key); | ||
| 560 | err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid); | ||
| 561 | err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid); | ||
| 562 | err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid); | ||
| 563 | err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid); | ||
| 564 | err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode); | ||
| 565 | err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq); | ||
| 566 | err2 |= __put_user(s.sem_otime, &usp32->sem_otime); | ||
| 567 | err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime); | ||
| 568 | err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems); | ||
| 569 | } | ||
| 570 | if (err2) | ||
| 571 | err = -EFAULT; | ||
| 572 | break; | ||
| 573 | |||
| 574 | default: | ||
| 575 | err = - EINVAL; | ||
| 576 | break; | ||
| 577 | } | ||
| 578 | |||
| 579 | return err; | ||
| 580 | } | ||
| 581 | |||
| 582 | static int | ||
| 583 | do_sys32_msgsnd (int first, int second, int third, void __user *uptr) | ||
| 584 | { | ||
| 585 | struct msgbuf32 __user *up = (struct msgbuf32 __user *)uptr; | ||
| 586 | struct msgbuf *p; | ||
| 587 | mm_segment_t old_fs; | ||
| 588 | int err; | ||
| 589 | |||
| 590 | if (second < 0) | ||
| 591 | return -EINVAL; | ||
| 592 | p = kmalloc (second + sizeof (struct msgbuf) | ||
| 593 | + 4, GFP_USER); | ||
| 594 | if (!p) | ||
| 595 | return -ENOMEM; | ||
| 596 | err = get_user (p->mtype, &up->mtype); | ||
| 597 | if (err) | ||
| 598 | goto out; | ||
| 599 | err |= __copy_from_user (p->mtext, &up->mtext, second); | ||
| 600 | if (err) | ||
| 601 | goto out; | ||
| 602 | old_fs = get_fs (); | ||
| 603 | set_fs (KERNEL_DS); | ||
| 604 | err = sys_msgsnd (first, (struct msgbuf __user *)p, second, third); | ||
| 605 | set_fs (old_fs); | ||
| 606 | out: | ||
| 607 | kfree (p); | ||
| 608 | |||
| 609 | return err; | ||
| 610 | } | ||
| 611 | |||
| 612 | static int | ||
| 613 | do_sys32_msgrcv (int first, int second, int msgtyp, int third, | ||
| 614 | int version, void __user *uptr) | ||
| 615 | { | ||
| 616 | struct msgbuf32 __user *up; | ||
| 617 | struct msgbuf *p; | ||
| 618 | mm_segment_t old_fs; | ||
| 619 | int err; | ||
| 620 | |||
| 621 | if (!version) { | ||
| 622 | struct ipc_kludge32 __user *uipck = (struct ipc_kludge32 __user *)uptr; | ||
| 623 | struct ipc_kludge32 ipck; | ||
| 624 | |||
| 625 | err = -EINVAL; | ||
| 626 | if (!uptr) | ||
| 627 | goto out; | ||
| 628 | err = -EFAULT; | ||
| 629 | if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge32))) | ||
| 630 | goto out; | ||
| 631 | uptr = (void __user *)AA(ipck.msgp); | ||
| 632 | msgtyp = ipck.msgtyp; | ||
| 633 | } | ||
| 634 | |||
| 635 | if (second < 0) | ||
| 636 | return -EINVAL; | ||
| 637 | err = -ENOMEM; | ||
| 638 | p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER); | ||
| 639 | if (!p) | ||
| 640 | goto out; | ||
| 641 | old_fs = get_fs (); | ||
| 642 | set_fs (KERNEL_DS); | ||
| 643 | err = sys_msgrcv (first, (struct msgbuf __user *)p, second + 4, msgtyp, third); | ||
| 644 | set_fs (old_fs); | ||
| 645 | if (err < 0) | ||
| 646 | goto free_then_out; | ||
| 647 | up = (struct msgbuf32 __user *)uptr; | ||
| 648 | if (put_user (p->mtype, &up->mtype) || | ||
| 649 | __copy_to_user (&up->mtext, p->mtext, err)) | ||
| 650 | err = -EFAULT; | ||
| 651 | free_then_out: | ||
| 652 | kfree (p); | ||
| 653 | out: | ||
| 654 | return err; | ||
| 655 | } | ||
| 656 | |||
| 657 | static int | ||
| 658 | do_sys32_msgctl (int first, int second, void __user *uptr) | ||
| 659 | { | ||
| 660 | int err = -EINVAL, err2; | ||
| 661 | struct msqid64_ds m; | ||
| 662 | struct msqid_ds32 __user *up32 = (struct msqid_ds32 __user *)uptr; | ||
| 663 | struct msqid64_ds32 __user *up64 = (struct msqid64_ds32 __user *)uptr; | ||
| 664 | mm_segment_t old_fs; | ||
| 665 | |||
| 666 | switch (second & ~IPC_64) { | ||
| 667 | case IPC_INFO: | ||
| 668 | case IPC_RMID: | ||
| 669 | case MSG_INFO: | ||
| 670 | err = sys_msgctl (first, second, (struct msqid_ds __user *)uptr); | ||
| 671 | break; | ||
| 672 | |||
| 673 | case IPC_SET: | ||
| 674 | if (second & IPC_64) { | ||
| 675 | if (!access_ok(VERIFY_READ, up64, sizeof(*up64))) { | ||
| 676 | err = -EFAULT; | ||
| 677 | break; | ||
| 678 | } | ||
| 679 | err = __get_user(m.msg_perm.uid, &up64->msg_perm.uid); | ||
| 680 | err |= __get_user(m.msg_perm.gid, &up64->msg_perm.gid); | ||
| 681 | err |= __get_user(m.msg_perm.mode, &up64->msg_perm.mode); | ||
| 682 | err |= __get_user(m.msg_qbytes, &up64->msg_qbytes); | ||
| 683 | } else { | ||
| 684 | if (!access_ok(VERIFY_READ, up32, sizeof(*up32))) { | ||
| 685 | err = -EFAULT; | ||
| 686 | break; | ||
| 687 | } | ||
| 688 | err = __get_user(m.msg_perm.uid, &up32->msg_perm.uid); | ||
| 689 | err |= __get_user(m.msg_perm.gid, &up32->msg_perm.gid); | ||
| 690 | err |= __get_user(m.msg_perm.mode, &up32->msg_perm.mode); | ||
| 691 | err |= __get_user(m.msg_qbytes, &up32->msg_qbytes); | ||
| 692 | } | ||
| 693 | if (err) | ||
| 694 | break; | ||
| 695 | old_fs = get_fs(); | ||
| 696 | set_fs(KERNEL_DS); | ||
| 697 | err = sys_msgctl(first, second | IPC_64, (struct msqid_ds __user *)&m); | ||
| 698 | set_fs(old_fs); | ||
| 699 | break; | ||
| 700 | |||
| 701 | case IPC_STAT: | ||
| 702 | case MSG_STAT: | ||
| 703 | old_fs = get_fs(); | ||
| 704 | set_fs(KERNEL_DS); | ||
| 705 | err = sys_msgctl(first, second | IPC_64, (struct msqid_ds __user *)&m); | ||
| 706 | set_fs(old_fs); | ||
| 707 | if (second & IPC_64) { | ||
| 708 | if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { | ||
| 709 | err = -EFAULT; | ||
| 710 | break; | ||
| 711 | } | ||
| 712 | err2 = __put_user(m.msg_perm.key, &up64->msg_perm.key); | ||
| 713 | err2 |= __put_user(m.msg_perm.uid, &up64->msg_perm.uid); | ||
| 714 | err2 |= __put_user(m.msg_perm.gid, &up64->msg_perm.gid); | ||
| 715 | err2 |= __put_user(m.msg_perm.cuid, &up64->msg_perm.cuid); | ||
| 716 | err2 |= __put_user(m.msg_perm.cgid, &up64->msg_perm.cgid); | ||
| 717 | err2 |= __put_user(m.msg_perm.mode, &up64->msg_perm.mode); | ||
| 718 | err2 |= __put_user(m.msg_perm.seq, &up64->msg_perm.seq); | ||
| 719 | err2 |= __put_user(m.msg_stime, &up64->msg_stime); | ||
| 720 | err2 |= __put_user(m.msg_rtime, &up64->msg_rtime); | ||
| 721 | err2 |= __put_user(m.msg_ctime, &up64->msg_ctime); | ||
| 722 | err2 |= __put_user(m.msg_cbytes, &up64->msg_cbytes); | ||
| 723 | err2 |= __put_user(m.msg_qnum, &up64->msg_qnum); | ||
| 724 | err2 |= __put_user(m.msg_qbytes, &up64->msg_qbytes); | ||
| 725 | err2 |= __put_user(m.msg_lspid, &up64->msg_lspid); | ||
| 726 | err2 |= __put_user(m.msg_lrpid, &up64->msg_lrpid); | ||
| 727 | if (err2) | ||
| 728 | err = -EFAULT; | ||
| 729 | } else { | ||
| 730 | if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) { | ||
| 731 | err = -EFAULT; | ||
| 732 | break; | ||
| 733 | } | ||
| 734 | err2 = __put_user(m.msg_perm.key, &up32->msg_perm.key); | ||
| 735 | err2 |= __put_user(m.msg_perm.uid, &up32->msg_perm.uid); | ||
| 736 | err2 |= __put_user(m.msg_perm.gid, &up32->msg_perm.gid); | ||
| 737 | err2 |= __put_user(m.msg_perm.cuid, &up32->msg_perm.cuid); | ||
| 738 | err2 |= __put_user(m.msg_perm.cgid, &up32->msg_perm.cgid); | ||
| 739 | err2 |= __put_user(m.msg_perm.mode, &up32->msg_perm.mode); | ||
| 740 | err2 |= __put_user(m.msg_perm.seq, &up32->msg_perm.seq); | ||
| 741 | err2 |= __put_user(m.msg_stime, &up32->msg_stime); | ||
| 742 | err2 |= __put_user(m.msg_rtime, &up32->msg_rtime); | ||
| 743 | err2 |= __put_user(m.msg_ctime, &up32->msg_ctime); | ||
| 744 | err2 |= __put_user(m.msg_cbytes, &up32->msg_cbytes); | ||
| 745 | err2 |= __put_user(m.msg_qnum, &up32->msg_qnum); | ||
| 746 | err2 |= __put_user(m.msg_qbytes, &up32->msg_qbytes); | ||
| 747 | err2 |= __put_user(m.msg_lspid, &up32->msg_lspid); | ||
| 748 | err2 |= __put_user(m.msg_lrpid, &up32->msg_lrpid); | ||
| 749 | if (err2) | ||
| 750 | err = -EFAULT; | ||
| 751 | } | ||
| 752 | break; | ||
| 753 | } | ||
| 754 | |||
| 755 | return err; | ||
| 756 | } | ||
| 757 | |||
| 758 | static int | ||
| 759 | do_sys32_shmat (int first, int second, int third, int version, void __user *uptr) | ||
| 760 | { | ||
| 761 | unsigned long raddr; | ||
| 762 | u32 __user *uaddr = (u32 __user *)A((u32)third); | ||
| 763 | int err = -EINVAL; | ||
| 764 | |||
| 765 | if (version == 1) | ||
| 766 | return err; | ||
| 767 | err = do_shmat (first, uptr, second, &raddr); | ||
| 768 | if (err) | ||
| 769 | return err; | ||
| 770 | err = put_user (raddr, uaddr); | ||
| 771 | return err; | ||
| 772 | } | ||
| 773 | |||
| 774 | struct shm_info32 { | ||
| 775 | int used_ids; | ||
| 776 | u32 shm_tot, shm_rss, shm_swp; | ||
| 777 | u32 swap_attempts, swap_successes; | ||
| 778 | }; | ||
| 779 | |||
| 780 | static int | ||
| 781 | do_sys32_shmctl (int first, int second, void __user *uptr) | ||
| 782 | { | ||
| 783 | struct shmid64_ds32 __user *up64 = (struct shmid64_ds32 __user *)uptr; | ||
| 784 | struct shmid_ds32 __user *up32 = (struct shmid_ds32 __user *)uptr; | ||
| 785 | struct shm_info32 __user *uip = (struct shm_info32 __user *)uptr; | ||
| 786 | int err = -EFAULT, err2; | ||
| 787 | struct shmid64_ds s64; | ||
| 788 | mm_segment_t old_fs; | ||
| 789 | struct shm_info si; | ||
| 790 | struct shmid_ds s; | ||
| 791 | |||
| 792 | switch (second & ~IPC_64) { | ||
| 793 | case IPC_INFO: | ||
| 794 | second = IPC_INFO; /* So that we don't have to translate it */ | ||
| 795 | case IPC_RMID: | ||
| 796 | case SHM_LOCK: | ||
| 797 | case SHM_UNLOCK: | ||
| 798 | err = sys_shmctl(first, second, (struct shmid_ds __user *)uptr); | ||
| 799 | break; | ||
| 800 | case IPC_SET: | ||
| 801 | if (second & IPC_64) { | ||
| 802 | err = get_user(s.shm_perm.uid, &up64->shm_perm.uid); | ||
| 803 | err |= get_user(s.shm_perm.gid, &up64->shm_perm.gid); | ||
| 804 | err |= get_user(s.shm_perm.mode, &up64->shm_perm.mode); | ||
| 805 | } else { | ||
| 806 | err = get_user(s.shm_perm.uid, &up32->shm_perm.uid); | ||
| 807 | err |= get_user(s.shm_perm.gid, &up32->shm_perm.gid); | ||
| 808 | err |= get_user(s.shm_perm.mode, &up32->shm_perm.mode); | ||
| 809 | } | ||
| 810 | if (err) | ||
| 811 | break; | ||
| 812 | old_fs = get_fs(); | ||
| 813 | set_fs(KERNEL_DS); | ||
| 814 | err = sys_shmctl(first, second & ~IPC_64, (struct shmid_ds __user *)&s); | ||
| 815 | set_fs(old_fs); | ||
| 816 | break; | ||
| 817 | |||
| 818 | case IPC_STAT: | ||
| 819 | case SHM_STAT: | ||
| 820 | old_fs = get_fs(); | ||
| 821 | set_fs(KERNEL_DS); | ||
| 822 | err = sys_shmctl(first, second | IPC_64, (void __user *) &s64); | ||
| 823 | set_fs(old_fs); | ||
| 824 | if (err < 0) | ||
| 825 | break; | ||
| 826 | if (second & IPC_64) { | ||
| 827 | if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { | ||
| 828 | err = -EFAULT; | ||
| 829 | break; | ||
| 830 | } | ||
| 831 | err2 = __put_user(s64.shm_perm.key, &up64->shm_perm.key); | ||
| 832 | err2 |= __put_user(s64.shm_perm.uid, &up64->shm_perm.uid); | ||
| 833 | err2 |= __put_user(s64.shm_perm.gid, &up64->shm_perm.gid); | ||
| 834 | err2 |= __put_user(s64.shm_perm.cuid, &up64->shm_perm.cuid); | ||
| 835 | err2 |= __put_user(s64.shm_perm.cgid, &up64->shm_perm.cgid); | ||
| 836 | err2 |= __put_user(s64.shm_perm.mode, &up64->shm_perm.mode); | ||
| 837 | err2 |= __put_user(s64.shm_perm.seq, &up64->shm_perm.seq); | ||
| 838 | err2 |= __put_user(s64.shm_atime, &up64->shm_atime); | ||
| 839 | err2 |= __put_user(s64.shm_dtime, &up64->shm_dtime); | ||
| 840 | err2 |= __put_user(s64.shm_ctime, &up64->shm_ctime); | ||
| 841 | err2 |= __put_user(s64.shm_segsz, &up64->shm_segsz); | ||
| 842 | err2 |= __put_user(s64.shm_nattch, &up64->shm_nattch); | ||
| 843 | err2 |= __put_user(s64.shm_cpid, &up64->shm_cpid); | ||
| 844 | err2 |= __put_user(s64.shm_lpid, &up64->shm_lpid); | ||
| 845 | } else { | ||
| 846 | if (!access_ok(VERIFY_WRITE, up32, sizeof(*up32))) { | ||
| 847 | err = -EFAULT; | ||
| 848 | break; | ||
| 849 | } | ||
| 850 | err2 = __put_user(s64.shm_perm.key, &up32->shm_perm.key); | ||
| 851 | err2 |= __put_user(s64.shm_perm.uid, &up32->shm_perm.uid); | ||
| 852 | err2 |= __put_user(s64.shm_perm.gid, &up32->shm_perm.gid); | ||
| 853 | err2 |= __put_user(s64.shm_perm.cuid, &up32->shm_perm.cuid); | ||
| 854 | err2 |= __put_user(s64.shm_perm.cgid, &up32->shm_perm.cgid); | ||
| 855 | err2 |= __put_user(s64.shm_perm.mode, &up32->shm_perm.mode); | ||
| 856 | err2 |= __put_user(s64.shm_perm.seq, &up32->shm_perm.seq); | ||
| 857 | err2 |= __put_user(s64.shm_atime, &up32->shm_atime); | ||
| 858 | err2 |= __put_user(s64.shm_dtime, &up32->shm_dtime); | ||
| 859 | err2 |= __put_user(s64.shm_ctime, &up32->shm_ctime); | ||
| 860 | err2 |= __put_user(s64.shm_segsz, &up32->shm_segsz); | ||
| 861 | err2 |= __put_user(s64.shm_nattch, &up32->shm_nattch); | ||
| 862 | err2 |= __put_user(s64.shm_cpid, &up32->shm_cpid); | ||
| 863 | err2 |= __put_user(s64.shm_lpid, &up32->shm_lpid); | ||
| 864 | } | ||
| 865 | if (err2) | ||
| 866 | err = -EFAULT; | ||
| 867 | break; | ||
| 868 | |||
| 869 | case SHM_INFO: | ||
| 870 | old_fs = get_fs(); | ||
| 871 | set_fs(KERNEL_DS); | ||
| 872 | err = sys_shmctl(first, second, (void __user *)&si); | ||
| 873 | set_fs(old_fs); | ||
| 874 | if (err < 0) | ||
| 875 | break; | ||
| 876 | err2 = put_user(si.used_ids, &uip->used_ids); | ||
| 877 | err2 |= __put_user(si.shm_tot, &uip->shm_tot); | ||
| 878 | err2 |= __put_user(si.shm_rss, &uip->shm_rss); | ||
| 879 | err2 |= __put_user(si.shm_swp, &uip->shm_swp); | ||
| 880 | err2 |= __put_user(si.swap_attempts, &uip->swap_attempts); | ||
| 881 | err2 |= __put_user (si.swap_successes, &uip->swap_successes); | ||
| 882 | if (err2) | ||
| 883 | err = -EFAULT; | ||
| 884 | break; | ||
| 885 | |||
| 886 | default: | ||
| 887 | err = -EINVAL; | ||
| 888 | break; | ||
| 889 | } | ||
| 890 | |||
| 891 | return err; | ||
| 892 | } | ||
| 893 | |||
| 894 | static int sys32_semtimedop(int semid, struct sembuf __user *tsems, int nsems, | ||
| 895 | const struct compat_timespec __user *timeout32) | ||
| 896 | { | ||
| 897 | struct compat_timespec t32; | ||
| 898 | struct timespec __user *t64 = compat_alloc_user_space(sizeof(*t64)); | ||
| 899 | |||
| 900 | if (copy_from_user(&t32, timeout32, sizeof(t32))) | ||
| 901 | return -EFAULT; | ||
| 902 | |||
| 903 | if (put_user(t32.tv_sec, &t64->tv_sec) || | ||
| 904 | put_user(t32.tv_nsec, &t64->tv_nsec)) | ||
| 905 | return -EFAULT; | ||
| 906 | |||
| 907 | return sys_semtimedop(semid, tsems, nsems, t64); | ||
| 908 | } | ||
| 909 | |||
| 910 | asmlinkage long | 385 | asmlinkage long |
| 911 | sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) | 386 | sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) |
| 912 | { | 387 | { |
| @@ -918,48 +393,43 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) | |||
| 918 | switch (call) { | 393 | switch (call) { |
| 919 | case SEMOP: | 394 | case SEMOP: |
| 920 | /* struct sembuf is the same on 32 and 64bit :)) */ | 395 | /* struct sembuf is the same on 32 and 64bit :)) */ |
| 921 | err = sys_semtimedop (first, (struct sembuf __user *)AA(ptr), second, | 396 | err = sys_semtimedop(first, compat_ptr(ptr), second, NULL); |
| 922 | NULL); | ||
| 923 | break; | 397 | break; |
| 924 | case SEMTIMEDOP: | 398 | case SEMTIMEDOP: |
| 925 | err = sys32_semtimedop (first, (struct sembuf __user *)AA(ptr), second, | 399 | err = compat_sys_semtimedop(first, compat_ptr(ptr), second, |
| 926 | (const struct compat_timespec __user *)AA(fifth)); | 400 | compat_ptr(fifth)); |
| 927 | break; | 401 | break; |
| 928 | case SEMGET: | 402 | case SEMGET: |
| 929 | err = sys_semget (first, second, third); | 403 | err = sys_semget(first, second, third); |
| 930 | break; | 404 | break; |
| 931 | case SEMCTL: | 405 | case SEMCTL: |
| 932 | err = do_sys32_semctl (first, second, third, | 406 | err = compat_sys_semctl(first, second, third, compat_ptr(ptr)); |
| 933 | (void __user *)AA(ptr)); | ||
| 934 | break; | 407 | break; |
| 935 | |||
| 936 | case MSGSND: | 408 | case MSGSND: |
| 937 | err = do_sys32_msgsnd (first, second, third, | 409 | err = compat_sys_msgsnd(first, second, third, compat_ptr(ptr)); |
| 938 | (void __user *)AA(ptr)); | ||
| 939 | break; | 410 | break; |
| 940 | case MSGRCV: | 411 | case MSGRCV: |
| 941 | err = do_sys32_msgrcv (first, second, fifth, third, | 412 | err = compat_sys_msgrcv(first, second, fifth, third, |
| 942 | version, (void __user *)AA(ptr)); | 413 | version, compat_ptr(ptr)); |
| 943 | break; | 414 | break; |
| 944 | case MSGGET: | 415 | case MSGGET: |
| 945 | err = sys_msgget ((key_t) first, second); | 416 | err = sys_msgget((key_t) first, second); |
| 946 | break; | 417 | break; |
| 947 | case MSGCTL: | 418 | case MSGCTL: |
| 948 | err = do_sys32_msgctl (first, second, (void __user *)AA(ptr)); | 419 | err = compat_sys_msgctl(first, second, compat_ptr(ptr)); |
| 949 | break; | 420 | break; |
| 950 | |||
| 951 | case SHMAT: | 421 | case SHMAT: |
| 952 | err = do_sys32_shmat (first, second, third, | 422 | err = compat_sys_shmat(first, second, third, version, |
| 953 | version, (void __user *)AA(ptr)); | 423 | compat_ptr(ptr)); |
| 954 | break; | 424 | break; |
| 955 | case SHMDT: | 425 | case SHMDT: |
| 956 | err = sys_shmdt ((char __user *)A(ptr)); | 426 | err = sys_shmdt(compat_ptr(ptr)); |
| 957 | break; | 427 | break; |
| 958 | case SHMGET: | 428 | case SHMGET: |
| 959 | err = sys_shmget (first, (unsigned)second, third); | 429 | err = sys_shmget(first, (unsigned)second, third); |
| 960 | break; | 430 | break; |
| 961 | case SHMCTL: | 431 | case SHMCTL: |
| 962 | err = do_sys32_shmctl (first, second, (void __user *)AA(ptr)); | 432 | err = compat_sys_shmctl(first, second, compat_ptr(ptr)); |
| 963 | break; | 433 | break; |
| 964 | default: | 434 | default: |
| 965 | err = -EINVAL; | 435 | err = -EINVAL; |
| @@ -969,18 +439,16 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) | |||
| 969 | return err; | 439 | return err; |
| 970 | } | 440 | } |
| 971 | 441 | ||
| 972 | asmlinkage long sys32_shmat(int shmid, char __user *shmaddr, | 442 | #ifdef CONFIG_MIPS32_N32 |
| 973 | int shmflg, int32_t __user *addr) | 443 | asmlinkage long sysn32_semctl(int semid, int semnum, int cmd, union semun arg) |
| 974 | { | 444 | { |
| 975 | unsigned long raddr; | 445 | /* compat_sys_semctl expects a pointer to union semun */ |
| 976 | int err; | 446 | u32 __user *uptr = compat_alloc_user_space(sizeof(u32)); |
| 977 | 447 | if (put_user(ptr_to_compat(arg.__pad), uptr)) | |
| 978 | err = do_shmat(shmid, shmaddr, shmflg, &raddr); | 448 | return -EFAULT; |
| 979 | if (err) | 449 | return compat_sys_semctl(semid, semnum, cmd, uptr); |
| 980 | return err; | ||
| 981 | |||
| 982 | return put_user(raddr, addr); | ||
| 983 | } | 450 | } |
| 451 | #endif | ||
| 984 | 452 | ||
| 985 | struct sysctl_args32 | 453 | struct sysctl_args32 |
| 986 | { | 454 | { |
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index 5b18f265d75b..34567d81f940 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S | |||
| @@ -149,8 +149,8 @@ EXPORT(sysn32_call_table) | |||
| 149 | PTR sys_mincore | 149 | PTR sys_mincore |
| 150 | PTR sys_madvise | 150 | PTR sys_madvise |
| 151 | PTR sys_shmget | 151 | PTR sys_shmget |
| 152 | PTR sys32_shmat | 152 | PTR sys_shmat |
| 153 | PTR sys_shmctl /* 6030 */ | 153 | PTR compat_sys_shmctl /* 6030 */ |
| 154 | PTR sys_dup | 154 | PTR sys_dup |
| 155 | PTR sys_dup2 | 155 | PTR sys_dup2 |
| 156 | PTR sys_pause | 156 | PTR sys_pause |
| @@ -184,12 +184,12 @@ EXPORT(sysn32_call_table) | |||
| 184 | PTR sys32_newuname | 184 | PTR sys32_newuname |
| 185 | PTR sys_semget | 185 | PTR sys_semget |
| 186 | PTR sys_semop | 186 | PTR sys_semop |
| 187 | PTR sys_semctl | 187 | PTR sysn32_semctl |
| 188 | PTR sys_shmdt /* 6065 */ | 188 | PTR sys_shmdt /* 6065 */ |
| 189 | PTR sys_msgget | 189 | PTR sys_msgget |
| 190 | PTR sys_msgsnd | 190 | PTR compat_sys_msgsnd |
| 191 | PTR sys_msgrcv | 191 | PTR compat_sys_msgrcv |
| 192 | PTR sys_msgctl | 192 | PTR compat_sys_msgctl |
| 193 | PTR compat_sys_fcntl /* 6070 */ | 193 | PTR compat_sys_fcntl /* 6070 */ |
| 194 | PTR sys_flock | 194 | PTR sys_flock |
| 195 | PTR sys_fsync | 195 | PTR sys_fsync |
| @@ -335,7 +335,7 @@ EXPORT(sysn32_call_table) | |||
| 335 | PTR compat_sys_fcntl64 | 335 | PTR compat_sys_fcntl64 |
| 336 | PTR sys_set_tid_address | 336 | PTR sys_set_tid_address |
| 337 | PTR sys_restart_syscall | 337 | PTR sys_restart_syscall |
| 338 | PTR sys_semtimedop /* 6215 */ | 338 | PTR compat_sys_semtimedop /* 6215 */ |
| 339 | PTR sys_fadvise64_64 | 339 | PTR sys_fadvise64_64 |
| 340 | PTR compat_sys_statfs64 | 340 | PTR compat_sys_statfs64 |
| 341 | PTR compat_sys_fstatfs64 | 341 | PTR compat_sys_fstatfs64 |
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h index 900f472fdd2b..55a0152feb08 100644 --- a/include/asm-mips/compat.h +++ b/include/asm-mips/compat.h | |||
| @@ -32,6 +32,7 @@ typedef struct { | |||
| 32 | s32 val[2]; | 32 | s32 val[2]; |
| 33 | } compat_fsid_t; | 33 | } compat_fsid_t; |
| 34 | typedef s32 compat_timer_t; | 34 | typedef s32 compat_timer_t; |
| 35 | typedef s32 compat_key_t; | ||
| 35 | 36 | ||
| 36 | typedef s32 compat_int_t; | 37 | typedef s32 compat_int_t; |
| 37 | typedef s32 compat_long_t; | 38 | typedef s32 compat_long_t; |
| @@ -146,4 +147,71 @@ static inline void __user *compat_alloc_user_space(long len) | |||
| 146 | return (void __user *) (regs->regs[29] - len); | 147 | return (void __user *) (regs->regs[29] - len); |
| 147 | } | 148 | } |
| 148 | 149 | ||
| 150 | struct compat_ipc64_perm { | ||
| 151 | compat_key_t key; | ||
| 152 | __compat_uid32_t uid; | ||
| 153 | __compat_gid32_t gid; | ||
| 154 | __compat_uid32_t cuid; | ||
| 155 | __compat_gid32_t cgid; | ||
| 156 | compat_mode_t mode; | ||
| 157 | unsigned short seq; | ||
| 158 | unsigned short __pad2; | ||
| 159 | compat_ulong_t __unused1; | ||
| 160 | compat_ulong_t __unused2; | ||
| 161 | }; | ||
| 162 | |||
| 163 | struct compat_semid64_ds { | ||
| 164 | struct compat_ipc64_perm sem_perm; | ||
| 165 | compat_time_t sem_otime; | ||
| 166 | compat_time_t sem_ctime; | ||
| 167 | compat_ulong_t sem_nsems; | ||
| 168 | compat_ulong_t __unused1; | ||
| 169 | compat_ulong_t __unused2; | ||
| 170 | }; | ||
| 171 | |||
| 172 | struct compat_msqid64_ds { | ||
| 173 | struct compat_ipc64_perm msg_perm; | ||
| 174 | #ifndef CONFIG_CPU_LITTLE_ENDIAN | ||
| 175 | compat_ulong_t __unused1; | ||
| 176 | #endif | ||
| 177 | compat_time_t msg_stime; | ||
| 178 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
| 179 | compat_ulong_t __unused1; | ||
| 180 | #endif | ||
| 181 | #ifndef CONFIG_CPU_LITTLE_ENDIAN | ||
| 182 | compat_ulong_t __unused2; | ||
| 183 | #endif | ||
| 184 | compat_time_t msg_rtime; | ||
| 185 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
| 186 | compat_ulong_t __unused2; | ||
| 187 | #endif | ||
| 188 | #ifndef CONFIG_CPU_LITTLE_ENDIAN | ||
| 189 | compat_ulong_t __unused3; | ||
| 190 | #endif | ||
| 191 | compat_time_t msg_ctime; | ||
| 192 | #ifdef CONFIG_CPU_LITTLE_ENDIAN | ||
| 193 | compat_ulong_t __unused3; | ||
| 194 | #endif | ||
| 195 | compat_ulong_t msg_cbytes; | ||
| 196 | compat_ulong_t msg_qnum; | ||
| 197 | compat_ulong_t msg_qbytes; | ||
| 198 | compat_pid_t msg_lspid; | ||
| 199 | compat_pid_t msg_lrpid; | ||
| 200 | compat_ulong_t __unused4; | ||
| 201 | compat_ulong_t __unused5; | ||
| 202 | }; | ||
| 203 | |||
| 204 | struct compat_shmid64_ds { | ||
| 205 | struct compat_ipc64_perm shm_perm; | ||
| 206 | compat_size_t shm_segsz; | ||
| 207 | compat_time_t shm_atime; | ||
| 208 | compat_time_t shm_dtime; | ||
| 209 | compat_time_t shm_ctime; | ||
| 210 | compat_pid_t shm_cpid; | ||
| 211 | compat_pid_t shm_lpid; | ||
| 212 | compat_ulong_t shm_nattch; | ||
| 213 | compat_ulong_t __unused1; | ||
| 214 | compat_ulong_t __unused2; | ||
| 215 | }; | ||
| 216 | |||
| 149 | #endif /* _ASM_COMPAT_H */ | 217 | #endif /* _ASM_COMPAT_H */ |
