aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ipv6_sockglue.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r--net/ipv6/ipv6_sockglue.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 26b83e512a09..86e28a75267f 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -67,7 +67,7 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
67 67
68 /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ 68 /* RA packet may be delivered ONLY to IPPROTO_RAW socket */
69 if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW) 69 if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW)
70 return -EINVAL; 70 return -ENOPROTOOPT;
71 71
72 new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; 72 new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
73 73
@@ -345,18 +345,21 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
345 case IPV6_DSTOPTS: 345 case IPV6_DSTOPTS:
346 { 346 {
347 struct ipv6_txoptions *opt; 347 struct ipv6_txoptions *opt;
348
349 /* remove any sticky options header with a zero option
350 * length, per RFC3542.
351 */
348 if (optlen == 0) 352 if (optlen == 0)
349 optval = NULL; 353 optval = NULL;
354 else if (optlen < sizeof(struct ipv6_opt_hdr) ||
355 optlen & 0x7 || optlen > 8 * 255)
356 goto e_inval;
350 357
351 /* hop-by-hop / destination options are privileged option */ 358 /* hop-by-hop / destination options are privileged option */
352 retv = -EPERM; 359 retv = -EPERM;
353 if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) 360 if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
354 break; 361 break;
355 362
356 if (optlen < sizeof(struct ipv6_opt_hdr) ||
357 optlen & 0x7 || optlen > 8 * 255)
358 goto e_inval;
359
360 opt = ipv6_renew_options(sk, np->opt, optname, 363 opt = ipv6_renew_options(sk, np->opt, optname,
361 (struct ipv6_opt_hdr __user *)optval, 364 (struct ipv6_opt_hdr __user *)optval,
362 optlen); 365 optlen);
@@ -446,7 +449,7 @@ done:
446 449
447 case IPV6_MULTICAST_HOPS: 450 case IPV6_MULTICAST_HOPS:
448 if (sk->sk_type == SOCK_STREAM) 451 if (sk->sk_type == SOCK_STREAM)
449 goto e_inval; 452 break;
450 if (optlen < sizeof(int)) 453 if (optlen < sizeof(int))
451 goto e_inval; 454 goto e_inval;
452 if (val > 255 || val < -1) 455 if (val > 255 || val < -1)
@@ -458,13 +461,15 @@ done:
458 case IPV6_MULTICAST_LOOP: 461 case IPV6_MULTICAST_LOOP:
459 if (optlen < sizeof(int)) 462 if (optlen < sizeof(int))
460 goto e_inval; 463 goto e_inval;
464 if (val != valbool)
465 goto e_inval;
461 np->mc_loop = valbool; 466 np->mc_loop = valbool;
462 retv = 0; 467 retv = 0;
463 break; 468 break;
464 469
465 case IPV6_MULTICAST_IF: 470 case IPV6_MULTICAST_IF:
466 if (sk->sk_type == SOCK_STREAM) 471 if (sk->sk_type == SOCK_STREAM)
467 goto e_inval; 472 break;
468 if (optlen < sizeof(int)) 473 if (optlen < sizeof(int))
469 goto e_inval; 474 goto e_inval;
470 475
@@ -860,7 +865,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
860 if (sk->sk_protocol != IPPROTO_UDP && 865 if (sk->sk_protocol != IPPROTO_UDP &&
861 sk->sk_protocol != IPPROTO_UDPLITE && 866 sk->sk_protocol != IPPROTO_UDPLITE &&
862 sk->sk_protocol != IPPROTO_TCP) 867 sk->sk_protocol != IPPROTO_TCP)
863 return -EINVAL; 868 return -ENOPROTOOPT;
864 if (sk->sk_state != TCP_ESTABLISHED) 869 if (sk->sk_state != TCP_ESTABLISHED)
865 return -ENOTCONN; 870 return -ENOTCONN;
866 val = sk->sk_family; 871 val = sk->sk_family;
@@ -874,6 +879,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
874 return -EINVAL; 879 return -EINVAL;
875 if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) 880 if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
876 return -EFAULT; 881 return -EFAULT;
882 if (gsf.gf_group.ss_family != AF_INET6)
883 return -EADDRNOTAVAIL;
877 lock_sock(sk); 884 lock_sock(sk);
878 err = ip6_mc_msfget(sk, &gsf, 885 err = ip6_mc_msfget(sk, &gsf,
879 (struct group_filter __user *)optval, optlen); 886 (struct group_filter __user *)optval, optlen);