1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * IPv6 BSD socket options interface |
4 | * Linux INET6 implementation |
5 | * |
6 | * Authors: |
7 | * Pedro Roque <roque@di.fc.ul.pt> |
8 | * |
9 | * Based on linux/net/ipv4/ip_sockglue.c |
10 | * |
11 | * FIXME: Make the setsockopt code POSIX compliant: That is |
12 | * |
13 | * o Truncate getsockopt returns |
14 | * o Return an optlen of the truncated length if need be |
15 | * |
16 | * Changes: |
17 | * David L Stevens <dlstevens@us.ibm.com>: |
18 | * - added multicast source filtering API for MLDv2 |
19 | */ |
20 | |
21 | #include <linux/module.h> |
22 | #include <linux/capability.h> |
23 | #include <linux/errno.h> |
24 | #include <linux/types.h> |
25 | #include <linux/socket.h> |
26 | #include <linux/sockios.h> |
27 | #include <linux/net.h> |
28 | #include <linux/in6.h> |
29 | #include <linux/mroute6.h> |
30 | #include <linux/netdevice.h> |
31 | #include <linux/if_arp.h> |
32 | #include <linux/init.h> |
33 | #include <linux/sysctl.h> |
34 | #include <linux/netfilter.h> |
35 | #include <linux/slab.h> |
36 | |
37 | #include <net/sock.h> |
38 | #include <net/snmp.h> |
39 | #include <net/ipv6.h> |
40 | #include <net/ndisc.h> |
41 | #include <net/protocol.h> |
42 | #include <net/transp_v6.h> |
43 | #include <net/ip6_route.h> |
44 | #include <net/addrconf.h> |
45 | #include <net/inet_common.h> |
46 | #include <net/tcp.h> |
47 | #include <net/udp.h> |
48 | #include <net/udplite.h> |
49 | #include <net/xfrm.h> |
50 | #include <net/compat.h> |
51 | #include <net/seg6.h> |
52 | |
53 | #include <linux/uaccess.h> |
54 | |
55 | struct ip6_ra_chain *ip6_ra_chain; |
56 | DEFINE_RWLOCK(ip6_ra_lock); |
57 | |
58 | DEFINE_STATIC_KEY_FALSE(ip6_min_hopcount); |
59 | |
60 | int ip6_ra_control(struct sock *sk, int sel) |
61 | { |
62 | struct ip6_ra_chain *ra, *new_ra, **rap; |
63 | |
64 | /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ |
65 | if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW) |
66 | return -ENOPROTOOPT; |
67 | |
68 | new_ra = (sel >= 0) ? kmalloc(size: sizeof(*new_ra), GFP_KERNEL) : NULL; |
69 | if (sel >= 0 && !new_ra) |
70 | return -ENOMEM; |
71 | |
72 | write_lock_bh(&ip6_ra_lock); |
73 | for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) { |
74 | if (ra->sk == sk) { |
75 | if (sel >= 0) { |
76 | write_unlock_bh(&ip6_ra_lock); |
77 | kfree(objp: new_ra); |
78 | return -EADDRINUSE; |
79 | } |
80 | |
81 | *rap = ra->next; |
82 | write_unlock_bh(&ip6_ra_lock); |
83 | |
84 | sock_put(sk); |
85 | kfree(objp: ra); |
86 | return 0; |
87 | } |
88 | } |
89 | if (!new_ra) { |
90 | write_unlock_bh(&ip6_ra_lock); |
91 | return -ENOBUFS; |
92 | } |
93 | new_ra->sk = sk; |
94 | new_ra->sel = sel; |
95 | new_ra->next = ra; |
96 | *rap = new_ra; |
97 | sock_hold(sk); |
98 | write_unlock_bh(&ip6_ra_lock); |
99 | return 0; |
100 | } |
101 | |
102 | struct ipv6_txoptions *ipv6_update_options(struct sock *sk, |
103 | struct ipv6_txoptions *opt) |
104 | { |
105 | if (inet_test_bit(IS_ICSK, sk)) { |
106 | if (opt && |
107 | !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && |
108 | inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) { |
109 | struct inet_connection_sock *icsk = inet_csk(sk); |
110 | icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; |
111 | icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); |
112 | } |
113 | } |
114 | opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt, |
115 | opt); |
116 | sk_dst_reset(sk); |
117 | |
118 | return opt; |
119 | } |
120 | |
121 | static bool setsockopt_needs_rtnl(int optname) |
122 | { |
123 | switch (optname) { |
124 | case IPV6_ADDRFORM: |
125 | case IPV6_ADD_MEMBERSHIP: |
126 | case IPV6_DROP_MEMBERSHIP: |
127 | case IPV6_JOIN_ANYCAST: |
128 | case IPV6_LEAVE_ANYCAST: |
129 | case MCAST_JOIN_GROUP: |
130 | case MCAST_LEAVE_GROUP: |
131 | case MCAST_JOIN_SOURCE_GROUP: |
132 | case MCAST_LEAVE_SOURCE_GROUP: |
133 | case MCAST_BLOCK_SOURCE: |
134 | case MCAST_UNBLOCK_SOURCE: |
135 | case MCAST_MSFILTER: |
136 | return true; |
137 | } |
138 | return false; |
139 | } |
140 | |
141 | static int copy_group_source_from_sockptr(struct group_source_req *greqs, |
142 | sockptr_t optval, int optlen) |
143 | { |
144 | if (in_compat_syscall()) { |
145 | struct compat_group_source_req gr32; |
146 | |
147 | if (optlen < sizeof(gr32)) |
148 | return -EINVAL; |
149 | if (copy_from_sockptr(dst: &gr32, src: optval, size: sizeof(gr32))) |
150 | return -EFAULT; |
151 | greqs->gsr_interface = gr32.gsr_interface; |
152 | greqs->gsr_group = gr32.gsr_group; |
153 | greqs->gsr_source = gr32.gsr_source; |
154 | } else { |
155 | if (optlen < sizeof(*greqs)) |
156 | return -EINVAL; |
157 | if (copy_from_sockptr(dst: greqs, src: optval, size: sizeof(*greqs))) |
158 | return -EFAULT; |
159 | } |
160 | |
161 | return 0; |
162 | } |
163 | |
164 | static int do_ipv6_mcast_group_source(struct sock *sk, int optname, |
165 | sockptr_t optval, int optlen) |
166 | { |
167 | struct group_source_req greqs; |
168 | int omode, add; |
169 | int ret; |
170 | |
171 | ret = copy_group_source_from_sockptr(greqs: &greqs, optval, optlen); |
172 | if (ret) |
173 | return ret; |
174 | |
175 | if (greqs.gsr_group.ss_family != AF_INET6 || |
176 | greqs.gsr_source.ss_family != AF_INET6) |
177 | return -EADDRNOTAVAIL; |
178 | |
179 | if (optname == MCAST_BLOCK_SOURCE) { |
180 | omode = MCAST_EXCLUDE; |
181 | add = 1; |
182 | } else if (optname == MCAST_UNBLOCK_SOURCE) { |
183 | omode = MCAST_EXCLUDE; |
184 | add = 0; |
185 | } else if (optname == MCAST_JOIN_SOURCE_GROUP) { |
186 | struct sockaddr_in6 *psin6; |
187 | int retv; |
188 | |
189 | psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; |
190 | retv = ipv6_sock_mc_join_ssm(sk, ifindex: greqs.gsr_interface, |
191 | addr: &psin6->sin6_addr, |
192 | MCAST_INCLUDE); |
193 | /* prior join w/ different source is ok */ |
194 | if (retv && retv != -EADDRINUSE) |
195 | return retv; |
196 | omode = MCAST_INCLUDE; |
197 | add = 1; |
198 | } else /* MCAST_LEAVE_SOURCE_GROUP */ { |
199 | omode = MCAST_INCLUDE; |
200 | add = 0; |
201 | } |
202 | return ip6_mc_source(add, omode, sk, pgsr: &greqs); |
203 | } |
204 | |
205 | static int ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval, |
206 | int optlen) |
207 | { |
208 | struct group_filter *gsf; |
209 | int ret; |
210 | |
211 | if (optlen < GROUP_FILTER_SIZE(0)) |
212 | return -EINVAL; |
213 | if (optlen > READ_ONCE(sysctl_optmem_max)) |
214 | return -ENOBUFS; |
215 | |
216 | gsf = memdup_sockptr(src: optval, len: optlen); |
217 | if (IS_ERR(ptr: gsf)) |
218 | return PTR_ERR(ptr: gsf); |
219 | |
220 | /* numsrc >= (4G-140)/128 overflow in 32 bits */ |
221 | ret = -ENOBUFS; |
222 | if (gsf->gf_numsrc >= 0x1ffffffU || |
223 | gsf->gf_numsrc > sysctl_mld_max_msf) |
224 | goto out_free_gsf; |
225 | |
226 | ret = -EINVAL; |
227 | if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) |
228 | goto out_free_gsf; |
229 | |
230 | ret = ip6_mc_msfilter(sk, gsf, list: gsf->gf_slist_flex); |
231 | out_free_gsf: |
232 | kfree(objp: gsf); |
233 | return ret; |
234 | } |
235 | |
236 | static int compat_ipv6_set_mcast_msfilter(struct sock *sk, sockptr_t optval, |
237 | int optlen) |
238 | { |
239 | const int size0 = offsetof(struct compat_group_filter, gf_slist_flex); |
240 | struct compat_group_filter *gf32; |
241 | void *p; |
242 | int ret; |
243 | int n; |
244 | |
245 | if (optlen < size0) |
246 | return -EINVAL; |
247 | if (optlen > READ_ONCE(sysctl_optmem_max) - 4) |
248 | return -ENOBUFS; |
249 | |
250 | p = kmalloc(size: optlen + 4, GFP_KERNEL); |
251 | if (!p) |
252 | return -ENOMEM; |
253 | |
254 | gf32 = p + 4; /* we want ->gf_group and ->gf_slist_flex aligned */ |
255 | ret = -EFAULT; |
256 | if (copy_from_sockptr(dst: gf32, src: optval, size: optlen)) |
257 | goto out_free_p; |
258 | |
259 | /* numsrc >= (4G-140)/128 overflow in 32 bits */ |
260 | ret = -ENOBUFS; |
261 | n = gf32->gf_numsrc; |
262 | if (n >= 0x1ffffffU || n > sysctl_mld_max_msf) |
263 | goto out_free_p; |
264 | |
265 | ret = -EINVAL; |
266 | if (offsetof(struct compat_group_filter, gf_slist_flex[n]) > optlen) |
267 | goto out_free_p; |
268 | |
269 | ret = ip6_mc_msfilter(sk, gsf: &(struct group_filter){ |
270 | .gf_interface = gf32->gf_interface, |
271 | .gf_group = gf32->gf_group, |
272 | .gf_fmode = gf32->gf_fmode, |
273 | .gf_numsrc = gf32->gf_numsrc}, list: gf32->gf_slist_flex); |
274 | |
275 | out_free_p: |
276 | kfree(objp: p); |
277 | return ret; |
278 | } |
279 | |
280 | static int ipv6_mcast_join_leave(struct sock *sk, int optname, |
281 | sockptr_t optval, int optlen) |
282 | { |
283 | struct sockaddr_in6 *psin6; |
284 | struct group_req greq; |
285 | |
286 | if (optlen < sizeof(greq)) |
287 | return -EINVAL; |
288 | if (copy_from_sockptr(dst: &greq, src: optval, size: sizeof(greq))) |
289 | return -EFAULT; |
290 | |
291 | if (greq.gr_group.ss_family != AF_INET6) |
292 | return -EADDRNOTAVAIL; |
293 | psin6 = (struct sockaddr_in6 *)&greq.gr_group; |
294 | if (optname == MCAST_JOIN_GROUP) |
295 | return ipv6_sock_mc_join(sk, ifindex: greq.gr_interface, |
296 | addr: &psin6->sin6_addr); |
297 | return ipv6_sock_mc_drop(sk, ifindex: greq.gr_interface, addr: &psin6->sin6_addr); |
298 | } |
299 | |
300 | static int compat_ipv6_mcast_join_leave(struct sock *sk, int optname, |
301 | sockptr_t optval, int optlen) |
302 | { |
303 | struct compat_group_req gr32; |
304 | struct sockaddr_in6 *psin6; |
305 | |
306 | if (optlen < sizeof(gr32)) |
307 | return -EINVAL; |
308 | if (copy_from_sockptr(dst: &gr32, src: optval, size: sizeof(gr32))) |
309 | return -EFAULT; |
310 | |
311 | if (gr32.gr_group.ss_family != AF_INET6) |
312 | return -EADDRNOTAVAIL; |
313 | psin6 = (struct sockaddr_in6 *)&gr32.gr_group; |
314 | if (optname == MCAST_JOIN_GROUP) |
315 | return ipv6_sock_mc_join(sk, ifindex: gr32.gr_interface, |
316 | addr: &psin6->sin6_addr); |
317 | return ipv6_sock_mc_drop(sk, ifindex: gr32.gr_interface, addr: &psin6->sin6_addr); |
318 | } |
319 | |
320 | static int ipv6_set_opt_hdr(struct sock *sk, int optname, sockptr_t optval, |
321 | int optlen) |
322 | { |
323 | struct ipv6_pinfo *np = inet6_sk(sk: sk); |
324 | struct ipv6_opt_hdr *new = NULL; |
325 | struct net *net = sock_net(sk); |
326 | struct ipv6_txoptions *opt; |
327 | int err; |
328 | |
329 | /* hop-by-hop / destination options are privileged option */ |
330 | if (optname != IPV6_RTHDR && !sockopt_ns_capable(ns: net->user_ns, CAP_NET_RAW)) |
331 | return -EPERM; |
332 | |
333 | /* remove any sticky options header with a zero option |
334 | * length, per RFC3542. |
335 | */ |
336 | if (optlen > 0) { |
337 | if (sockptr_is_null(sockptr: optval)) |
338 | return -EINVAL; |
339 | if (optlen < sizeof(struct ipv6_opt_hdr) || |
340 | optlen & 0x7 || |
341 | optlen > 8 * 255) |
342 | return -EINVAL; |
343 | |
344 | new = memdup_sockptr(src: optval, len: optlen); |
345 | if (IS_ERR(ptr: new)) |
346 | return PTR_ERR(ptr: new); |
347 | if (unlikely(ipv6_optlen(new) > optlen)) { |
348 | kfree(objp: new); |
349 | return -EINVAL; |
350 | } |
351 | } |
352 | |
353 | opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk)); |
354 | opt = ipv6_renew_options(sk, opt, newtype: optname, newopt: new); |
355 | kfree(objp: new); |
356 | if (IS_ERR(ptr: opt)) |
357 | return PTR_ERR(ptr: opt); |
358 | |
359 | /* routing header option needs extra check */ |
360 | err = -EINVAL; |
361 | if (optname == IPV6_RTHDR && opt && opt->srcrt) { |
362 | struct ipv6_rt_hdr *rthdr = opt->srcrt; |
363 | switch (rthdr->type) { |
364 | #if IS_ENABLED(CONFIG_IPV6_MIP6) |
365 | case IPV6_SRCRT_TYPE_2: |
366 | if (rthdr->hdrlen != 2 || rthdr->segments_left != 1) |
367 | goto sticky_done; |
368 | break; |
369 | #endif |
370 | case IPV6_SRCRT_TYPE_4: |
371 | { |
372 | struct ipv6_sr_hdr *srh = |
373 | (struct ipv6_sr_hdr *)opt->srcrt; |
374 | |
375 | if (!seg6_validate_srh(srh, len: optlen, reduced: false)) |
376 | goto sticky_done; |
377 | break; |
378 | } |
379 | default: |
380 | goto sticky_done; |
381 | } |
382 | } |
383 | |
384 | err = 0; |
385 | opt = ipv6_update_options(sk, opt); |
386 | sticky_done: |
387 | if (opt) { |
388 | atomic_sub(i: opt->tot_len, v: &sk->sk_omem_alloc); |
389 | txopt_put(opt); |
390 | } |
391 | return err; |
392 | } |
393 | |
394 | int do_ipv6_setsockopt(struct sock *sk, int level, int optname, |
395 | sockptr_t optval, unsigned int optlen) |
396 | { |
397 | struct ipv6_pinfo *np = inet6_sk(sk: sk); |
398 | struct net *net = sock_net(sk); |
399 | int val, valbool; |
400 | int retv = -ENOPROTOOPT; |
401 | bool needs_rtnl = setsockopt_needs_rtnl(optname); |
402 | |
403 | if (sockptr_is_null(sockptr: optval)) |
404 | val = 0; |
405 | else { |
406 | if (optlen >= sizeof(int)) { |
407 | if (copy_from_sockptr(dst: &val, src: optval, size: sizeof(val))) |
408 | return -EFAULT; |
409 | } else |
410 | val = 0; |
411 | } |
412 | |
413 | valbool = (val != 0); |
414 | |
415 | if (ip6_mroute_opt(opt: optname)) |
416 | return ip6_mroute_setsockopt(sk, optname, optval, optlen); |
417 | |
418 | /* Handle options that can be set without locking the socket. */ |
419 | switch (optname) { |
420 | case IPV6_UNICAST_HOPS: |
421 | if (optlen < sizeof(int)) |
422 | return -EINVAL; |
423 | if (val > 255 || val < -1) |
424 | return -EINVAL; |
425 | WRITE_ONCE(np->hop_limit, val); |
426 | return 0; |
427 | case IPV6_MULTICAST_LOOP: |
428 | if (optlen < sizeof(int)) |
429 | return -EINVAL; |
430 | if (val != valbool) |
431 | return -EINVAL; |
432 | inet6_assign_bit(MC6_LOOP, sk, valbool); |
433 | return 0; |
434 | case IPV6_MULTICAST_HOPS: |
435 | if (sk->sk_type == SOCK_STREAM) |
436 | return retv; |
437 | if (optlen < sizeof(int)) |
438 | return -EINVAL; |
439 | if (val > 255 || val < -1) |
440 | return -EINVAL; |
441 | WRITE_ONCE(np->mcast_hops, |
442 | val == -1 ? IPV6_DEFAULT_MCASTHOPS : val); |
443 | return 0; |
444 | case IPV6_MTU: |
445 | if (optlen < sizeof(int)) |
446 | return -EINVAL; |
447 | if (val && val < IPV6_MIN_MTU) |
448 | return -EINVAL; |
449 | WRITE_ONCE(np->frag_size, val); |
450 | return 0; |
451 | case IPV6_MINHOPCOUNT: |
452 | if (optlen < sizeof(int)) |
453 | return -EINVAL; |
454 | if (val < 0 || val > 255) |
455 | return -EINVAL; |
456 | |
457 | if (val) |
458 | static_branch_enable(&ip6_min_hopcount); |
459 | |
460 | /* tcp_v6_err() and tcp_v6_rcv() might read min_hopcount |
461 | * while we are changing it. |
462 | */ |
463 | WRITE_ONCE(np->min_hopcount, val); |
464 | return 0; |
465 | case IPV6_RECVERR_RFC4884: |
466 | if (optlen < sizeof(int)) |
467 | return -EINVAL; |
468 | if (val < 0 || val > 1) |
469 | return -EINVAL; |
470 | inet6_assign_bit(RECVERR6_RFC4884, sk, valbool); |
471 | return 0; |
472 | case IPV6_MULTICAST_ALL: |
473 | if (optlen < sizeof(int)) |
474 | return -EINVAL; |
475 | inet6_assign_bit(MC6_ALL, sk, valbool); |
476 | return 0; |
477 | case IPV6_AUTOFLOWLABEL: |
478 | inet6_assign_bit(AUTOFLOWLABEL, sk, valbool); |
479 | inet6_set_bit(AUTOFLOWLABEL_SET, sk); |
480 | return 0; |
481 | case IPV6_DONTFRAG: |
482 | inet6_assign_bit(DONTFRAG, sk, valbool); |
483 | return 0; |
484 | case IPV6_RECVERR: |
485 | if (optlen < sizeof(int)) |
486 | return -EINVAL; |
487 | inet6_assign_bit(RECVERR6, sk, valbool); |
488 | if (!val) |
489 | skb_errqueue_purge(list: &sk->sk_error_queue); |
490 | return 0; |
491 | case IPV6_ROUTER_ALERT_ISOLATE: |
492 | if (optlen < sizeof(int)) |
493 | return -EINVAL; |
494 | inet6_assign_bit(RTALERT_ISOLATE, sk, valbool); |
495 | return 0; |
496 | case IPV6_MTU_DISCOVER: |
497 | if (optlen < sizeof(int)) |
498 | return -EINVAL; |
499 | if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT) |
500 | return -EINVAL; |
501 | WRITE_ONCE(np->pmtudisc, val); |
502 | return 0; |
503 | case IPV6_FLOWINFO_SEND: |
504 | if (optlen < sizeof(int)) |
505 | return -EINVAL; |
506 | inet6_assign_bit(SNDFLOW, sk, valbool); |
507 | return 0; |
508 | case IPV6_ADDR_PREFERENCES: |
509 | if (optlen < sizeof(int)) |
510 | return -EINVAL; |
511 | return ip6_sock_set_addr_preferences(sk, val); |
512 | } |
513 | if (needs_rtnl) |
514 | rtnl_lock(); |
515 | sockopt_lock_sock(sk); |
516 | |
517 | /* Another thread has converted the socket into IPv4 with |
518 | * IPV6_ADDRFORM concurrently. |
519 | */ |
520 | if (unlikely(sk->sk_family != AF_INET6)) |
521 | goto unlock; |
522 | |
523 | switch (optname) { |
524 | |
525 | case IPV6_ADDRFORM: |
526 | if (optlen < sizeof(int)) |
527 | goto e_inval; |
528 | if (val == PF_INET) { |
529 | if (sk->sk_type == SOCK_RAW) |
530 | break; |
531 | |
532 | if (sk->sk_protocol == IPPROTO_UDP || |
533 | sk->sk_protocol == IPPROTO_UDPLITE) { |
534 | struct udp_sock *up = udp_sk(sk); |
535 | if (up->pending == AF_INET6) { |
536 | retv = -EBUSY; |
537 | break; |
538 | } |
539 | } else if (sk->sk_protocol == IPPROTO_TCP) { |
540 | if (sk->sk_prot != &tcpv6_prot) { |
541 | retv = -EBUSY; |
542 | break; |
543 | } |
544 | } else { |
545 | break; |
546 | } |
547 | |
548 | if (sk->sk_state != TCP_ESTABLISHED) { |
549 | retv = -ENOTCONN; |
550 | break; |
551 | } |
552 | |
553 | if (ipv6_only_sock(sk) || |
554 | !ipv6_addr_v4mapped(a: &sk->sk_v6_daddr)) { |
555 | retv = -EADDRNOTAVAIL; |
556 | break; |
557 | } |
558 | |
559 | __ipv6_sock_mc_close(sk); |
560 | __ipv6_sock_ac_close(sk); |
561 | |
562 | if (sk->sk_protocol == IPPROTO_TCP) { |
563 | struct inet_connection_sock *icsk = inet_csk(sk); |
564 | |
565 | sock_prot_inuse_add(net, prot: sk->sk_prot, val: -1); |
566 | sock_prot_inuse_add(net, prot: &tcp_prot, val: 1); |
567 | |
568 | /* Paired with READ_ONCE(sk->sk_prot) in inet6_stream_ops */ |
569 | WRITE_ONCE(sk->sk_prot, &tcp_prot); |
570 | /* Paired with READ_ONCE() in tcp_(get|set)sockopt() */ |
571 | WRITE_ONCE(icsk->icsk_af_ops, &ipv4_specific); |
572 | WRITE_ONCE(sk->sk_socket->ops, &inet_stream_ops); |
573 | WRITE_ONCE(sk->sk_family, PF_INET); |
574 | tcp_sync_mss(sk, pmtu: icsk->icsk_pmtu_cookie); |
575 | } else { |
576 | struct proto *prot = &udp_prot; |
577 | |
578 | if (sk->sk_protocol == IPPROTO_UDPLITE) |
579 | prot = &udplite_prot; |
580 | |
581 | sock_prot_inuse_add(net, prot: sk->sk_prot, val: -1); |
582 | sock_prot_inuse_add(net, prot, val: 1); |
583 | |
584 | /* Paired with READ_ONCE(sk->sk_prot) in inet6_dgram_ops */ |
585 | WRITE_ONCE(sk->sk_prot, prot); |
586 | WRITE_ONCE(sk->sk_socket->ops, &inet_dgram_ops); |
587 | WRITE_ONCE(sk->sk_family, PF_INET); |
588 | } |
589 | |
590 | /* Disable all options not to allocate memory anymore, |
591 | * but there is still a race. See the lockless path |
592 | * in udpv6_sendmsg() and ipv6_local_rxpmtu(). |
593 | */ |
594 | np->rxopt.all = 0; |
595 | |
596 | inet6_cleanup_sock(sk); |
597 | |
598 | module_put(THIS_MODULE); |
599 | retv = 0; |
600 | break; |
601 | } |
602 | goto e_inval; |
603 | |
604 | case IPV6_V6ONLY: |
605 | if (optlen < sizeof(int) || |
606 | inet_sk(sk)->inet_num) |
607 | goto e_inval; |
608 | sk->sk_ipv6only = valbool; |
609 | retv = 0; |
610 | break; |
611 | |
612 | case IPV6_RECVPKTINFO: |
613 | if (optlen < sizeof(int)) |
614 | goto e_inval; |
615 | np->rxopt.bits.rxinfo = valbool; |
616 | retv = 0; |
617 | break; |
618 | |
619 | case IPV6_2292PKTINFO: |
620 | if (optlen < sizeof(int)) |
621 | goto e_inval; |
622 | np->rxopt.bits.rxoinfo = valbool; |
623 | retv = 0; |
624 | break; |
625 | |
626 | case IPV6_RECVHOPLIMIT: |
627 | if (optlen < sizeof(int)) |
628 | goto e_inval; |
629 | np->rxopt.bits.rxhlim = valbool; |
630 | retv = 0; |
631 | break; |
632 | |
633 | case IPV6_2292HOPLIMIT: |
634 | if (optlen < sizeof(int)) |
635 | goto e_inval; |
636 | np->rxopt.bits.rxohlim = valbool; |
637 | retv = 0; |
638 | break; |
639 | |
640 | case IPV6_RECVRTHDR: |
641 | if (optlen < sizeof(int)) |
642 | goto e_inval; |
643 | np->rxopt.bits.srcrt = valbool; |
644 | retv = 0; |
645 | break; |
646 | |
647 | case IPV6_2292RTHDR: |
648 | if (optlen < sizeof(int)) |
649 | goto e_inval; |
650 | np->rxopt.bits.osrcrt = valbool; |
651 | retv = 0; |
652 | break; |
653 | |
654 | case IPV6_RECVHOPOPTS: |
655 | if (optlen < sizeof(int)) |
656 | goto e_inval; |
657 | np->rxopt.bits.hopopts = valbool; |
658 | retv = 0; |
659 | break; |
660 | |
661 | case IPV6_2292HOPOPTS: |
662 | if (optlen < sizeof(int)) |
663 | goto e_inval; |
664 | np->rxopt.bits.ohopopts = valbool; |
665 | retv = 0; |
666 | break; |
667 | |
668 | case IPV6_RECVDSTOPTS: |
669 | if (optlen < sizeof(int)) |
670 | goto e_inval; |
671 | np->rxopt.bits.dstopts = valbool; |
672 | retv = 0; |
673 | break; |
674 | |
675 | case IPV6_2292DSTOPTS: |
676 | if (optlen < sizeof(int)) |
677 | goto e_inval; |
678 | np->rxopt.bits.odstopts = valbool; |
679 | retv = 0; |
680 | break; |
681 | |
682 | case IPV6_TCLASS: |
683 | if (optlen < sizeof(int)) |
684 | goto e_inval; |
685 | if (val < -1 || val > 0xff) |
686 | goto e_inval; |
687 | /* RFC 3542, 6.5: default traffic class of 0x0 */ |
688 | if (val == -1) |
689 | val = 0; |
690 | if (sk->sk_type == SOCK_STREAM) { |
691 | val &= ~INET_ECN_MASK; |
692 | val |= np->tclass & INET_ECN_MASK; |
693 | } |
694 | if (np->tclass != val) { |
695 | np->tclass = val; |
696 | sk_dst_reset(sk); |
697 | } |
698 | retv = 0; |
699 | break; |
700 | |
701 | case IPV6_RECVTCLASS: |
702 | if (optlen < sizeof(int)) |
703 | goto e_inval; |
704 | np->rxopt.bits.rxtclass = valbool; |
705 | retv = 0; |
706 | break; |
707 | |
708 | case IPV6_FLOWINFO: |
709 | if (optlen < sizeof(int)) |
710 | goto e_inval; |
711 | np->rxopt.bits.rxflow = valbool; |
712 | retv = 0; |
713 | break; |
714 | |
715 | case IPV6_RECVPATHMTU: |
716 | if (optlen < sizeof(int)) |
717 | goto e_inval; |
718 | np->rxopt.bits.rxpmtu = valbool; |
719 | retv = 0; |
720 | break; |
721 | |
722 | case IPV6_TRANSPARENT: |
723 | if (valbool && !sockopt_ns_capable(ns: net->user_ns, CAP_NET_RAW) && |
724 | !sockopt_ns_capable(ns: net->user_ns, CAP_NET_ADMIN)) { |
725 | retv = -EPERM; |
726 | break; |
727 | } |
728 | if (optlen < sizeof(int)) |
729 | goto e_inval; |
730 | /* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */ |
731 | inet_assign_bit(TRANSPARENT, sk, valbool); |
732 | retv = 0; |
733 | break; |
734 | |
735 | case IPV6_FREEBIND: |
736 | if (optlen < sizeof(int)) |
737 | goto e_inval; |
738 | /* we also don't have a separate freebind bit for IPV6 */ |
739 | inet_assign_bit(FREEBIND, sk, valbool); |
740 | retv = 0; |
741 | break; |
742 | |
743 | case IPV6_RECVORIGDSTADDR: |
744 | if (optlen < sizeof(int)) |
745 | goto e_inval; |
746 | np->rxopt.bits.rxorigdstaddr = valbool; |
747 | retv = 0; |
748 | break; |
749 | |
750 | case IPV6_HOPOPTS: |
751 | case IPV6_RTHDRDSTOPTS: |
752 | case IPV6_RTHDR: |
753 | case IPV6_DSTOPTS: |
754 | retv = ipv6_set_opt_hdr(sk, optname, optval, optlen); |
755 | break; |
756 | |
757 | case IPV6_PKTINFO: |
758 | { |
759 | struct in6_pktinfo pkt; |
760 | |
761 | if (optlen == 0) |
762 | goto e_inval; |
763 | else if (optlen < sizeof(struct in6_pktinfo) || |
764 | sockptr_is_null(sockptr: optval)) |
765 | goto e_inval; |
766 | |
767 | if (copy_from_sockptr(dst: &pkt, src: optval, size: sizeof(pkt))) { |
768 | retv = -EFAULT; |
769 | break; |
770 | } |
771 | if (!sk_dev_equal_l3scope(sk, dif: pkt.ipi6_ifindex)) |
772 | goto e_inval; |
773 | |
774 | np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex; |
775 | np->sticky_pktinfo.ipi6_addr = pkt.ipi6_addr; |
776 | retv = 0; |
777 | break; |
778 | } |
779 | |
780 | case IPV6_2292PKTOPTIONS: |
781 | { |
782 | struct ipv6_txoptions *opt = NULL; |
783 | struct msghdr msg; |
784 | struct flowi6 fl6; |
785 | struct ipcm6_cookie ipc6; |
786 | |
787 | memset(&fl6, 0, sizeof(fl6)); |
788 | fl6.flowi6_oif = sk->sk_bound_dev_if; |
789 | fl6.flowi6_mark = sk->sk_mark; |
790 | |
791 | if (optlen == 0) |
792 | goto update; |
793 | |
794 | /* 1K is probably excessive |
795 | * 1K is surely not enough, 2K per standard header is 16K. |
796 | */ |
797 | retv = -EINVAL; |
798 | if (optlen > 64*1024) |
799 | break; |
800 | |
801 | opt = sock_kmalloc(sk, size: sizeof(*opt) + optlen, GFP_KERNEL); |
802 | retv = -ENOBUFS; |
803 | if (!opt) |
804 | break; |
805 | |
806 | memset(opt, 0, sizeof(*opt)); |
807 | refcount_set(r: &opt->refcnt, n: 1); |
808 | opt->tot_len = sizeof(*opt) + optlen; |
809 | retv = -EFAULT; |
810 | if (copy_from_sockptr(dst: opt + 1, src: optval, size: optlen)) |
811 | goto done; |
812 | |
813 | msg.msg_controllen = optlen; |
814 | msg.msg_control_is_user = false; |
815 | msg.msg_control = (void *)(opt+1); |
816 | ipc6.opt = opt; |
817 | |
818 | retv = ip6_datagram_send_ctl(net, sk, msg: &msg, fl6: &fl6, ipc6: &ipc6); |
819 | if (retv) |
820 | goto done; |
821 | update: |
822 | retv = 0; |
823 | opt = ipv6_update_options(sk, opt); |
824 | done: |
825 | if (opt) { |
826 | atomic_sub(i: opt->tot_len, v: &sk->sk_omem_alloc); |
827 | txopt_put(opt); |
828 | } |
829 | break; |
830 | } |
831 | |
832 | |
833 | case IPV6_UNICAST_IF: |
834 | { |
835 | struct net_device *dev = NULL; |
836 | int ifindex; |
837 | |
838 | if (optlen != sizeof(int)) |
839 | goto e_inval; |
840 | |
841 | ifindex = (__force int)ntohl((__force __be32)val); |
842 | if (ifindex == 0) { |
843 | np->ucast_oif = 0; |
844 | retv = 0; |
845 | break; |
846 | } |
847 | |
848 | dev = dev_get_by_index(net, ifindex); |
849 | retv = -EADDRNOTAVAIL; |
850 | if (!dev) |
851 | break; |
852 | dev_put(dev); |
853 | |
854 | retv = -EINVAL; |
855 | if (sk->sk_bound_dev_if) |
856 | break; |
857 | |
858 | np->ucast_oif = ifindex; |
859 | retv = 0; |
860 | break; |
861 | } |
862 | |
863 | case IPV6_MULTICAST_IF: |
864 | if (sk->sk_type == SOCK_STREAM) |
865 | break; |
866 | if (optlen < sizeof(int)) |
867 | goto e_inval; |
868 | |
869 | if (val) { |
870 | struct net_device *dev; |
871 | int midx; |
872 | |
873 | rcu_read_lock(); |
874 | |
875 | dev = dev_get_by_index_rcu(net, ifindex: val); |
876 | if (!dev) { |
877 | rcu_read_unlock(); |
878 | retv = -ENODEV; |
879 | break; |
880 | } |
881 | midx = l3mdev_master_ifindex_rcu(dev); |
882 | |
883 | rcu_read_unlock(); |
884 | |
885 | if (sk->sk_bound_dev_if && |
886 | sk->sk_bound_dev_if != val && |
887 | (!midx || midx != sk->sk_bound_dev_if)) |
888 | goto e_inval; |
889 | } |
890 | np->mcast_oif = val; |
891 | retv = 0; |
892 | break; |
893 | case IPV6_ADD_MEMBERSHIP: |
894 | case IPV6_DROP_MEMBERSHIP: |
895 | { |
896 | struct ipv6_mreq mreq; |
897 | |
898 | if (optlen < sizeof(struct ipv6_mreq)) |
899 | goto e_inval; |
900 | |
901 | retv = -EPROTO; |
902 | if (inet_test_bit(IS_ICSK, sk)) |
903 | break; |
904 | |
905 | retv = -EFAULT; |
906 | if (copy_from_sockptr(dst: &mreq, src: optval, size: sizeof(struct ipv6_mreq))) |
907 | break; |
908 | |
909 | if (optname == IPV6_ADD_MEMBERSHIP) |
910 | retv = ipv6_sock_mc_join(sk, ifindex: mreq.ipv6mr_ifindex, addr: &mreq.ipv6mr_multiaddr); |
911 | else |
912 | retv = ipv6_sock_mc_drop(sk, ifindex: mreq.ipv6mr_ifindex, addr: &mreq.ipv6mr_multiaddr); |
913 | break; |
914 | } |
915 | case IPV6_JOIN_ANYCAST: |
916 | case IPV6_LEAVE_ANYCAST: |
917 | { |
918 | struct ipv6_mreq mreq; |
919 | |
920 | if (optlen < sizeof(struct ipv6_mreq)) |
921 | goto e_inval; |
922 | |
923 | retv = -EFAULT; |
924 | if (copy_from_sockptr(dst: &mreq, src: optval, size: sizeof(struct ipv6_mreq))) |
925 | break; |
926 | |
927 | if (optname == IPV6_JOIN_ANYCAST) |
928 | retv = ipv6_sock_ac_join(sk, ifindex: mreq.ipv6mr_ifindex, addr: &mreq.ipv6mr_acaddr); |
929 | else |
930 | retv = ipv6_sock_ac_drop(sk, ifindex: mreq.ipv6mr_ifindex, addr: &mreq.ipv6mr_acaddr); |
931 | break; |
932 | } |
933 | case MCAST_JOIN_GROUP: |
934 | case MCAST_LEAVE_GROUP: |
935 | if (in_compat_syscall()) |
936 | retv = compat_ipv6_mcast_join_leave(sk, optname, optval, |
937 | optlen); |
938 | else |
939 | retv = ipv6_mcast_join_leave(sk, optname, optval, |
940 | optlen); |
941 | break; |
942 | case MCAST_JOIN_SOURCE_GROUP: |
943 | case MCAST_LEAVE_SOURCE_GROUP: |
944 | case MCAST_BLOCK_SOURCE: |
945 | case MCAST_UNBLOCK_SOURCE: |
946 | retv = do_ipv6_mcast_group_source(sk, optname, optval, optlen); |
947 | break; |
948 | case MCAST_MSFILTER: |
949 | if (in_compat_syscall()) |
950 | retv = compat_ipv6_set_mcast_msfilter(sk, optval, |
951 | optlen); |
952 | else |
953 | retv = ipv6_set_mcast_msfilter(sk, optval, optlen); |
954 | break; |
955 | case IPV6_ROUTER_ALERT: |
956 | if (optlen < sizeof(int)) |
957 | goto e_inval; |
958 | retv = ip6_ra_control(sk, sel: val); |
959 | break; |
960 | case IPV6_FLOWLABEL_MGR: |
961 | retv = ipv6_flowlabel_opt(sk, optval, optlen); |
962 | break; |
963 | case IPV6_IPSEC_POLICY: |
964 | case IPV6_XFRM_POLICY: |
965 | retv = -EPERM; |
966 | if (!sockopt_ns_capable(ns: net->user_ns, CAP_NET_ADMIN)) |
967 | break; |
968 | retv = xfrm_user_policy(sk, optname, optval, optlen); |
969 | break; |
970 | |
971 | case IPV6_RECVFRAGSIZE: |
972 | np->rxopt.bits.recvfragsize = valbool; |
973 | retv = 0; |
974 | break; |
975 | } |
976 | |
977 | unlock: |
978 | sockopt_release_sock(sk); |
979 | if (needs_rtnl) |
980 | rtnl_unlock(); |
981 | |
982 | return retv; |
983 | |
984 | e_inval: |
985 | retv = -EINVAL; |
986 | goto unlock; |
987 | } |
988 | |
989 | int ipv6_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, |
990 | unsigned int optlen) |
991 | { |
992 | int err; |
993 | |
994 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) |
995 | return udp_prot.setsockopt(sk, level, optname, optval, optlen); |
996 | |
997 | if (level != SOL_IPV6) |
998 | return -ENOPROTOOPT; |
999 | |
1000 | err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); |
1001 | #ifdef CONFIG_NETFILTER |
1002 | /* we need to exclude all possible ENOPROTOOPTs except default case */ |
1003 | if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && |
1004 | optname != IPV6_XFRM_POLICY) |
1005 | err = nf_setsockopt(sk, PF_INET6, optval: optname, opt: optval, len: optlen); |
1006 | #endif |
1007 | return err; |
1008 | } |
1009 | EXPORT_SYMBOL(ipv6_setsockopt); |
1010 | |
1011 | static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt, |
1012 | int optname, sockptr_t optval, int len) |
1013 | { |
1014 | struct ipv6_opt_hdr *hdr; |
1015 | |
1016 | if (!opt) |
1017 | return 0; |
1018 | |
1019 | switch (optname) { |
1020 | case IPV6_HOPOPTS: |
1021 | hdr = opt->hopopt; |
1022 | break; |
1023 | case IPV6_RTHDRDSTOPTS: |
1024 | hdr = opt->dst0opt; |
1025 | break; |
1026 | case IPV6_RTHDR: |
1027 | hdr = (struct ipv6_opt_hdr *)opt->srcrt; |
1028 | break; |
1029 | case IPV6_DSTOPTS: |
1030 | hdr = opt->dst1opt; |
1031 | break; |
1032 | default: |
1033 | return -EINVAL; /* should not happen */ |
1034 | } |
1035 | |
1036 | if (!hdr) |
1037 | return 0; |
1038 | |
1039 | len = min_t(unsigned int, len, ipv6_optlen(hdr)); |
1040 | if (copy_to_sockptr(dst: optval, src: hdr, size: len)) |
1041 | return -EFAULT; |
1042 | return len; |
1043 | } |
1044 | |
1045 | static int ipv6_get_msfilter(struct sock *sk, sockptr_t optval, |
1046 | sockptr_t optlen, int len) |
1047 | { |
1048 | const int size0 = offsetof(struct group_filter, gf_slist_flex); |
1049 | struct group_filter gsf; |
1050 | int num; |
1051 | int err; |
1052 | |
1053 | if (len < size0) |
1054 | return -EINVAL; |
1055 | if (copy_from_sockptr(dst: &gsf, src: optval, size: size0)) |
1056 | return -EFAULT; |
1057 | if (gsf.gf_group.ss_family != AF_INET6) |
1058 | return -EADDRNOTAVAIL; |
1059 | num = gsf.gf_numsrc; |
1060 | sockopt_lock_sock(sk); |
1061 | err = ip6_mc_msfget(sk, gsf: &gsf, optval, ss_offset: size0); |
1062 | if (!err) { |
1063 | if (num > gsf.gf_numsrc) |
1064 | num = gsf.gf_numsrc; |
1065 | len = GROUP_FILTER_SIZE(num); |
1066 | if (copy_to_sockptr(dst: optlen, src: &len, size: sizeof(int)) || |
1067 | copy_to_sockptr(dst: optval, src: &gsf, size: size0)) |
1068 | err = -EFAULT; |
1069 | } |
1070 | sockopt_release_sock(sk); |
1071 | return err; |
1072 | } |
1073 | |
1074 | static int compat_ipv6_get_msfilter(struct sock *sk, sockptr_t optval, |
1075 | sockptr_t optlen, int len) |
1076 | { |
1077 | const int size0 = offsetof(struct compat_group_filter, gf_slist_flex); |
1078 | struct compat_group_filter gf32; |
1079 | struct group_filter gf; |
1080 | int err; |
1081 | int num; |
1082 | |
1083 | if (len < size0) |
1084 | return -EINVAL; |
1085 | |
1086 | if (copy_from_sockptr(dst: &gf32, src: optval, size: size0)) |
1087 | return -EFAULT; |
1088 | gf.gf_interface = gf32.gf_interface; |
1089 | gf.gf_fmode = gf32.gf_fmode; |
1090 | num = gf.gf_numsrc = gf32.gf_numsrc; |
1091 | gf.gf_group = gf32.gf_group; |
1092 | |
1093 | if (gf.gf_group.ss_family != AF_INET6) |
1094 | return -EADDRNOTAVAIL; |
1095 | |
1096 | sockopt_lock_sock(sk); |
1097 | err = ip6_mc_msfget(sk, gsf: &gf, optval, ss_offset: size0); |
1098 | sockopt_release_sock(sk); |
1099 | if (err) |
1100 | return err; |
1101 | if (num > gf.gf_numsrc) |
1102 | num = gf.gf_numsrc; |
1103 | len = GROUP_FILTER_SIZE(num) - (sizeof(gf)-sizeof(gf32)); |
1104 | if (copy_to_sockptr(dst: optlen, src: &len, size: sizeof(int)) || |
1105 | copy_to_sockptr_offset(dst: optval, offsetof(struct compat_group_filter, gf_fmode), |
1106 | src: &gf.gf_fmode, size: sizeof(gf32.gf_fmode)) || |
1107 | copy_to_sockptr_offset(dst: optval, offsetof(struct compat_group_filter, gf_numsrc), |
1108 | src: &gf.gf_numsrc, size: sizeof(gf32.gf_numsrc))) |
1109 | return -EFAULT; |
1110 | return 0; |
1111 | } |
1112 | |
1113 | int do_ipv6_getsockopt(struct sock *sk, int level, int optname, |
1114 | sockptr_t optval, sockptr_t optlen) |
1115 | { |
1116 | struct ipv6_pinfo *np = inet6_sk(sk: sk); |
1117 | int len; |
1118 | int val; |
1119 | |
1120 | if (ip6_mroute_opt(opt: optname)) |
1121 | return ip6_mroute_getsockopt(sk, optname, optval, optlen); |
1122 | |
1123 | if (copy_from_sockptr(dst: &len, src: optlen, size: sizeof(int))) |
1124 | return -EFAULT; |
1125 | switch (optname) { |
1126 | case IPV6_ADDRFORM: |
1127 | if (sk->sk_protocol != IPPROTO_UDP && |
1128 | sk->sk_protocol != IPPROTO_UDPLITE && |
1129 | sk->sk_protocol != IPPROTO_TCP) |
1130 | return -ENOPROTOOPT; |
1131 | if (sk->sk_state != TCP_ESTABLISHED) |
1132 | return -ENOTCONN; |
1133 | val = sk->sk_family; |
1134 | break; |
1135 | case MCAST_MSFILTER: |
1136 | if (in_compat_syscall()) |
1137 | return compat_ipv6_get_msfilter(sk, optval, optlen, len); |
1138 | return ipv6_get_msfilter(sk, optval, optlen, len); |
1139 | case IPV6_2292PKTOPTIONS: |
1140 | { |
1141 | struct msghdr msg; |
1142 | struct sk_buff *skb; |
1143 | |
1144 | if (sk->sk_type != SOCK_STREAM) |
1145 | return -ENOPROTOOPT; |
1146 | |
1147 | if (optval.is_kernel) { |
1148 | msg.msg_control_is_user = false; |
1149 | msg.msg_control = optval.kernel; |
1150 | } else { |
1151 | msg.msg_control_is_user = true; |
1152 | msg.msg_control_user = optval.user; |
1153 | } |
1154 | msg.msg_controllen = len; |
1155 | msg.msg_flags = 0; |
1156 | |
1157 | sockopt_lock_sock(sk); |
1158 | skb = np->pktoptions; |
1159 | if (skb) |
1160 | ip6_datagram_recv_ctl(sk, msg: &msg, skb); |
1161 | sockopt_release_sock(sk); |
1162 | if (!skb) { |
1163 | if (np->rxopt.bits.rxinfo) { |
1164 | struct in6_pktinfo src_info; |
1165 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : |
1166 | np->sticky_pktinfo.ipi6_ifindex; |
1167 | src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr; |
1168 | put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, len: sizeof(src_info), data: &src_info); |
1169 | } |
1170 | if (np->rxopt.bits.rxhlim) { |
1171 | int hlim = READ_ONCE(np->mcast_hops); |
1172 | |
1173 | put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, len: sizeof(hlim), data: &hlim); |
1174 | } |
1175 | if (np->rxopt.bits.rxtclass) { |
1176 | int tclass = (int)ip6_tclass(flowinfo: np->rcv_flowinfo); |
1177 | |
1178 | put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, len: sizeof(tclass), data: &tclass); |
1179 | } |
1180 | if (np->rxopt.bits.rxoinfo) { |
1181 | struct in6_pktinfo src_info; |
1182 | src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : |
1183 | np->sticky_pktinfo.ipi6_ifindex; |
1184 | src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : |
1185 | np->sticky_pktinfo.ipi6_addr; |
1186 | put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, len: sizeof(src_info), data: &src_info); |
1187 | } |
1188 | if (np->rxopt.bits.rxohlim) { |
1189 | int hlim = READ_ONCE(np->mcast_hops); |
1190 | |
1191 | put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, len: sizeof(hlim), data: &hlim); |
1192 | } |
1193 | if (np->rxopt.bits.rxflow) { |
1194 | __be32 flowinfo = np->rcv_flowinfo; |
1195 | |
1196 | put_cmsg(&msg, SOL_IPV6, IPV6_FLOWINFO, len: sizeof(flowinfo), data: &flowinfo); |
1197 | } |
1198 | } |
1199 | len -= msg.msg_controllen; |
1200 | return copy_to_sockptr(dst: optlen, src: &len, size: sizeof(int)); |
1201 | } |
1202 | case IPV6_MTU: |
1203 | { |
1204 | struct dst_entry *dst; |
1205 | |
1206 | val = 0; |
1207 | rcu_read_lock(); |
1208 | dst = __sk_dst_get(sk); |
1209 | if (dst) |
1210 | val = dst_mtu(dst); |
1211 | rcu_read_unlock(); |
1212 | if (!val) |
1213 | return -ENOTCONN; |
1214 | break; |
1215 | } |
1216 | |
1217 | case IPV6_V6ONLY: |
1218 | val = sk->sk_ipv6only; |
1219 | break; |
1220 | |
1221 | case IPV6_RECVPKTINFO: |
1222 | val = np->rxopt.bits.rxinfo; |
1223 | break; |
1224 | |
1225 | case IPV6_2292PKTINFO: |
1226 | val = np->rxopt.bits.rxoinfo; |
1227 | break; |
1228 | |
1229 | case IPV6_RECVHOPLIMIT: |
1230 | val = np->rxopt.bits.rxhlim; |
1231 | break; |
1232 | |
1233 | case IPV6_2292HOPLIMIT: |
1234 | val = np->rxopt.bits.rxohlim; |
1235 | break; |
1236 | |
1237 | case IPV6_RECVRTHDR: |
1238 | val = np->rxopt.bits.srcrt; |
1239 | break; |
1240 | |
1241 | case IPV6_2292RTHDR: |
1242 | val = np->rxopt.bits.osrcrt; |
1243 | break; |
1244 | |
1245 | case IPV6_HOPOPTS: |
1246 | case IPV6_RTHDRDSTOPTS: |
1247 | case IPV6_RTHDR: |
1248 | case IPV6_DSTOPTS: |
1249 | { |
1250 | struct ipv6_txoptions *opt; |
1251 | |
1252 | sockopt_lock_sock(sk); |
1253 | opt = rcu_dereference_protected(np->opt, |
1254 | lockdep_sock_is_held(sk)); |
1255 | len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len); |
1256 | sockopt_release_sock(sk); |
1257 | /* check if ipv6_getsockopt_sticky() returns err code */ |
1258 | if (len < 0) |
1259 | return len; |
1260 | return copy_to_sockptr(dst: optlen, src: &len, size: sizeof(int)); |
1261 | } |
1262 | |
1263 | case IPV6_RECVHOPOPTS: |
1264 | val = np->rxopt.bits.hopopts; |
1265 | break; |
1266 | |
1267 | case IPV6_2292HOPOPTS: |
1268 | val = np->rxopt.bits.ohopopts; |
1269 | break; |
1270 | |
1271 | case IPV6_RECVDSTOPTS: |
1272 | val = np->rxopt.bits.dstopts; |
1273 | break; |
1274 | |
1275 | case IPV6_2292DSTOPTS: |
1276 | val = np->rxopt.bits.odstopts; |
1277 | break; |
1278 | |
1279 | case IPV6_TCLASS: |
1280 | val = np->tclass; |
1281 | break; |
1282 | |
1283 | case IPV6_RECVTCLASS: |
1284 | val = np->rxopt.bits.rxtclass; |
1285 | break; |
1286 | |
1287 | case IPV6_FLOWINFO: |
1288 | val = np->rxopt.bits.rxflow; |
1289 | break; |
1290 | |
1291 | case IPV6_RECVPATHMTU: |
1292 | val = np->rxopt.bits.rxpmtu; |
1293 | break; |
1294 | |
1295 | case IPV6_PATHMTU: |
1296 | { |
1297 | struct dst_entry *dst; |
1298 | struct ip6_mtuinfo mtuinfo; |
1299 | |
1300 | if (len < sizeof(mtuinfo)) |
1301 | return -EINVAL; |
1302 | |
1303 | len = sizeof(mtuinfo); |
1304 | memset(&mtuinfo, 0, sizeof(mtuinfo)); |
1305 | |
1306 | rcu_read_lock(); |
1307 | dst = __sk_dst_get(sk); |
1308 | if (dst) |
1309 | mtuinfo.ip6m_mtu = dst_mtu(dst); |
1310 | rcu_read_unlock(); |
1311 | if (!mtuinfo.ip6m_mtu) |
1312 | return -ENOTCONN; |
1313 | |
1314 | if (copy_to_sockptr(dst: optlen, src: &len, size: sizeof(int))) |
1315 | return -EFAULT; |
1316 | if (copy_to_sockptr(dst: optval, src: &mtuinfo, size: len)) |
1317 | return -EFAULT; |
1318 | |
1319 | return 0; |
1320 | } |
1321 | |
1322 | case IPV6_TRANSPARENT: |
1323 | val = inet_test_bit(TRANSPARENT, sk); |
1324 | break; |
1325 | |
1326 | case IPV6_FREEBIND: |
1327 | val = inet_test_bit(FREEBIND, sk); |
1328 | break; |
1329 | |
1330 | case IPV6_RECVORIGDSTADDR: |
1331 | val = np->rxopt.bits.rxorigdstaddr; |
1332 | break; |
1333 | |
1334 | case IPV6_UNICAST_HOPS: |
1335 | case IPV6_MULTICAST_HOPS: |
1336 | { |
1337 | struct dst_entry *dst; |
1338 | |
1339 | if (optname == IPV6_UNICAST_HOPS) |
1340 | val = READ_ONCE(np->hop_limit); |
1341 | else |
1342 | val = READ_ONCE(np->mcast_hops); |
1343 | |
1344 | if (val < 0) { |
1345 | rcu_read_lock(); |
1346 | dst = __sk_dst_get(sk); |
1347 | if (dst) |
1348 | val = ip6_dst_hoplimit(dst); |
1349 | rcu_read_unlock(); |
1350 | } |
1351 | |
1352 | if (val < 0) |
1353 | val = sock_net(sk)->ipv6.devconf_all->hop_limit; |
1354 | break; |
1355 | } |
1356 | |
1357 | case IPV6_MULTICAST_LOOP: |
1358 | val = inet6_test_bit(MC6_LOOP, sk); |
1359 | break; |
1360 | |
1361 | case IPV6_MULTICAST_IF: |
1362 | val = np->mcast_oif; |
1363 | break; |
1364 | |
1365 | case IPV6_MULTICAST_ALL: |
1366 | val = inet6_test_bit(MC6_ALL, sk); |
1367 | break; |
1368 | |
1369 | case IPV6_UNICAST_IF: |
1370 | val = (__force int)htonl((__u32) np->ucast_oif); |
1371 | break; |
1372 | |
1373 | case IPV6_MTU_DISCOVER: |
1374 | val = READ_ONCE(np->pmtudisc); |
1375 | break; |
1376 | |
1377 | case IPV6_RECVERR: |
1378 | val = inet6_test_bit(RECVERR6, sk); |
1379 | break; |
1380 | |
1381 | case IPV6_FLOWINFO_SEND: |
1382 | val = inet6_test_bit(SNDFLOW, sk); |
1383 | break; |
1384 | |
1385 | case IPV6_FLOWLABEL_MGR: |
1386 | { |
1387 | struct in6_flowlabel_req freq; |
1388 | int flags; |
1389 | |
1390 | if (len < sizeof(freq)) |
1391 | return -EINVAL; |
1392 | |
1393 | if (copy_from_sockptr(dst: &freq, src: optval, size: sizeof(freq))) |
1394 | return -EFAULT; |
1395 | |
1396 | if (freq.flr_action != IPV6_FL_A_GET) |
1397 | return -EINVAL; |
1398 | |
1399 | len = sizeof(freq); |
1400 | flags = freq.flr_flags; |
1401 | |
1402 | memset(&freq, 0, sizeof(freq)); |
1403 | |
1404 | val = ipv6_flowlabel_opt_get(sk, freq: &freq, flags); |
1405 | if (val < 0) |
1406 | return val; |
1407 | |
1408 | if (copy_to_sockptr(dst: optlen, src: &len, size: sizeof(int))) |
1409 | return -EFAULT; |
1410 | if (copy_to_sockptr(dst: optval, src: &freq, size: len)) |
1411 | return -EFAULT; |
1412 | |
1413 | return 0; |
1414 | } |
1415 | |
1416 | case IPV6_ADDR_PREFERENCES: |
1417 | { |
1418 | u8 srcprefs = READ_ONCE(np->srcprefs); |
1419 | val = 0; |
1420 | |
1421 | if (srcprefs & IPV6_PREFER_SRC_TMP) |
1422 | val |= IPV6_PREFER_SRC_TMP; |
1423 | else if (srcprefs & IPV6_PREFER_SRC_PUBLIC) |
1424 | val |= IPV6_PREFER_SRC_PUBLIC; |
1425 | else { |
1426 | /* XXX: should we return system default? */ |
1427 | val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT; |
1428 | } |
1429 | |
1430 | if (srcprefs & IPV6_PREFER_SRC_COA) |
1431 | val |= IPV6_PREFER_SRC_COA; |
1432 | else |
1433 | val |= IPV6_PREFER_SRC_HOME; |
1434 | break; |
1435 | } |
1436 | case IPV6_MINHOPCOUNT: |
1437 | val = READ_ONCE(np->min_hopcount); |
1438 | break; |
1439 | |
1440 | case IPV6_DONTFRAG: |
1441 | val = inet6_test_bit(DONTFRAG, sk); |
1442 | break; |
1443 | |
1444 | case IPV6_AUTOFLOWLABEL: |
1445 | val = ip6_autoflowlabel(net: sock_net(sk), sk); |
1446 | break; |
1447 | |
1448 | case IPV6_RECVFRAGSIZE: |
1449 | val = np->rxopt.bits.recvfragsize; |
1450 | break; |
1451 | |
1452 | case IPV6_ROUTER_ALERT_ISOLATE: |
1453 | val = inet6_test_bit(RTALERT_ISOLATE, sk); |
1454 | break; |
1455 | |
1456 | case IPV6_RECVERR_RFC4884: |
1457 | val = inet6_test_bit(RECVERR6_RFC4884, sk); |
1458 | break; |
1459 | |
1460 | default: |
1461 | return -ENOPROTOOPT; |
1462 | } |
1463 | len = min_t(unsigned int, sizeof(int), len); |
1464 | if (copy_to_sockptr(dst: optlen, src: &len, size: sizeof(int))) |
1465 | return -EFAULT; |
1466 | if (copy_to_sockptr(dst: optval, src: &val, size: len)) |
1467 | return -EFAULT; |
1468 | return 0; |
1469 | } |
1470 | |
1471 | int ipv6_getsockopt(struct sock *sk, int level, int optname, |
1472 | char __user *optval, int __user *optlen) |
1473 | { |
1474 | int err; |
1475 | |
1476 | if (level == SOL_IP && sk->sk_type != SOCK_RAW) |
1477 | return udp_prot.getsockopt(sk, level, optname, optval, optlen); |
1478 | |
1479 | if (level != SOL_IPV6) |
1480 | return -ENOPROTOOPT; |
1481 | |
1482 | err = do_ipv6_getsockopt(sk, level, optname, |
1483 | optval: USER_SOCKPTR(p: optval), optlen: USER_SOCKPTR(p: optlen)); |
1484 | #ifdef CONFIG_NETFILTER |
1485 | /* we need to exclude all possible ENOPROTOOPTs except default case */ |
1486 | if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) { |
1487 | int len; |
1488 | |
1489 | if (get_user(len, optlen)) |
1490 | return -EFAULT; |
1491 | |
1492 | err = nf_getsockopt(sk, PF_INET6, optval: optname, opt: optval, len: &len); |
1493 | if (err >= 0) |
1494 | err = put_user(len, optlen); |
1495 | } |
1496 | #endif |
1497 | return err; |
1498 | } |
1499 | EXPORT_SYMBOL(ipv6_getsockopt); |
1500 | |