hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/net/ipv6/ipv6_sockglue.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * IPv6 BSD socket options interface
34 * Linux INET6 implementation
....@@ -6,11 +7,6 @@
67 * Pedro Roque <roque@di.fc.ul.pt>
78 *
89 * Based on linux/net/ipv4/ip_sockglue.c
9
- *
10
- * This program is free software; you can redistribute it and/or
11
- * modify it under the terms of the GNU General Public License
12
- * as published by the Free Software Foundation; either version
13
- * 2 of the License, or (at your option) any later version.
1410 *
1511 * FIXME: Make the setsockopt code POSIX compliant: That is
1612 *
....@@ -68,6 +64,8 @@
6864 return -ENOPROTOOPT;
6965
7066 new_ra = (sel >= 0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL;
67
+ if (sel >= 0 && !new_ra)
68
+ return -ENOMEM;
7169
7270 write_lock_bh(&ip6_ra_lock);
7371 for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) {
....@@ -138,8 +136,261 @@
138136 return false;
139137 }
140138
139
+static int copy_group_source_from_sockptr(struct group_source_req *greqs,
140
+ sockptr_t optval, int optlen)
141
+{
142
+ if (in_compat_syscall()) {
143
+ struct compat_group_source_req gr32;
144
+
145
+ if (optlen < sizeof(gr32))
146
+ return -EINVAL;
147
+ if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
148
+ return -EFAULT;
149
+ greqs->gsr_interface = gr32.gsr_interface;
150
+ greqs->gsr_group = gr32.gsr_group;
151
+ greqs->gsr_source = gr32.gsr_source;
152
+ } else {
153
+ if (optlen < sizeof(*greqs))
154
+ return -EINVAL;
155
+ if (copy_from_sockptr(greqs, optval, sizeof(*greqs)))
156
+ return -EFAULT;
157
+ }
158
+
159
+ return 0;
160
+}
161
+
162
+static int do_ipv6_mcast_group_source(struct sock *sk, int optname,
163
+ sockptr_t optval, int optlen)
164
+{
165
+ struct group_source_req greqs;
166
+ int omode, add;
167
+ int ret;
168
+
169
+ ret = copy_group_source_from_sockptr(&greqs, optval, optlen);
170
+ if (ret)
171
+ return ret;
172
+
173
+ if (greqs.gsr_group.ss_family != AF_INET6 ||
174
+ greqs.gsr_source.ss_family != AF_INET6)
175
+ return -EADDRNOTAVAIL;
176
+
177
+ if (optname == MCAST_BLOCK_SOURCE) {
178
+ omode = MCAST_EXCLUDE;
179
+ add = 1;
180
+ } else if (optname == MCAST_UNBLOCK_SOURCE) {
181
+ omode = MCAST_EXCLUDE;
182
+ add = 0;
183
+ } else if (optname == MCAST_JOIN_SOURCE_GROUP) {
184
+ struct sockaddr_in6 *psin6;
185
+ int retv;
186
+
187
+ psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
188
+ retv = ipv6_sock_mc_join_ssm(sk, greqs.gsr_interface,
189
+ &psin6->sin6_addr,
190
+ MCAST_INCLUDE);
191
+ /* prior join w/ different source is ok */
192
+ if (retv && retv != -EADDRINUSE)
193
+ return retv;
194
+ omode = MCAST_INCLUDE;
195
+ add = 1;
196
+ } else /* MCAST_LEAVE_SOURCE_GROUP */ {
197
+ omode = MCAST_INCLUDE;
198
+ add = 0;
199
+ }
200
+ return ip6_mc_source(add, omode, sk, &greqs);
201
+}
202
+
203
+static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
204
+ int optlen)
205
+{
206
+ struct group_filter *gsf;
207
+ int ret;
208
+
209
+ if (optlen < GROUP_FILTER_SIZE(0))
210
+ return -EINVAL;
211
+ if (optlen > READ_ONCE(sysctl_optmem_max))
212
+ return -ENOBUFS;
213
+
214
+ gsf = memdup_sockptr(optval, optlen);
215
+ if (IS_ERR(gsf))
216
+ return PTR_ERR(gsf);
217
+
218
+ /* numsrc >= (4G-140)/128 overflow in 32 bits */
219
+ ret = -ENOBUFS;
220
+ if (gsf->gf_numsrc >= 0x1ffffffU ||
221
+ gsf->gf_numsrc > sysctl_mld_max_msf)
222
+ goto out_free_gsf;
223
+
224
+ ret = -EINVAL;
225
+ if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen)
226
+ goto out_free_gsf;
227
+
228
+ ret = ip6_mc_msfilter(sk, gsf, gsf->gf_slist);
229
+out_free_gsf:
230
+ kfree(gsf);
231
+ return ret;
232
+}
233
+
234
+static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval,
235
+ int optlen)
236
+{
237
+ const int size0 = offsetof(struct compat_group_filter, gf_slist);
238
+ struct compat_group_filter *gf32;
239
+ void *p;
240
+ int ret;
241
+ int n;
242
+
243
+ if (optlen < size0)
244
+ return -EINVAL;
245
+ if (optlen > READ_ONCE(sysctl_optmem_max) - 4)
246
+ return -ENOBUFS;
247
+
248
+ p = kmalloc(optlen + 4, GFP_KERNEL);
249
+ if (!p)
250
+ return -ENOMEM;
251
+
252
+ gf32 = p + 4; /* we want ->gf_group and ->gf_slist aligned */
253
+ ret = -EFAULT;
254
+ if (copy_from_sockptr(gf32, optval, optlen))
255
+ goto out_free_p;
256
+
257
+ /* numsrc >= (4G-140)/128 overflow in 32 bits */
258
+ ret = -ENOBUFS;
259
+ n = gf32->gf_numsrc;
260
+ if (n >= 0x1ffffffU || n > sysctl_mld_max_msf)
261
+ goto out_free_p;
262
+
263
+ ret = -EINVAL;
264
+ if (offsetof(struct compat_group_filter, gf_slist[n]) > optlen)
265
+ goto out_free_p;
266
+
267
+ ret = ip6_mc_msfilter(sk, &(struct group_filter){
268
+ .gf_interface = gf32->gf_interface,
269
+ .gf_group = gf32->gf_group,
270
+ .gf_fmode = gf32->gf_fmode,
271
+ .gf_numsrc = gf32->gf_numsrc}, gf32->gf_slist);
272
+
273
+out_free_p:
274
+ kfree(p);
275
+ return ret;
276
+}
277
+
278
+static int ipv6_mcast_join_leave(struct sock *sk, int optname,
279
+ sockptr_t optval, int optlen)
280
+{
281
+ struct sockaddr_in6 *psin6;
282
+ struct group_req greq;
283
+
284
+ if (optlen < sizeof(greq))
285
+ return -EINVAL;
286
+ if (copy_from_sockptr(&greq, optval, sizeof(greq)))
287
+ return -EFAULT;
288
+
289
+ if (greq.gr_group.ss_family != AF_INET6)
290
+ return -EADDRNOTAVAIL;
291
+ psin6 = (struct sockaddr_in6 *)&greq.gr_group;
292
+ if (optname == MCAST_JOIN_GROUP)
293
+ return ipv6_sock_mc_join(sk, greq.gr_interface,
294
+ &psin6->sin6_addr);
295
+ return ipv6_sock_mc_drop(sk, greq.gr_interface, &psin6->sin6_addr);
296
+}
297
+
298
+static int compat_ipv6_mcast_join_leave(struct sock *sk, int optname,
299
+ sockptr_t optval, int optlen)
300
+{
301
+ struct compat_group_req gr32;
302
+ struct sockaddr_in6 *psin6;
303
+
304
+ if (optlen < sizeof(gr32))
305
+ return -EINVAL;
306
+ if (copy_from_sockptr(&gr32, optval, sizeof(gr32)))
307
+ return -EFAULT;
308
+
309
+ if (gr32.gr_group.ss_family != AF_INET6)
310
+ return -EADDRNOTAVAIL;
311
+ psin6 = (struct sockaddr_in6 *)&gr32.gr_group;
312
+ if (optname == MCAST_JOIN_GROUP)
313
+ return ipv6_sock_mc_join(sk, gr32.gr_interface,
314
+ &psin6->sin6_addr);
315
+ return ipv6_sock_mc_drop(sk, gr32.gr_interface, &psin6->sin6_addr);
316
+}
317
+
318
+static int ipv6_set_opt_hdr(struct sock *sk, int optname, sockptr_t optval,
319
+ int optlen)
320
+{
321
+ struct ipv6_pinfo *np = inet6_sk(sk);
322
+ struct ipv6_opt_hdr *new = NULL;
323
+ struct net *net = sock_net(sk);
324
+ struct ipv6_txoptions *opt;
325
+ int err;
326
+
327
+ /* hop-by-hop / destination options are privileged option */
328
+ if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
329
+ return -EPERM;
330
+
331
+ /* remove any sticky options header with a zero option
332
+ * length, per RFC3542.
333
+ */
334
+ if (optlen > 0) {
335
+ if (sockptr_is_null(optval))
336
+ return -EINVAL;
337
+ if (optlen < sizeof(struct ipv6_opt_hdr) ||
338
+ optlen & 0x7 ||
339
+ optlen > 8 * 255)
340
+ return -EINVAL;
341
+
342
+ new = memdup_sockptr(optval, optlen);
343
+ if (IS_ERR(new))
344
+ return PTR_ERR(new);
345
+ if (unlikely(ipv6_optlen(new) > optlen)) {
346
+ kfree(new);
347
+ return -EINVAL;
348
+ }
349
+ }
350
+
351
+ opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk));
352
+ opt = ipv6_renew_options(sk, opt, optname, new);
353
+ kfree(new);
354
+ if (IS_ERR(opt))
355
+ return PTR_ERR(opt);
356
+
357
+ /* routing header option needs extra check */
358
+ err = -EINVAL;
359
+ if (optname == IPV6_RTHDR && opt && opt->srcrt) {
360
+ struct ipv6_rt_hdr *rthdr = opt->srcrt;
361
+ switch (rthdr->type) {
362
+#if IS_ENABLED(CONFIG_IPV6_MIP6)
363
+ case IPV6_SRCRT_TYPE_2:
364
+ if (rthdr->hdrlen != 2 || rthdr->segments_left != 1)
365
+ goto sticky_done;
366
+ break;
367
+#endif
368
+ case IPV6_SRCRT_TYPE_4:
369
+ {
370
+ struct ipv6_sr_hdr *srh =
371
+ (struct ipv6_sr_hdr *)opt->srcrt;
372
+
373
+ if (!seg6_validate_srh(srh, optlen, false))
374
+ goto sticky_done;
375
+ break;
376
+ }
377
+ default:
378
+ goto sticky_done;
379
+ }
380
+ }
381
+
382
+ err = 0;
383
+ opt = ipv6_update_options(sk, opt);
384
+sticky_done:
385
+ if (opt) {
386
+ atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
387
+ txopt_put(opt);
388
+ }
389
+ return err;
390
+}
391
+
141392 static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
142
- char __user *optval, unsigned int optlen)
393
+ sockptr_t optval, unsigned int optlen)
143394 {
144395 struct ipv6_pinfo *np = inet6_sk(sk);
145396 struct net *net = sock_net(sk);
....@@ -147,11 +398,11 @@
147398 int retv = -ENOPROTOOPT;
148399 bool needs_rtnl = setsockopt_needs_rtnl(optname);
149400
150
- if (!optval)
401
+ if (sockptr_is_null(optval))
151402 val = 0;
152403 else {
153404 if (optlen >= sizeof(int)) {
154
- if (get_user(val, (int __user *) optval))
405
+ if (copy_from_sockptr(&val, optval, sizeof(val)))
155406 return -EFAULT;
156407 } else
157408 val = 0;
....@@ -166,15 +417,18 @@
166417 rtnl_lock();
167418 lock_sock(sk);
168419
420
+ /* Another thread has converted the socket into IPv4 with
421
+ * IPV6_ADDRFORM concurrently.
422
+ */
423
+ if (unlikely(sk->sk_family != AF_INET6))
424
+ goto unlock;
425
+
169426 switch (optname) {
170427
171428 case IPV6_ADDRFORM:
172429 if (optlen < sizeof(int))
173430 goto e_inval;
174431 if (val == PF_INET) {
175
- struct ipv6_txoptions *opt;
176
- struct sk_buff *pktopt;
177
-
178432 if (sk->sk_type == SOCK_RAW)
179433 break;
180434
....@@ -205,7 +459,6 @@
205459 break;
206460 }
207461
208
- fl6_free_socklist(sk);
209462 __ipv6_sock_mc_close(sk);
210463 __ipv6_sock_ac_close(sk);
211464
....@@ -240,14 +493,14 @@
240493 sk->sk_socket->ops = &inet_dgram_ops;
241494 sk->sk_family = PF_INET;
242495 }
243
- opt = xchg((__force struct ipv6_txoptions **)&np->opt,
244
- NULL);
245
- if (opt) {
246
- atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
247
- txopt_put(opt);
248
- }
249
- pktopt = xchg(&np->pktoptions, NULL);
250
- kfree_skb(pktopt);
496
+
497
+ /* Disable all options not to allocate memory anymore,
498
+ * but there is still a race. See the lockless path
499
+ * in udpv6_sendmsg() and ipv6_local_rxpmtu().
500
+ */
501
+ np->rxopt.all = 0;
502
+
503
+ inet6_cleanup_sock(sk);
251504
252505 /*
253506 * ... and add it to the refcnt debug socks count
....@@ -372,8 +625,8 @@
372625 break;
373626
374627 case IPV6_TRANSPARENT:
375
- if (valbool && !ns_capable(net->user_ns, CAP_NET_ADMIN) &&
376
- !ns_capable(net->user_ns, CAP_NET_RAW)) {
628
+ if (valbool && !ns_capable(net->user_ns, CAP_NET_RAW) &&
629
+ !ns_capable(net->user_ns, CAP_NET_ADMIN)) {
377630 retv = -EPERM;
378631 break;
379632 }
....@@ -403,82 +656,8 @@
403656 case IPV6_RTHDRDSTOPTS:
404657 case IPV6_RTHDR:
405658 case IPV6_DSTOPTS:
406
- {
407
- struct ipv6_txoptions *opt;
408
- struct ipv6_opt_hdr *new = NULL;
409
-
410
- /* hop-by-hop / destination options are privileged option */
411
- retv = -EPERM;
412
- if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
413
- break;
414
-
415
- /* remove any sticky options header with a zero option
416
- * length, per RFC3542.
417
- */
418
- if (optlen == 0)
419
- optval = NULL;
420
- else if (!optval)
421
- goto e_inval;
422
- else if (optlen < sizeof(struct ipv6_opt_hdr) ||
423
- optlen & 0x7 || optlen > 8 * 255)
424
- goto e_inval;
425
- else {
426
- new = memdup_user(optval, optlen);
427
- if (IS_ERR(new)) {
428
- retv = PTR_ERR(new);
429
- break;
430
- }
431
- if (unlikely(ipv6_optlen(new) > optlen)) {
432
- kfree(new);
433
- goto e_inval;
434
- }
435
- }
436
-
437
- opt = rcu_dereference_protected(np->opt,
438
- lockdep_sock_is_held(sk));
439
- opt = ipv6_renew_options(sk, opt, optname, new);
440
- kfree(new);
441
- if (IS_ERR(opt)) {
442
- retv = PTR_ERR(opt);
443
- break;
444
- }
445
-
446
- /* routing header option needs extra check */
447
- retv = -EINVAL;
448
- if (optname == IPV6_RTHDR && opt && opt->srcrt) {
449
- struct ipv6_rt_hdr *rthdr = opt->srcrt;
450
- switch (rthdr->type) {
451
-#if IS_ENABLED(CONFIG_IPV6_MIP6)
452
- case IPV6_SRCRT_TYPE_2:
453
- if (rthdr->hdrlen != 2 ||
454
- rthdr->segments_left != 1)
455
- goto sticky_done;
456
-
457
- break;
458
-#endif
459
- case IPV6_SRCRT_TYPE_4:
460
- {
461
- struct ipv6_sr_hdr *srh = (struct ipv6_sr_hdr *)
462
- opt->srcrt;
463
-
464
- if (!seg6_validate_srh(srh, optlen))
465
- goto sticky_done;
466
- break;
467
- }
468
- default:
469
- goto sticky_done;
470
- }
471
- }
472
-
473
- retv = 0;
474
- opt = ipv6_update_options(sk, opt);
475
-sticky_done:
476
- if (opt) {
477
- atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
478
- txopt_put(opt);
479
- }
659
+ retv = ipv6_set_opt_hdr(sk, optname, optval, optlen);
480660 break;
481
- }
482661
483662 case IPV6_PKTINFO:
484663 {
....@@ -486,14 +665,15 @@
486665
487666 if (optlen == 0)
488667 goto e_inval;
489
- else if (optlen < sizeof(struct in6_pktinfo) || !optval)
668
+ else if (optlen < sizeof(struct in6_pktinfo) ||
669
+ sockptr_is_null(optval))
490670 goto e_inval;
491671
492
- if (copy_from_user(&pkt, optval, sizeof(struct in6_pktinfo))) {
493
- retv = -EFAULT;
494
- break;
672
+ if (copy_from_sockptr(&pkt, optval, sizeof(pkt))) {
673
+ retv = -EFAULT;
674
+ break;
495675 }
496
- if (sk->sk_bound_dev_if && pkt.ipi6_ifindex != sk->sk_bound_dev_if)
676
+ if (!sk_dev_equal_l3scope(sk, pkt.ipi6_ifindex))
497677 goto e_inval;
498678
499679 np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex;
....@@ -532,7 +712,7 @@
532712 refcount_set(&opt->refcnt, 1);
533713 opt->tot_len = sizeof(*opt) + optlen;
534714 retv = -EFAULT;
535
- if (copy_from_user(opt+1, optval, optlen))
715
+ if (copy_from_sockptr(opt + 1, optval, optlen))
536716 goto done;
537717
538718 msg.msg_controllen = optlen;
....@@ -654,7 +834,7 @@
654834 break;
655835
656836 retv = -EFAULT;
657
- if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
837
+ if (copy_from_sockptr(&mreq, optval, sizeof(struct ipv6_mreq)))
658838 break;
659839
660840 if (optname == IPV6_ADD_MEMBERSHIP)
....@@ -672,7 +852,7 @@
672852 goto e_inval;
673853
674854 retv = -EFAULT;
675
- if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq)))
855
+ if (copy_from_sockptr(&mreq, optval, sizeof(struct ipv6_mreq)))
676856 break;
677857
678858 if (optname == IPV6_JOIN_ANYCAST)
....@@ -681,111 +861,45 @@
681861 retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr);
682862 break;
683863 }
864
+ case IPV6_MULTICAST_ALL:
865
+ if (optlen < sizeof(int))
866
+ goto e_inval;
867
+ np->mc_all = valbool;
868
+ retv = 0;
869
+ break;
870
+
684871 case MCAST_JOIN_GROUP:
685872 case MCAST_LEAVE_GROUP:
686
- {
687
- struct group_req greq;
688
- struct sockaddr_in6 *psin6;
689
-
690
- if (optlen < sizeof(struct group_req))
691
- goto e_inval;
692
-
693
- retv = -EFAULT;
694
- if (copy_from_user(&greq, optval, sizeof(struct group_req)))
695
- break;
696
- if (greq.gr_group.ss_family != AF_INET6) {
697
- retv = -EADDRNOTAVAIL;
698
- break;
699
- }
700
- psin6 = (struct sockaddr_in6 *)&greq.gr_group;
701
- if (optname == MCAST_JOIN_GROUP)
702
- retv = ipv6_sock_mc_join(sk, greq.gr_interface,
703
- &psin6->sin6_addr);
873
+ if (in_compat_syscall())
874
+ retv = compat_ipv6_mcast_join_leave(sk, optname, optval,
875
+ optlen);
704876 else
705
- retv = ipv6_sock_mc_drop(sk, greq.gr_interface,
706
- &psin6->sin6_addr);
877
+ retv = ipv6_mcast_join_leave(sk, optname, optval,
878
+ optlen);
707879 break;
708
- }
709880 case MCAST_JOIN_SOURCE_GROUP:
710881 case MCAST_LEAVE_SOURCE_GROUP:
711882 case MCAST_BLOCK_SOURCE:
712883 case MCAST_UNBLOCK_SOURCE:
713
- {
714
- struct group_source_req greqs;
715
- int omode, add;
716
-
717
- if (optlen < sizeof(struct group_source_req))
718
- goto e_inval;
719
- if (copy_from_user(&greqs, optval, sizeof(greqs))) {
720
- retv = -EFAULT;
721
- break;
722
- }
723
- if (greqs.gsr_group.ss_family != AF_INET6 ||
724
- greqs.gsr_source.ss_family != AF_INET6) {
725
- retv = -EADDRNOTAVAIL;
726
- break;
727
- }
728
- if (optname == MCAST_BLOCK_SOURCE) {
729
- omode = MCAST_EXCLUDE;
730
- add = 1;
731
- } else if (optname == MCAST_UNBLOCK_SOURCE) {
732
- omode = MCAST_EXCLUDE;
733
- add = 0;
734
- } else if (optname == MCAST_JOIN_SOURCE_GROUP) {
735
- struct sockaddr_in6 *psin6;
736
-
737
- psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
738
- retv = ipv6_sock_mc_join_ssm(sk, greqs.gsr_interface,
739
- &psin6->sin6_addr,
740
- MCAST_INCLUDE);
741
- /* prior join w/ different source is ok */
742
- if (retv && retv != -EADDRINUSE)
743
- break;
744
- omode = MCAST_INCLUDE;
745
- add = 1;
746
- } else /* MCAST_LEAVE_SOURCE_GROUP */ {
747
- omode = MCAST_INCLUDE;
748
- add = 0;
749
- }
750
- retv = ip6_mc_source(add, omode, sk, &greqs);
884
+ retv = do_ipv6_mcast_group_source(sk, optname, optval, optlen);
751885 break;
752
- }
753886 case MCAST_MSFILTER:
754
- {
755
- struct group_filter *gsf;
756
-
757
- if (optlen < GROUP_FILTER_SIZE(0))
758
- goto e_inval;
759
- if (optlen > sysctl_optmem_max) {
760
- retv = -ENOBUFS;
761
- break;
762
- }
763
- gsf = memdup_user(optval, optlen);
764
- if (IS_ERR(gsf)) {
765
- retv = PTR_ERR(gsf);
766
- break;
767
- }
768
- /* numsrc >= (4G-140)/128 overflow in 32 bits */
769
- if (gsf->gf_numsrc >= 0x1ffffffU ||
770
- gsf->gf_numsrc > sysctl_mld_max_msf) {
771
- kfree(gsf);
772
- retv = -ENOBUFS;
773
- break;
774
- }
775
- if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) {
776
- kfree(gsf);
777
- retv = -EINVAL;
778
- break;
779
- }
780
- retv = ip6_mc_msfilter(sk, gsf);
781
- kfree(gsf);
782
-
887
+ if (in_compat_syscall())
888
+ retv = compat_ipv6_set_mcast_msfilter(sk, optval,
889
+ optlen);
890
+ else
891
+ retv = ipv6_set_mcast_msfilter(sk, optval, optlen);
783892 break;
784
- }
785893 case IPV6_ROUTER_ALERT:
786894 if (optlen < sizeof(int))
787895 goto e_inval;
788896 retv = ip6_ra_control(sk, val);
897
+ break;
898
+ case IPV6_ROUTER_ALERT_ISOLATE:
899
+ if (optlen < sizeof(int))
900
+ goto e_inval;
901
+ np->rtalert_isolate = valbool;
902
+ retv = 0;
789903 break;
790904 case IPV6_MTU_DISCOVER:
791905 if (optlen < sizeof(int))
....@@ -829,67 +943,10 @@
829943 break;
830944
831945 case IPV6_ADDR_PREFERENCES:
832
- {
833
- unsigned int pref = 0;
834
- unsigned int prefmask = ~0;
835
-
836946 if (optlen < sizeof(int))
837947 goto e_inval;
838
-
839
- retv = -EINVAL;
840
-
841
- /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */
842
- switch (val & (IPV6_PREFER_SRC_PUBLIC|
843
- IPV6_PREFER_SRC_TMP|
844
- IPV6_PREFER_SRC_PUBTMP_DEFAULT)) {
845
- case IPV6_PREFER_SRC_PUBLIC:
846
- pref |= IPV6_PREFER_SRC_PUBLIC;
847
- break;
848
- case IPV6_PREFER_SRC_TMP:
849
- pref |= IPV6_PREFER_SRC_TMP;
850
- break;
851
- case IPV6_PREFER_SRC_PUBTMP_DEFAULT:
852
- break;
853
- case 0:
854
- goto pref_skip_pubtmp;
855
- default:
856
- goto e_inval;
857
- }
858
-
859
- prefmask &= ~(IPV6_PREFER_SRC_PUBLIC|
860
- IPV6_PREFER_SRC_TMP);
861
-pref_skip_pubtmp:
862
-
863
- /* check HOME/COA conflicts */
864
- switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) {
865
- case IPV6_PREFER_SRC_HOME:
866
- break;
867
- case IPV6_PREFER_SRC_COA:
868
- pref |= IPV6_PREFER_SRC_COA;
869
- case 0:
870
- goto pref_skip_coa;
871
- default:
872
- goto e_inval;
873
- }
874
-
875
- prefmask &= ~IPV6_PREFER_SRC_COA;
876
-pref_skip_coa:
877
-
878
- /* check CGA/NONCGA conflicts */
879
- switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) {
880
- case IPV6_PREFER_SRC_CGA:
881
- case IPV6_PREFER_SRC_NONCGA:
882
- case 0:
883
- break;
884
- default:
885
- goto e_inval;
886
- }
887
-
888
- np->srcprefs = (np->srcprefs & prefmask) | pref;
889
- retv = 0;
890
-
948
+ retv = __ip6_sock_set_addr_preferences(sk, val);
891949 break;
892
- }
893950 case IPV6_MINHOPCOUNT:
894951 if (optlen < sizeof(int))
895952 goto e_inval;
....@@ -911,8 +968,17 @@
911968 np->rxopt.bits.recvfragsize = valbool;
912969 retv = 0;
913970 break;
971
+ case IPV6_RECVERR_RFC4884:
972
+ if (optlen < sizeof(int))
973
+ goto e_inval;
974
+ if (val < 0 || val > 1)
975
+ goto e_inval;
976
+ np->recverr_rfc4884 = valbool;
977
+ retv = 0;
978
+ break;
914979 }
915980
981
+unlock:
916982 release_sock(sk);
917983 if (needs_rtnl)
918984 rtnl_unlock();
....@@ -926,8 +992,8 @@
926992 return -EINVAL;
927993 }
928994
929
-int ipv6_setsockopt(struct sock *sk, int level, int optname,
930
- char __user *optval, unsigned int optlen)
995
+int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval,
996
+ unsigned int optlen)
931997 {
932998 int err;
933999
....@@ -947,39 +1013,6 @@
9471013 return err;
9481014 }
9491015 EXPORT_SYMBOL(ipv6_setsockopt);
950
-
951
-#ifdef CONFIG_COMPAT
952
-int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
953
- char __user *optval, unsigned int optlen)
954
-{
955
- int err;
956
-
957
- if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
958
- if (udp_prot.compat_setsockopt != NULL)
959
- return udp_prot.compat_setsockopt(sk, level, optname,
960
- optval, optlen);
961
- return udp_prot.setsockopt(sk, level, optname, optval, optlen);
962
- }
963
-
964
- if (level != SOL_IPV6)
965
- return -ENOPROTOOPT;
966
-
967
- if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
968
- return compat_mc_setsockopt(sk, level, optname, optval, optlen,
969
- ipv6_setsockopt);
970
-
971
- err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
972
-#ifdef CONFIG_NETFILTER
973
- /* we need to exclude all possible ENOPROTOOPTs except default case */
974
- if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY &&
975
- optname != IPV6_XFRM_POLICY)
976
- err = compat_nf_setsockopt(sk, PF_INET6, optname, optval,
977
- optlen);
978
-#endif
979
- return err;
980
-}
981
-EXPORT_SYMBOL(compat_ipv6_setsockopt);
982
-#endif
9831016
9841017 static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
9851018 int optname, char __user *optval, int len)
....@@ -1015,6 +1048,75 @@
10151048 return len;
10161049 }
10171050
1051
+static int ipv6_get_msfilter(struct sock *sk, void __user *optval,
1052
+ int __user *optlen, int len)
1053
+{
1054
+ const int size0 = offsetof(struct group_filter, gf_slist);
1055
+ struct group_filter __user *p = optval;
1056
+ struct group_filter gsf;
1057
+ int num;
1058
+ int err;
1059
+
1060
+ if (len < size0)
1061
+ return -EINVAL;
1062
+ if (copy_from_user(&gsf, p, size0))
1063
+ return -EFAULT;
1064
+ if (gsf.gf_group.ss_family != AF_INET6)
1065
+ return -EADDRNOTAVAIL;
1066
+ num = gsf.gf_numsrc;
1067
+ lock_sock(sk);
1068
+ err = ip6_mc_msfget(sk, &gsf, p->gf_slist);
1069
+ if (!err) {
1070
+ if (num > gsf.gf_numsrc)
1071
+ num = gsf.gf_numsrc;
1072
+ if (put_user(GROUP_FILTER_SIZE(num), optlen) ||
1073
+ copy_to_user(p, &gsf, size0))
1074
+ err = -EFAULT;
1075
+ }
1076
+ release_sock(sk);
1077
+ return err;
1078
+}
1079
+
1080
+static int compat_ipv6_get_msfilter(struct sock *sk, void __user *optval,
1081
+ int __user *optlen)
1082
+{
1083
+ const int size0 = offsetof(struct compat_group_filter, gf_slist);
1084
+ struct compat_group_filter __user *p = optval;
1085
+ struct compat_group_filter gf32;
1086
+ struct group_filter gf;
1087
+ int len, err;
1088
+ int num;
1089
+
1090
+ if (get_user(len, optlen))
1091
+ return -EFAULT;
1092
+ if (len < size0)
1093
+ return -EINVAL;
1094
+
1095
+ if (copy_from_user(&gf32, p, size0))
1096
+ return -EFAULT;
1097
+ gf.gf_interface = gf32.gf_interface;
1098
+ gf.gf_fmode = gf32.gf_fmode;
1099
+ num = gf.gf_numsrc = gf32.gf_numsrc;
1100
+ gf.gf_group = gf32.gf_group;
1101
+
1102
+ if (gf.gf_group.ss_family != AF_INET6)
1103
+ return -EADDRNOTAVAIL;
1104
+
1105
+ lock_sock(sk);
1106
+ err = ip6_mc_msfget(sk, &gf, p->gf_slist);
1107
+ release_sock(sk);
1108
+ if (err)
1109
+ return err;
1110
+ if (num > gf.gf_numsrc)
1111
+ num = gf.gf_numsrc;
1112
+ len = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32));
1113
+ if (put_user(len, optlen) ||
1114
+ put_user(gf.gf_fmode, &p->gf_fmode) ||
1115
+ put_user(gf.gf_numsrc, &p->gf_numsrc))
1116
+ return -EFAULT;
1117
+ return 0;
1118
+}
1119
+
10181120 static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
10191121 char __user *optval, int __user *optlen, unsigned int flags)
10201122 {
....@@ -1038,23 +1140,9 @@
10381140 val = sk->sk_family;
10391141 break;
10401142 case MCAST_MSFILTER:
1041
- {
1042
- struct group_filter gsf;
1043
- int err;
1044
-
1045
- if (len < GROUP_FILTER_SIZE(0))
1046
- return -EINVAL;
1047
- if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0)))
1048
- return -EFAULT;
1049
- if (gsf.gf_group.ss_family != AF_INET6)
1050
- return -EADDRNOTAVAIL;
1051
- lock_sock(sk);
1052
- err = ip6_mc_msfget(sk, &gsf,
1053
- (struct group_filter __user *)optval, optlen);
1054
- release_sock(sk);
1055
- return err;
1056
- }
1057
-
1143
+ if (in_compat_syscall())
1144
+ return compat_ipv6_get_msfilter(sk, optval, optlen);
1145
+ return ipv6_get_msfilter(sk, optval, optlen, len);
10581146 case IPV6_2292PKTOPTIONS:
10591147 {
10601148 struct msghdr msg;
....@@ -1066,6 +1154,7 @@
10661154 msg.msg_control = optval;
10671155 msg.msg_controllen = len;
10681156 msg.msg_flags = flags;
1157
+ msg.msg_control_is_user = true;
10691158
10701159 lock_sock(sk);
10711160 skb = np->pktoptions;
....@@ -1273,6 +1362,10 @@
12731362 val = np->mcast_oif;
12741363 break;
12751364
1365
+ case IPV6_MULTICAST_ALL:
1366
+ val = np->mc_all;
1367
+ break;
1368
+
12761369 case IPV6_UNICAST_IF:
12771370 val = (__force int)htonl((__u32) np->ucast_oif);
12781371 break;
....@@ -1354,6 +1447,14 @@
13541447 val = np->rxopt.bits.recvfragsize;
13551448 break;
13561449
1450
+ case IPV6_ROUTER_ALERT_ISOLATE:
1451
+ val = np->rtalert_isolate;
1452
+ break;
1453
+
1454
+ case IPV6_RECVERR_RFC4884:
1455
+ val = np->recverr_rfc4884;
1456
+ break;
1457
+
13571458 default:
13581459 return -ENOPROTOOPT;
13591460 }
....@@ -1393,43 +1494,3 @@
13931494 return err;
13941495 }
13951496 EXPORT_SYMBOL(ipv6_getsockopt);
1396
-
1397
-#ifdef CONFIG_COMPAT
1398
-int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
1399
- char __user *optval, int __user *optlen)
1400
-{
1401
- int err;
1402
-
1403
- if (level == SOL_IP && sk->sk_type != SOCK_RAW) {
1404
- if (udp_prot.compat_getsockopt != NULL)
1405
- return udp_prot.compat_getsockopt(sk, level, optname,
1406
- optval, optlen);
1407
- return udp_prot.getsockopt(sk, level, optname, optval, optlen);
1408
- }
1409
-
1410
- if (level != SOL_IPV6)
1411
- return -ENOPROTOOPT;
1412
-
1413
- if (optname == MCAST_MSFILTER)
1414
- return compat_mc_getsockopt(sk, level, optname, optval, optlen,
1415
- ipv6_getsockopt);
1416
-
1417
- err = do_ipv6_getsockopt(sk, level, optname, optval, optlen,
1418
- MSG_CMSG_COMPAT);
1419
-#ifdef CONFIG_NETFILTER
1420
- /* we need to exclude all possible ENOPROTOOPTs except default case */
1421
- if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
1422
- int len;
1423
-
1424
- if (get_user(len, optlen))
1425
- return -EFAULT;
1426
-
1427
- err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, &len);
1428
- if (err >= 0)
1429
- err = put_user(len, optlen);
1430
- }
1431
-#endif
1432
- return err;
1433
-}
1434
-EXPORT_SYMBOL(compat_ipv6_getsockopt);
1435
-#endif