diff options
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 23 |
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); |