Commit b2a9d7c2 authored by YOSHIFUJI Hideaki's avatar YOSHIFUJI Hideaki

[IPV6]: Check length of int/boolean optval provided by user in setsockopt().

Signed-off-by: default avatarYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
parent a28398ba
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
* *
* FIXME: Make the setsockopt code POSIX compliant: That is * FIXME: Make the setsockopt code POSIX compliant: That is
* *
* o Return -EINVAL for setsockopt of short lengths
* o Truncate getsockopt returns * o Truncate getsockopt returns
* o Return an optlen of the truncated length if need be * o Return an optlen of the truncated length if need be
* *
...@@ -114,8 +113,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -114,8 +113,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
if (optval == NULL) if (optval == NULL)
val=0; val=0;
else if (get_user(val, (int __user *) optval)) else {
if (optlen >= sizeof(int)) {
if (get_user(val, (int __user *) optval))
return -EFAULT; return -EFAULT;
} else
val = 0;
}
valbool = (val!=0); valbool = (val!=0);
...@@ -127,6 +131,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -127,6 +131,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
switch (optname) { switch (optname) {
case IPV6_ADDRFORM: case IPV6_ADDRFORM:
if (optlen < sizeof(int))
goto e_inval;
if (val == PF_INET) { if (val == PF_INET) {
struct ipv6_txoptions *opt; struct ipv6_txoptions *opt;
struct sk_buff *pktopt; struct sk_buff *pktopt;
...@@ -201,63 +207,86 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -201,63 +207,86 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
goto e_inval; goto e_inval;
case IPV6_V6ONLY: case IPV6_V6ONLY:
if (inet_sk(sk)->num) if (optlen < sizeof(int) ||
inet_sk(sk)->num)
goto e_inval; goto e_inval;
np->ipv6only = valbool; np->ipv6only = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_RECVPKTINFO: case IPV6_RECVPKTINFO:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.rxinfo = valbool; np->rxopt.bits.rxinfo = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_2292PKTINFO: case IPV6_2292PKTINFO:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.rxoinfo = valbool; np->rxopt.bits.rxoinfo = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_RECVHOPLIMIT: case IPV6_RECVHOPLIMIT:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.rxhlim = valbool; np->rxopt.bits.rxhlim = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_2292HOPLIMIT: case IPV6_2292HOPLIMIT:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.rxohlim = valbool; np->rxopt.bits.rxohlim = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_RECVRTHDR: case IPV6_RECVRTHDR:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.srcrt = valbool; np->rxopt.bits.srcrt = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_2292RTHDR: case IPV6_2292RTHDR:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.osrcrt = valbool; np->rxopt.bits.osrcrt = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_RECVHOPOPTS: case IPV6_RECVHOPOPTS:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.hopopts = valbool; np->rxopt.bits.hopopts = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_2292HOPOPTS: case IPV6_2292HOPOPTS:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.ohopopts = valbool; np->rxopt.bits.ohopopts = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_RECVDSTOPTS: case IPV6_RECVDSTOPTS:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.dstopts = valbool; np->rxopt.bits.dstopts = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_2292DSTOPTS: case IPV6_2292DSTOPTS:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.odstopts = valbool; np->rxopt.bits.odstopts = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_TCLASS: case IPV6_TCLASS:
if (optlen < sizeof(int))
goto e_inval;
if (val < -1 || val > 0xff) if (val < -1 || val > 0xff)
goto e_inval; goto e_inval;
np->tclass = val; np->tclass = val;
...@@ -265,11 +294,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -265,11 +294,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
break; break;
case IPV6_RECVTCLASS: case IPV6_RECVTCLASS:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.rxtclass = valbool; np->rxopt.bits.rxtclass = valbool;
retv = 0; retv = 0;
break; break;
case IPV6_FLOWINFO: case IPV6_FLOWINFO:
if (optlen < sizeof(int))
goto e_inval;
np->rxopt.bits.rxflow = valbool; np->rxopt.bits.rxflow = valbool;
retv = 0; retv = 0;
break; break;
...@@ -288,9 +321,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -288,9 +321,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW))
break; break;
retv = -EINVAL; if (optlen < sizeof(struct ipv6_opt_hdr) ||
if (optlen & 0x7 || optlen > 8 * 255) optlen & 0x7 || optlen > 8 * 255)
break; goto e_inval;
opt = ipv6_renew_options(sk, np->opt, optname, opt = ipv6_renew_options(sk, np->opt, optname,
(struct ipv6_opt_hdr __user *)optval, (struct ipv6_opt_hdr __user *)optval,
...@@ -408,6 +441,8 @@ done: ...@@ -408,6 +441,8 @@ done:
break; break;
} }
case IPV6_UNICAST_HOPS: case IPV6_UNICAST_HOPS:
if (optlen < sizeof(int))
goto e_inval;
if (val > 255 || val < -1) if (val > 255 || val < -1)
goto e_inval; goto e_inval;
np->hop_limit = val; np->hop_limit = val;
...@@ -417,6 +452,8 @@ done: ...@@ -417,6 +452,8 @@ done:
case IPV6_MULTICAST_HOPS: case IPV6_MULTICAST_HOPS:
if (sk->sk_type == SOCK_STREAM) if (sk->sk_type == SOCK_STREAM)
goto e_inval; goto e_inval;
if (optlen < sizeof(int))
goto e_inval;
if (val > 255 || val < -1) if (val > 255 || val < -1)
goto e_inval; goto e_inval;
np->mcast_hops = val; np->mcast_hops = val;
...@@ -424,6 +461,8 @@ done: ...@@ -424,6 +461,8 @@ done:
break; break;
case IPV6_MULTICAST_LOOP: case IPV6_MULTICAST_LOOP:
if (optlen < sizeof(int))
goto e_inval;
np->mc_loop = valbool; np->mc_loop = valbool;
retv = 0; retv = 0;
break; break;
...@@ -431,6 +470,8 @@ done: ...@@ -431,6 +470,8 @@ done:
case IPV6_MULTICAST_IF: case IPV6_MULTICAST_IF:
if (sk->sk_type == SOCK_STREAM) if (sk->sk_type == SOCK_STREAM)
goto e_inval; goto e_inval;
if (optlen < sizeof(int))
goto e_inval;
if (val) { if (val) {
if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val)
...@@ -591,27 +632,37 @@ done: ...@@ -591,27 +632,37 @@ done:
break; break;
} }
case IPV6_ROUTER_ALERT: case IPV6_ROUTER_ALERT:
if (optlen < sizeof(int))
goto e_inval;
retv = ip6_ra_control(sk, val, NULL); retv = ip6_ra_control(sk, val, NULL);
break; break;
case IPV6_MTU_DISCOVER: case IPV6_MTU_DISCOVER:
if (optlen < sizeof(int))
goto e_inval;
if (val<0 || val>3) if (val<0 || val>3)
goto e_inval; goto e_inval;
np->pmtudisc = val; np->pmtudisc = val;
retv = 0; retv = 0;
break; break;
case IPV6_MTU: case IPV6_MTU:
if (optlen < sizeof(int))
goto e_inval;
if (val && val < IPV6_MIN_MTU) if (val && val < IPV6_MIN_MTU)
goto e_inval; goto e_inval;
np->frag_size = val; np->frag_size = val;
retv = 0; retv = 0;
break; break;
case IPV6_RECVERR: case IPV6_RECVERR:
if (optlen < sizeof(int))
goto e_inval;
np->recverr = valbool; np->recverr = valbool;
if (!val) if (!val)
skb_queue_purge(&sk->sk_error_queue); skb_queue_purge(&sk->sk_error_queue);
retv = 0; retv = 0;
break; break;
case IPV6_FLOWINFO_SEND: case IPV6_FLOWINFO_SEND:
if (optlen < sizeof(int))
goto e_inval;
np->sndflow = valbool; np->sndflow = valbool;
retv = 0; retv = 0;
break; break;
...@@ -631,6 +682,9 @@ done: ...@@ -631,6 +682,9 @@ done:
unsigned int pref = 0; unsigned int pref = 0;
unsigned int prefmask = ~0; unsigned int prefmask = ~0;
if (optlen < sizeof(int))
goto e_inval;
retv = -EINVAL; retv = -EINVAL;
/* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment