diff options
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 68 |
1 files changed, 61 insertions, 7 deletions
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index bd3fb129b393..2f1244dc5ebf 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c | |||
@@ -16,7 +16,6 @@ | |||
16 | * | 16 | * |
17 | * FIXME: Make the setsockopt code POSIX compliant: That is | 17 | * FIXME: Make the setsockopt code POSIX compliant: That is |
18 | * | 18 | * |
19 | * o Return -EINVAL for setsockopt of short lengths | ||
20 | * o Truncate getsockopt returns | 19 | * o Truncate getsockopt returns |
21 | * o Return an optlen of the truncated length if need be | 20 | * o Return an optlen of the truncated length if need be |
22 | * | 21 | * |
@@ -114,8 +113,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
114 | 113 | ||
115 | if (optval == NULL) | 114 | if (optval == NULL) |
116 | val=0; | 115 | val=0; |
117 | else if (get_user(val, (int __user *) optval)) | 116 | else { |
118 | return -EFAULT; | 117 | if (optlen >= sizeof(int)) { |
118 | if (get_user(val, (int __user *) optval)) | ||
119 | return -EFAULT; | ||
120 | } else | ||
121 | val = 0; | ||
122 | } | ||
119 | 123 | ||
120 | valbool = (val!=0); | 124 | valbool = (val!=0); |
121 | 125 | ||
@@ -127,6 +131,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
127 | switch (optname) { | 131 | switch (optname) { |
128 | 132 | ||
129 | case IPV6_ADDRFORM: | 133 | case IPV6_ADDRFORM: |
134 | if (optlen < sizeof(int)) | ||
135 | goto e_inval; | ||
130 | if (val == PF_INET) { | 136 | if (val == PF_INET) { |
131 | struct ipv6_txoptions *opt; | 137 | struct ipv6_txoptions *opt; |
132 | struct sk_buff *pktopt; | 138 | struct sk_buff *pktopt; |
@@ -201,63 +207,86 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
201 | goto e_inval; | 207 | goto e_inval; |
202 | 208 | ||
203 | case IPV6_V6ONLY: | 209 | case IPV6_V6ONLY: |
204 | if (inet_sk(sk)->num) | 210 | if (optlen < sizeof(int) || |
211 | inet_sk(sk)->num) | ||
205 | goto e_inval; | 212 | goto e_inval; |
206 | np->ipv6only = valbool; | 213 | np->ipv6only = valbool; |
207 | retv = 0; | 214 | retv = 0; |
208 | break; | 215 | break; |
209 | 216 | ||
210 | case IPV6_RECVPKTINFO: | 217 | case IPV6_RECVPKTINFO: |
218 | if (optlen < sizeof(int)) | ||
219 | goto e_inval; | ||
211 | np->rxopt.bits.rxinfo = valbool; | 220 | np->rxopt.bits.rxinfo = valbool; |
212 | retv = 0; | 221 | retv = 0; |
213 | break; | 222 | break; |
214 | 223 | ||
215 | case IPV6_2292PKTINFO: | 224 | case IPV6_2292PKTINFO: |
225 | if (optlen < sizeof(int)) | ||
226 | goto e_inval; | ||
216 | np->rxopt.bits.rxoinfo = valbool; | 227 | np->rxopt.bits.rxoinfo = valbool; |
217 | retv = 0; | 228 | retv = 0; |
218 | break; | 229 | break; |
219 | 230 | ||
220 | case IPV6_RECVHOPLIMIT: | 231 | case IPV6_RECVHOPLIMIT: |
232 | if (optlen < sizeof(int)) | ||
233 | goto e_inval; | ||
221 | np->rxopt.bits.rxhlim = valbool; | 234 | np->rxopt.bits.rxhlim = valbool; |
222 | retv = 0; | 235 | retv = 0; |
223 | break; | 236 | break; |
224 | 237 | ||
225 | case IPV6_2292HOPLIMIT: | 238 | case IPV6_2292HOPLIMIT: |
239 | if (optlen < sizeof(int)) | ||
240 | goto e_inval; | ||
226 | np->rxopt.bits.rxohlim = valbool; | 241 | np->rxopt.bits.rxohlim = valbool; |
227 | retv = 0; | 242 | retv = 0; |
228 | break; | 243 | break; |
229 | 244 | ||
230 | case IPV6_RECVRTHDR: | 245 | case IPV6_RECVRTHDR: |
246 | if (optlen < sizeof(int)) | ||
247 | goto e_inval; | ||
231 | np->rxopt.bits.srcrt = valbool; | 248 | np->rxopt.bits.srcrt = valbool; |
232 | retv = 0; | 249 | retv = 0; |
233 | break; | 250 | break; |
234 | 251 | ||
235 | case IPV6_2292RTHDR: | 252 | case IPV6_2292RTHDR: |
253 | if (optlen < sizeof(int)) | ||
254 | goto e_inval; | ||
236 | np->rxopt.bits.osrcrt = valbool; | 255 | np->rxopt.bits.osrcrt = valbool; |
237 | retv = 0; | 256 | retv = 0; |
238 | break; | 257 | break; |
239 | 258 | ||
240 | case IPV6_RECVHOPOPTS: | 259 | case IPV6_RECVHOPOPTS: |
260 | if (optlen < sizeof(int)) | ||
261 | goto e_inval; | ||
241 | np->rxopt.bits.hopopts = valbool; | 262 | np->rxopt.bits.hopopts = valbool; |
242 | retv = 0; | 263 | retv = 0; |
243 | break; | 264 | break; |
244 | 265 | ||
245 | case IPV6_2292HOPOPTS: | 266 | case IPV6_2292HOPOPTS: |
267 | if (optlen < sizeof(int)) | ||
268 | goto e_inval; | ||
246 | np->rxopt.bits.ohopopts = valbool; | 269 | np->rxopt.bits.ohopopts = valbool; |
247 | retv = 0; | 270 | retv = 0; |
248 | break; | 271 | break; |
249 | 272 | ||
250 | case IPV6_RECVDSTOPTS: | 273 | case IPV6_RECVDSTOPTS: |
274 | if (optlen < sizeof(int)) | ||
275 | goto e_inval; | ||
251 | np->rxopt.bits.dstopts = valbool; | 276 | np->rxopt.bits.dstopts = valbool; |
252 | retv = 0; | 277 | retv = 0; |
253 | break; | 278 | break; |
254 | 279 | ||
255 | case IPV6_2292DSTOPTS: | 280 | case IPV6_2292DSTOPTS: |
281 | if (optlen < sizeof(int)) | ||
282 | goto e_inval; | ||
256 | np->rxopt.bits.odstopts = valbool; | 283 | np->rxopt.bits.odstopts = valbool; |
257 | retv = 0; | 284 | retv = 0; |
258 | break; | 285 | break; |
259 | 286 | ||
260 | case IPV6_TCLASS: | 287 | case IPV6_TCLASS: |
288 | if (optlen < sizeof(int)) | ||
289 | goto e_inval; | ||
261 | if (val < -1 || val > 0xff) | 290 | if (val < -1 || val > 0xff) |
262 | goto e_inval; | 291 | goto e_inval; |
263 | np->tclass = val; | 292 | np->tclass = val; |
@@ -265,11 +294,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
265 | break; | 294 | break; |
266 | 295 | ||
267 | case IPV6_RECVTCLASS: | 296 | case IPV6_RECVTCLASS: |
297 | if (optlen < sizeof(int)) | ||
298 | goto e_inval; | ||
268 | np->rxopt.bits.rxtclass = valbool; | 299 | np->rxopt.bits.rxtclass = valbool; |
269 | retv = 0; | 300 | retv = 0; |
270 | break; | 301 | break; |
271 | 302 | ||
272 | case IPV6_FLOWINFO: | 303 | case IPV6_FLOWINFO: |
304 | if (optlen < sizeof(int)) | ||
305 | goto e_inval; | ||
273 | np->rxopt.bits.rxflow = valbool; | 306 | np->rxopt.bits.rxflow = valbool; |
274 | retv = 0; | 307 | retv = 0; |
275 | break; | 308 | break; |
@@ -288,9 +321,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, | |||
288 | if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) | 321 | if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) |
289 | break; | 322 | break; |
290 | 323 | ||
291 | retv = -EINVAL; | 324 | if (optlen < sizeof(struct ipv6_opt_hdr) || |
292 | if (optlen & 0x7 || optlen > 8 * 255) | 325 | optlen & 0x7 || optlen > 8 * 255) |
293 | break; | 326 | goto e_inval; |
294 | 327 | ||
295 | opt = ipv6_renew_options(sk, np->opt, optname, | 328 | opt = ipv6_renew_options(sk, np->opt, optname, |
296 | (struct ipv6_opt_hdr __user *)optval, | 329 | (struct ipv6_opt_hdr __user *)optval, |
@@ -408,6 +441,8 @@ done: | |||
408 | break; | 441 | break; |
409 | } | 442 | } |
410 | case IPV6_UNICAST_HOPS: | 443 | case IPV6_UNICAST_HOPS: |
444 | if (optlen < sizeof(int)) | ||
445 | goto e_inval; | ||
411 | if (val > 255 || val < -1) | 446 | if (val > 255 || val < -1) |
412 | goto e_inval; | 447 | goto e_inval; |
413 | np->hop_limit = val; | 448 | np->hop_limit = val; |
@@ -417,6 +452,8 @@ done: | |||
417 | case IPV6_MULTICAST_HOPS: | 452 | case IPV6_MULTICAST_HOPS: |
418 | if (sk->sk_type == SOCK_STREAM) | 453 | if (sk->sk_type == SOCK_STREAM) |
419 | goto e_inval; | 454 | goto e_inval; |
455 | if (optlen < sizeof(int)) | ||
456 | goto e_inval; | ||
420 | if (val > 255 || val < -1) | 457 | if (val > 255 || val < -1) |
421 | goto e_inval; | 458 | goto e_inval; |
422 | np->mcast_hops = val; | 459 | np->mcast_hops = val; |
@@ -424,6 +461,8 @@ done: | |||
424 | break; | 461 | break; |
425 | 462 | ||
426 | case IPV6_MULTICAST_LOOP: | 463 | case IPV6_MULTICAST_LOOP: |
464 | if (optlen < sizeof(int)) | ||
465 | goto e_inval; | ||
427 | np->mc_loop = valbool; | 466 | np->mc_loop = valbool; |
428 | retv = 0; | 467 | retv = 0; |
429 | break; | 468 | break; |
@@ -431,6 +470,8 @@ done: | |||
431 | case IPV6_MULTICAST_IF: | 470 | case IPV6_MULTICAST_IF: |
432 | if (sk->sk_type == SOCK_STREAM) | 471 | if (sk->sk_type == SOCK_STREAM) |
433 | goto e_inval; | 472 | goto e_inval; |
473 | if (optlen < sizeof(int)) | ||
474 | goto e_inval; | ||
434 | 475 | ||
435 | if (val) { | 476 | if (val) { |
436 | if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) | 477 | if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) |
@@ -591,27 +632,37 @@ done: | |||
591 | break; | 632 | break; |
592 | } | 633 | } |
593 | case IPV6_ROUTER_ALERT: | 634 | case IPV6_ROUTER_ALERT: |
635 | if (optlen < sizeof(int)) | ||
636 | goto e_inval; | ||
594 | retv = ip6_ra_control(sk, val, NULL); | 637 | retv = ip6_ra_control(sk, val, NULL); |
595 | break; | 638 | break; |
596 | case IPV6_MTU_DISCOVER: | 639 | case IPV6_MTU_DISCOVER: |
640 | if (optlen < sizeof(int)) | ||
641 | goto e_inval; | ||
597 | if (val<0 || val>3) | 642 | if (val<0 || val>3) |
598 | goto e_inval; | 643 | goto e_inval; |
599 | np->pmtudisc = val; | 644 | np->pmtudisc = val; |
600 | retv = 0; | 645 | retv = 0; |
601 | break; | 646 | break; |
602 | case IPV6_MTU: | 647 | case IPV6_MTU: |
648 | if (optlen < sizeof(int)) | ||
649 | goto e_inval; | ||
603 | if (val && val < IPV6_MIN_MTU) | 650 | if (val && val < IPV6_MIN_MTU) |
604 | goto e_inval; | 651 | goto e_inval; |
605 | np->frag_size = val; | 652 | np->frag_size = val; |
606 | retv = 0; | 653 | retv = 0; |
607 | break; | 654 | break; |
608 | case IPV6_RECVERR: | 655 | case IPV6_RECVERR: |
656 | if (optlen < sizeof(int)) | ||
657 | goto e_inval; | ||
609 | np->recverr = valbool; | 658 | np->recverr = valbool; |
610 | if (!val) | 659 | if (!val) |
611 | skb_queue_purge(&sk->sk_error_queue); | 660 | skb_queue_purge(&sk->sk_error_queue); |
612 | retv = 0; | 661 | retv = 0; |
613 | break; | 662 | break; |
614 | case IPV6_FLOWINFO_SEND: | 663 | case IPV6_FLOWINFO_SEND: |
664 | if (optlen < sizeof(int)) | ||
665 | goto e_inval; | ||
615 | np->sndflow = valbool; | 666 | np->sndflow = valbool; |
616 | retv = 0; | 667 | retv = 0; |
617 | break; | 668 | break; |
@@ -631,6 +682,9 @@ done: | |||
631 | unsigned int pref = 0; | 682 | unsigned int pref = 0; |
632 | unsigned int prefmask = ~0; | 683 | unsigned int prefmask = ~0; |
633 | 684 | ||
685 | if (optlen < sizeof(int)) | ||
686 | goto e_inval; | ||
687 | |||
634 | retv = -EINVAL; | 688 | retv = -EINVAL; |
635 | 689 | ||
636 | /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ | 690 | /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ |