diff options
Diffstat (limited to 'net/compat.c')
-rw-r--r-- | net/compat.c | 117 |
1 files changed, 117 insertions, 0 deletions
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), |