diff options
| author | David L Stevens <dlstevens@us.ibm.com> | 2008-04-27 04:06:07 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-04-27 17:26:53 -0400 |
| commit | dae50295488f35d2d617b08a5fae43154c947eec (patch) | |
| tree | afee67a0e85f4a168e0bb75423f1b703f48baad3 | |
| parent | 01a2202c95989a4df48e9a5b5e013cb80c6b2d66 (diff) | |
ipv4/ipv6 compat: Fix SSM applications on 64bit kernels.
Add support on 64-bit kernels for seting 32-bit compatible MCAST*
socket options.
Signed-off-by: David L Stevens <dlstevens@us.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/compat.h | 3 | ||||
| -rw-r--r-- | net/compat.c | 117 | ||||
| -rw-r--r-- | net/ipv4/ip_sockglue.c | 5 | ||||
| -rw-r--r-- | net/ipv6/ipv6_sockglue.c | 5 |
4 files changed, 130 insertions, 0 deletions
diff --git a/include/net/compat.h b/include/net/compat.h index 406db242f73a..05fa5d0254ab 100644 --- a/include/net/compat.h +++ b/include/net/compat.h | |||
| @@ -40,4 +40,7 @@ extern int put_cmsg_compat(struct msghdr*, int, int, int, void *); | |||
| 40 | 40 | ||
| 41 | extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *, int); | 41 | extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsigned char *, int); |
| 42 | 42 | ||
| 43 | extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, int, | ||
| 44 | int (*)(struct sock *, int, int, char __user *, int)); | ||
| 45 | |||
| 43 | #endif /* NET_COMPAT_H */ | 46 | #endif /* NET_COMPAT_H */ |
diff --git a/net/compat.c b/net/compat.c index 80013fb69a61..01bf95d0832e 100644 --- a/net/compat.c +++ b/net/compat.c | |||
| @@ -24,6 +24,8 @@ | |||
| 24 | 24 | ||
| 25 | #include <net/scm.h> | 25 | #include <net/scm.h> |
| 26 | #include <net/sock.h> | 26 | #include <net/sock.h> |
| 27 | #include <net/ip.h> | ||
| 28 | #include <net/ipv6.h> | ||
| 27 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
| 28 | #include <net/compat.h> | 30 | #include <net/compat.h> |
| 29 | 31 | ||
| @@ -521,6 +523,121 @@ asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, | |||
| 521 | } | 523 | } |
| 522 | return err; | 524 | return err; |
| 523 | } | 525 | } |
| 526 | |||
| 527 | struct compat_group_req { | ||
| 528 | __u32 gr_interface; | ||
| 529 | struct __kernel_sockaddr_storage gr_group | ||
| 530 | __attribute__ ((aligned(4))); | ||
| 531 | } __attribute__ ((packed)); | ||
| 532 | |||
| 533 | struct compat_group_source_req { | ||
| 534 | __u32 gsr_interface; | ||
| 535 | struct __kernel_sockaddr_storage gsr_group | ||
| 536 | __attribute__ ((aligned(4))); | ||
| 537 | struct __kernel_sockaddr_storage gsr_source | ||
| 538 | __attribute__ ((aligned(4))); | ||
| 539 | } __attribute__ ((packed)); | ||
| 540 | |||
| 541 | struct compat_group_filter { | ||
| 542 | __u32 gf_interface; | ||
| 543 | struct __kernel_sockaddr_storage gf_group | ||
| 544 | __attribute__ ((aligned(4))); | ||
| 545 | __u32 gf_fmode; | ||
| 546 | __u32 gf_numsrc; | ||
| 547 | struct __kernel_sockaddr_storage gf_slist[1] | ||
| 548 | __attribute__ ((aligned(4))); | ||
| 549 | } __attribute__ ((packed)); | ||
| 550 | |||
| 551 | |||
| 552 | int compat_mc_setsockopt(struct sock *sock, int level, int optname, | ||
| 553 | char __user *optval, int optlen, | ||
| 554 | int (*setsockopt)(struct sock *,int,int,char __user *,int)) | ||
| 555 | { | ||
| 556 | char __user *koptval = optval; | ||
| 557 | int koptlen = optlen; | ||
| 558 | |||
| 559 | switch (optname) { | ||
| 560 | case MCAST_JOIN_GROUP: | ||
| 561 | case MCAST_LEAVE_GROUP: | ||
| 562 | { | ||
| 563 | struct compat_group_req __user *gr32 = (void *)optval; | ||
| 564 | struct group_req __user *kgr = | ||
| 565 | compat_alloc_user_space(sizeof(struct group_req)); | ||
| 566 | u32 interface; | ||
| 567 | |||
| 568 | if (!access_ok(VERIFY_READ, gr32, sizeof(*gr32)) || | ||
| 569 | !access_ok(VERIFY_WRITE, kgr, sizeof(struct group_req)) || | ||
| 570 | __get_user(interface, &gr32->gr_interface) || | ||
| 571 | __put_user(interface, &kgr->gr_interface) || | ||
| 572 | copy_in_user(&kgr->gr_group, &gr32->gr_group, | ||
| 573 | sizeof(kgr->gr_group))) | ||
| 574 | return -EFAULT; | ||
| 575 | koptval = (char __user *)kgr; | ||
| 576 | koptlen = sizeof(struct group_req); | ||
| 577 | break; | ||
| 578 | } | ||
| 579 | case MCAST_JOIN_SOURCE_GROUP: | ||
| 580 | case MCAST_LEAVE_SOURCE_GROUP: | ||
| 581 | case MCAST_BLOCK_SOURCE: | ||
| 582 | case MCAST_UNBLOCK_SOURCE: | ||
| 583 | { | ||
| 584 | struct compat_group_source_req __user *gsr32 = (void *)optval; | ||
| 585 | struct group_source_req *kgsr = compat_alloc_user_space( | ||
| 586 | sizeof(struct group_source_req)); | ||
| 587 | u32 interface; | ||
| 588 | |||
| 589 | if (!access_ok(VERIFY_READ, gsr32, sizeof(*gsr32)) || | ||
| 590 | !access_ok(VERIFY_WRITE, kgsr, | ||
| 591 | sizeof(struct group_source_req)) || | ||
| 592 | __get_user(interface, &gsr32->gsr_interface) || | ||
| 593 | __put_user(interface, &kgsr->gsr_interface) || | ||
| 594 | copy_in_user(&kgsr->gsr_group, &gsr32->gsr_group, | ||
| 595 | sizeof(kgsr->gsr_group)) || | ||
| 596 | copy_in_user(&kgsr->gsr_source, &gsr32->gsr_source, | ||
| 597 | sizeof(kgsr->gsr_source))) | ||
| 598 | return -EFAULT; | ||
| 599 | koptval = (char __user *)kgsr; | ||
| 600 | koptlen = sizeof(struct group_source_req); | ||
| 601 | break; | ||
| 602 | } | ||
| 603 | case MCAST_MSFILTER: | ||
| 604 | { | ||
| 605 | struct compat_group_filter __user *gf32 = (void *)optval; | ||
| 606 | struct group_filter *kgf; | ||
| 607 | u32 interface, fmode, numsrc; | ||
| 608 | |||
| 609 | if (!access_ok(VERIFY_READ, gf32, sizeof(*gf32)) || | ||
| 610 | __get_user(interface, &gf32->gf_interface) || | ||
| 611 | __get_user(fmode, &gf32->gf_fmode) || | ||
| 612 | __get_user(numsrc, &gf32->gf_numsrc)) | ||
| 613 | return -EFAULT; | ||
| 614 | koptlen = optlen + sizeof(struct group_filter) - | ||
| 615 | sizeof(struct compat_group_filter); | ||
| 616 | if (koptlen < GROUP_FILTER_SIZE(numsrc)) | ||
| 617 | return -EINVAL; | ||
| 618 | kgf = compat_alloc_user_space(koptlen); | ||
| 619 | if (!access_ok(VERIFY_WRITE, kgf, koptlen) || | ||
| 620 | __put_user(interface, &kgf->gf_interface) || | ||
| 621 | __put_user(fmode, &kgf->gf_fmode) || | ||
| 622 | __put_user(numsrc, &kgf->gf_numsrc) || | ||
| 623 | copy_in_user(&kgf->gf_group, &gf32->gf_group, | ||
| 624 | sizeof(kgf->gf_group)) || | ||
| 625 | (numsrc && copy_in_user(&kgf->gf_slist, &gf32->gf_slist, | ||
| 626 | numsrc * sizeof(kgf->gf_slist[0])))) | ||
| 627 | return -EFAULT; | ||
| 628 | koptval = (char __user *)kgf; | ||
| 629 | break; | ||
| 630 | } | ||
| 631 | |||
| 632 | default: | ||
| 633 | break; | ||
| 634 | } | ||
| 635 | return setsockopt(sock, level, optname, koptval, koptlen); | ||
| 636 | } | ||
| 637 | |||
| 638 | EXPORT_SYMBOL(compat_mc_setsockopt); | ||
| 639 | |||
| 640 | |||
| 524 | /* Argument list sizes for compat_sys_socketcall */ | 641 | /* Argument list sizes for compat_sys_socketcall */ |
| 525 | #define AL(x) ((x) * sizeof(u32)) | 642 | #define AL(x) ((x) * sizeof(u32)) |
| 526 | static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), | 643 | static unsigned char nas[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3), |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index d8adfd4972e2..4d8d95404f45 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/mroute.h> | 36 | #include <linux/mroute.h> |
| 37 | #include <net/route.h> | 37 | #include <net/route.h> |
| 38 | #include <net/xfrm.h> | 38 | #include <net/xfrm.h> |
| 39 | #include <net/compat.h> | ||
| 39 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 40 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
| 40 | #include <net/transp_v6.h> | 41 | #include <net/transp_v6.h> |
| 41 | #endif | 42 | #endif |
| @@ -923,6 +924,10 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname, | |||
| 923 | if (level != SOL_IP) | 924 | if (level != SOL_IP) |
| 924 | return -ENOPROTOOPT; | 925 | return -ENOPROTOOPT; |
| 925 | 926 | ||
| 927 | if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER) | ||
| 928 | return compat_mc_setsockopt(sk, level, optname, optval, optlen, | ||
| 929 | ip_setsockopt); | ||
| 930 | |||
| 926 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); | 931 | err = do_ip_setsockopt(sk, level, optname, optval, optlen); |
| 927 | #ifdef CONFIG_NETFILTER | 932 | #ifdef CONFIG_NETFILTER |
| 928 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | 933 | /* we need to exclude all possible ENOPROTOOPTs except default case */ |
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 06de9d0e1f6b..db6fdc1498aa 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | #include <net/udp.h> | 52 | #include <net/udp.h> |
| 53 | #include <net/udplite.h> | 53 | #include <net/udplite.h> |
| 54 | #include <net/xfrm.h> | 54 | #include <net/xfrm.h> |
| 55 | #include <net/compat.h> | ||
| 55 | 56 | ||
| 56 | #include <asm/uaccess.h> | 57 | #include <asm/uaccess.h> |
| 57 | 58 | ||
| @@ -779,6 +780,10 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
| 779 | if (level != SOL_IPV6) | 780 | if (level != SOL_IPV6) |
| 780 | return -ENOPROTOOPT; | 781 | return -ENOPROTOOPT; |
| 781 | 782 | ||
| 783 | if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER) | ||
| 784 | return compat_mc_setsockopt(sk, level, optname, optval, optlen, | ||
| 785 | ipv6_setsockopt); | ||
| 786 | |||
| 782 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); | 787 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); |
| 783 | #ifdef CONFIG_NETFILTER | 788 | #ifdef CONFIG_NETFILTER |
| 784 | /* we need to exclude all possible ENOPROTOOPTs except default case */ | 789 | /* we need to exclude all possible ENOPROTOOPTs except default case */ |
