aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ipv6_sockglue.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-04-11 23:59:42 -0400
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2008-04-12 00:43:24 -0400
commitb2a9d7c2f8ab151fff78db06f1ae9b22a856e95e (patch)
tree0d5451a945d09a44423caa205e8ff8b6ffdbd254 /net/ipv6/ipv6_sockglue.c
parenta28398ba6112be28c6a92aacf06aca1979b454b7 (diff)
[IPV6]: Check length of int/boolean optval provided by user in setsockopt().
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net/ipv6/ipv6_sockglue.c')
-rw-r--r--net/ipv6/ipv6_sockglue.c68
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 */