Loading net/ipv6/ipv6_sockglue.c +74 −65 Original line number Diff line number Diff line Loading @@ -1071,33 +1071,12 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt, return len; } static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen, unsigned int flags) static int ipv6_get_msfilter(struct sock *sk, void __user *optval, int __user *optlen, int len) { struct ipv6_pinfo *np = inet6_sk(sk); int len; int val; if (ip6_mroute_opt(optname)) return ip6_mroute_getsockopt(sk, optname, optval, optlen); if (get_user(len, optlen)) return -EFAULT; switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) return -ENOPROTOOPT; if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; val = sk->sk_family; break; case MCAST_MSFILTER: { struct group_filter __user *p = (void __user *)optval; struct group_filter gsf; const int size0 = offsetof(struct group_filter, gf_slist); struct group_filter __user *p = optval; struct group_filter gsf; int num; int err; Loading @@ -1121,6 +1100,72 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, return err; } #ifdef CONFIG_COMPAT static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval, int __user *optlen) { const int size0 = offsetof(struct compat_group_filter, gf_slist); struct compat_group_filter __user *p = optval; struct compat_group_filter gf32; struct group_filter gf; int len, err; int num; if (get_user(len, optlen)) return -EFAULT; if (len < size0) return -EINVAL; if (copy_from_user(&gf32, p, size0)) return -EFAULT; gf.gf_interface = gf32.gf_interface; gf.gf_fmode = gf32.gf_fmode; num = gf.gf_numsrc = gf32.gf_numsrc; gf.gf_group = gf32.gf_group; if (gf.gf_group.ss_family != AF_INET6) return -EADDRNOTAVAIL; lock_sock(sk); err = ip6_mc_msfget(sk, &gf, p->gf_slist); release_sock(sk); if (err) return err; if (num > gf.gf_numsrc) num = gf.gf_numsrc; len = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32)); if (put_user(len, optlen) || put_user(gf.gf_fmode, &p->gf_fmode) || put_user(gf.gf_numsrc, &p->gf_numsrc)) return -EFAULT; return 0; } #endif static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen, unsigned int flags) { struct ipv6_pinfo *np = inet6_sk(sk); int len; int val; if (ip6_mroute_opt(optname)) return ip6_mroute_getsockopt(sk, optname, optval, optlen); if (get_user(len, optlen)) return -EFAULT; switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) return -ENOPROTOOPT; if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; val = sk->sk_family; break; case MCAST_MSFILTER: return ipv6_get_msfilter(sk, optval, optlen, len); case IPV6_2292PKTOPTIONS: { struct msghdr msg; Loading Loading @@ -1481,44 +1526,8 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, if (level != SOL_IPV6) return -ENOPROTOOPT; if (optname == MCAST_MSFILTER) { const int size0 = offsetof(struct compat_group_filter, gf_slist); struct compat_group_filter __user *p = (void __user *)optval; struct compat_group_filter gf32; struct group_filter gf; int ulen, err; int num; if (get_user(ulen, optlen)) return -EFAULT; if (ulen < size0) return -EINVAL; if (copy_from_user(&gf32, p, size0)) return -EFAULT; gf.gf_interface = gf32.gf_interface; gf.gf_fmode = gf32.gf_fmode; num = gf.gf_numsrc = gf32.gf_numsrc; gf.gf_group = gf32.gf_group; if (gf.gf_group.ss_family != AF_INET6) return -EADDRNOTAVAIL; lock_sock(sk); err = ip6_mc_msfget(sk, &gf, p->gf_slist); release_sock(sk); if (err) return err; if (num > gf.gf_numsrc) num = gf.gf_numsrc; ulen = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32)); if (put_user(ulen, optlen) || put_user(gf.gf_fmode, &p->gf_fmode) || put_user(gf.gf_numsrc, &p->gf_numsrc)) return -EFAULT; return 0; } if (optname == MCAST_MSFILTER) return compat_ipv6_get_msfilter(sk, optval, optlen); err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, MSG_CMSG_COMPAT); Loading Loading
net/ipv6/ipv6_sockglue.c +74 −65 Original line number Diff line number Diff line Loading @@ -1071,33 +1071,12 @@ static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt, return len; } static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen, unsigned int flags) static int ipv6_get_msfilter(struct sock *sk, void __user *optval, int __user *optlen, int len) { struct ipv6_pinfo *np = inet6_sk(sk); int len; int val; if (ip6_mroute_opt(optname)) return ip6_mroute_getsockopt(sk, optname, optval, optlen); if (get_user(len, optlen)) return -EFAULT; switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) return -ENOPROTOOPT; if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; val = sk->sk_family; break; case MCAST_MSFILTER: { struct group_filter __user *p = (void __user *)optval; struct group_filter gsf; const int size0 = offsetof(struct group_filter, gf_slist); struct group_filter __user *p = optval; struct group_filter gsf; int num; int err; Loading @@ -1121,6 +1100,72 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, return err; } #ifdef CONFIG_COMPAT static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval, int __user *optlen) { const int size0 = offsetof(struct compat_group_filter, gf_slist); struct compat_group_filter __user *p = optval; struct compat_group_filter gf32; struct group_filter gf; int len, err; int num; if (get_user(len, optlen)) return -EFAULT; if (len < size0) return -EINVAL; if (copy_from_user(&gf32, p, size0)) return -EFAULT; gf.gf_interface = gf32.gf_interface; gf.gf_fmode = gf32.gf_fmode; num = gf.gf_numsrc = gf32.gf_numsrc; gf.gf_group = gf32.gf_group; if (gf.gf_group.ss_family != AF_INET6) return -EADDRNOTAVAIL; lock_sock(sk); err = ip6_mc_msfget(sk, &gf, p->gf_slist); release_sock(sk); if (err) return err; if (num > gf.gf_numsrc) num = gf.gf_numsrc; len = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32)); if (put_user(len, optlen) || put_user(gf.gf_fmode, &p->gf_fmode) || put_user(gf.gf_numsrc, &p->gf_numsrc)) return -EFAULT; return 0; } #endif static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen, unsigned int flags) { struct ipv6_pinfo *np = inet6_sk(sk); int len; int val; if (ip6_mroute_opt(optname)) return ip6_mroute_getsockopt(sk, optname, optval, optlen); if (get_user(len, optlen)) return -EFAULT; switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) return -ENOPROTOOPT; if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; val = sk->sk_family; break; case MCAST_MSFILTER: return ipv6_get_msfilter(sk, optval, optlen, len); case IPV6_2292PKTOPTIONS: { struct msghdr msg; Loading Loading @@ -1481,44 +1526,8 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, if (level != SOL_IPV6) return -ENOPROTOOPT; if (optname == MCAST_MSFILTER) { const int size0 = offsetof(struct compat_group_filter, gf_slist); struct compat_group_filter __user *p = (void __user *)optval; struct compat_group_filter gf32; struct group_filter gf; int ulen, err; int num; if (get_user(ulen, optlen)) return -EFAULT; if (ulen < size0) return -EINVAL; if (copy_from_user(&gf32, p, size0)) return -EFAULT; gf.gf_interface = gf32.gf_interface; gf.gf_fmode = gf32.gf_fmode; num = gf.gf_numsrc = gf32.gf_numsrc; gf.gf_group = gf32.gf_group; if (gf.gf_group.ss_family != AF_INET6) return -EADDRNOTAVAIL; lock_sock(sk); err = ip6_mc_msfget(sk, &gf, p->gf_slist); release_sock(sk); if (err) return err; if (num > gf.gf_numsrc) num = gf.gf_numsrc; ulen = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32)); if (put_user(ulen, optlen) || put_user(gf.gf_fmode, &p->gf_fmode) || put_user(gf.gf_numsrc, &p->gf_numsrc)) return -EFAULT; return 0; } if (optname == MCAST_MSFILTER) return compat_ipv6_get_msfilter(sk, optval, optlen); err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, MSG_CMSG_COMPAT); Loading