[IPV6]: Check length of int/boolean optval provided by user in setsockopt().
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
This commit is contained in:
parent
a28398ba61
commit
b2a9d7c2f8
|
@ -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,
|
||||||
|
|
||||||
if (optval == NULL)
|
if (optval == NULL)
|
||||||
val=0;
|
val=0;
|
||||||
else if (get_user(val, (int __user *) optval))
|
else {
|
||||||
return -EFAULT;
|
if (optlen >= sizeof(int)) {
|
||||||
|
if (get_user(val, (int __user *) optval))
|
||||||
|
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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:
|
||||||
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:
|
||||||
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:
|
||||||
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:
|
||||||
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:
|
||||||
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:
|
||||||
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 */
|
||||||
|
|
Reference in New Issue