| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * RAW sockets for IPv6 |
|---|
| 3 | 4 | * Linux INET6 implementation |
|---|
| .. | .. |
|---|
| 11 | 12 | * Hideaki YOSHIFUJI : sin6_scope_id support |
|---|
| 12 | 13 | * YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance) |
|---|
| 13 | 14 | * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is free software; you can redistribute it and/or |
|---|
| 16 | | - * modify it under the terms of the GNU General Public License |
|---|
| 17 | | - * as published by the Free Software Foundation; either version |
|---|
| 18 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 19 | 15 | */ |
|---|
| 20 | 16 | |
|---|
| 21 | 17 | #include <linux/errno.h> |
|---|
| .. | .. |
|---|
| 86 | 82 | !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) |
|---|
| 87 | 83 | continue; |
|---|
| 88 | 84 | |
|---|
| 89 | | - if (sk->sk_bound_dev_if && |
|---|
| 90 | | - sk->sk_bound_dev_if != dif && |
|---|
| 91 | | - sk->sk_bound_dev_if != sdif) |
|---|
| 85 | + if (!raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, |
|---|
| 86 | + dif, sdif)) |
|---|
| 92 | 87 | continue; |
|---|
| 93 | 88 | |
|---|
| 94 | 89 | if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { |
|---|
| .. | .. |
|---|
| 220 | 215 | |
|---|
| 221 | 216 | /* Not releasing hash table! */ |
|---|
| 222 | 217 | if (clone) { |
|---|
| 223 | | - nf_reset(clone); |
|---|
| 218 | + nf_reset_ct(clone); |
|---|
| 224 | 219 | rawv6_rcv(sk, clone); |
|---|
| 225 | 220 | } |
|---|
| 226 | 221 | } |
|---|
| .. | .. |
|---|
| 544 | 539 | static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, |
|---|
| 545 | 540 | struct raw6_sock *rp) |
|---|
| 546 | 541 | { |
|---|
| 542 | + struct ipv6_txoptions *opt; |
|---|
| 547 | 543 | struct sk_buff *skb; |
|---|
| 548 | 544 | int err = 0; |
|---|
| 549 | 545 | int offset; |
|---|
| .. | .. |
|---|
| 561 | 557 | |
|---|
| 562 | 558 | offset = rp->offset; |
|---|
| 563 | 559 | total_len = inet_sk(sk)->cork.base.length; |
|---|
| 560 | + opt = inet6_sk(sk)->cork.opt; |
|---|
| 561 | + total_len -= opt ? opt->opt_flen : 0; |
|---|
| 562 | + |
|---|
| 564 | 563 | if (offset >= total_len - 1) { |
|---|
| 565 | 564 | err = -EINVAL; |
|---|
| 566 | 565 | ip6_flush_pending_frames(sk); |
|---|
| .. | .. |
|---|
| 651 | 650 | |
|---|
| 652 | 651 | skb->protocol = htons(ETH_P_IPV6); |
|---|
| 653 | 652 | skb->priority = sk->sk_priority; |
|---|
| 654 | | - skb->mark = sk->sk_mark; |
|---|
| 653 | + skb->mark = sockc->mark; |
|---|
| 655 | 654 | skb->tstamp = sockc->transmit_time; |
|---|
| 656 | 655 | |
|---|
| 657 | 656 | skb_put(skb, length); |
|---|
| .. | .. |
|---|
| 660 | 659 | |
|---|
| 661 | 660 | skb->ip_summed = CHECKSUM_NONE; |
|---|
| 662 | 661 | |
|---|
| 663 | | - sock_tx_timestamp(sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags); |
|---|
| 662 | + skb_setup_tx_timestamp(skb, sockc->tsflags); |
|---|
| 664 | 663 | |
|---|
| 665 | 664 | if (flags & MSG_CONFIRM) |
|---|
| 666 | 665 | skb_set_dst_pending_confirm(skb, 1); |
|---|
| .. | .. |
|---|
| 751 | 750 | skb->csum = csum_block_add( |
|---|
| 752 | 751 | skb->csum, |
|---|
| 753 | 752 | csum_partial_copy_nocheck(rfv->c + offset, |
|---|
| 754 | | - to, copy, 0), |
|---|
| 753 | + to, copy), |
|---|
| 755 | 754 | odd); |
|---|
| 756 | 755 | |
|---|
| 757 | 756 | odd = 0; |
|---|
| .. | .. |
|---|
| 815 | 814 | |
|---|
| 816 | 815 | ipcm6_init(&ipc6); |
|---|
| 817 | 816 | ipc6.sockc.tsflags = sk->sk_tsflags; |
|---|
| 817 | + ipc6.sockc.mark = sk->sk_mark; |
|---|
| 818 | 818 | |
|---|
| 819 | 819 | if (sin6) { |
|---|
| 820 | 820 | if (addr_len < SIN6_LEN_RFC2133) |
|---|
| .. | .. |
|---|
| 828 | 828 | |
|---|
| 829 | 829 | if (!proto) |
|---|
| 830 | 830 | proto = inet->inet_num; |
|---|
| 831 | | - else if (proto != inet->inet_num) |
|---|
| 831 | + else if (proto != inet->inet_num && |
|---|
| 832 | + inet->inet_num != IPPROTO_RAW) |
|---|
| 832 | 833 | return -EINVAL; |
|---|
| 833 | 834 | |
|---|
| 834 | 835 | if (proto > 255) |
|---|
| .. | .. |
|---|
| 839 | 840 | fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; |
|---|
| 840 | 841 | if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { |
|---|
| 841 | 842 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
|---|
| 842 | | - if (!flowlabel) |
|---|
| 843 | + if (IS_ERR(flowlabel)) |
|---|
| 843 | 844 | return -EINVAL; |
|---|
| 844 | 845 | } |
|---|
| 845 | 846 | } |
|---|
| .. | .. |
|---|
| 881 | 882 | } |
|---|
| 882 | 883 | if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { |
|---|
| 883 | 884 | flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); |
|---|
| 884 | | - if (!flowlabel) |
|---|
| 885 | + if (IS_ERR(flowlabel)) |
|---|
| 885 | 886 | return -EINVAL; |
|---|
| 886 | 887 | } |
|---|
| 887 | 888 | if (!(opt->opt_nflen|opt->opt_flen)) |
|---|
| .. | .. |
|---|
| 896 | 897 | opt = ipv6_fixup_options(&opt_space, opt); |
|---|
| 897 | 898 | |
|---|
| 898 | 899 | fl6.flowi6_proto = proto; |
|---|
| 900 | + fl6.flowi6_mark = ipc6.sockc.mark; |
|---|
| 899 | 901 | |
|---|
| 900 | 902 | if (!hdrincl) { |
|---|
| 901 | 903 | rfv.msg = msg; |
|---|
| .. | .. |
|---|
| 918 | 920 | fl6.flowi6_oif = np->mcast_oif; |
|---|
| 919 | 921 | else if (!fl6.flowi6_oif) |
|---|
| 920 | 922 | fl6.flowi6_oif = np->ucast_oif; |
|---|
| 921 | | - security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); |
|---|
| 923 | + security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6)); |
|---|
| 922 | 924 | |
|---|
| 923 | 925 | if (hdrincl) |
|---|
| 924 | 926 | fl6.flowi6_flags |= FLOWI_FLAG_KNOWN_NH; |
|---|
| .. | .. |
|---|
| 975 | 977 | } |
|---|
| 976 | 978 | |
|---|
| 977 | 979 | static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, |
|---|
| 978 | | - char __user *optval, int optlen) |
|---|
| 980 | + sockptr_t optval, int optlen) |
|---|
| 979 | 981 | { |
|---|
| 980 | 982 | switch (optname) { |
|---|
| 981 | 983 | case ICMPV6_FILTER: |
|---|
| 982 | 984 | if (optlen > sizeof(struct icmp6_filter)) |
|---|
| 983 | 985 | optlen = sizeof(struct icmp6_filter); |
|---|
| 984 | | - if (copy_from_user(&raw6_sk(sk)->filter, optval, optlen)) |
|---|
| 986 | + if (copy_from_sockptr(&raw6_sk(sk)->filter, optval, optlen)) |
|---|
| 985 | 987 | return -EFAULT; |
|---|
| 986 | 988 | return 0; |
|---|
| 987 | 989 | default: |
|---|
| .. | .. |
|---|
| 1018 | 1020 | |
|---|
| 1019 | 1021 | |
|---|
| 1020 | 1022 | static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 1021 | | - char __user *optval, unsigned int optlen) |
|---|
| 1023 | + sockptr_t optval, unsigned int optlen) |
|---|
| 1022 | 1024 | { |
|---|
| 1023 | 1025 | struct raw6_sock *rp = raw6_sk(sk); |
|---|
| 1024 | 1026 | int val; |
|---|
| 1025 | 1027 | |
|---|
| 1026 | | - if (get_user(val, (int __user *)optval)) |
|---|
| 1028 | + if (optlen < sizeof(val)) |
|---|
| 1029 | + return -EINVAL; |
|---|
| 1030 | + |
|---|
| 1031 | + if (copy_from_sockptr(&val, optval, sizeof(val))) |
|---|
| 1027 | 1032 | return -EFAULT; |
|---|
| 1028 | 1033 | |
|---|
| 1029 | 1034 | switch (optname) { |
|---|
| .. | .. |
|---|
| 1065 | 1070 | } |
|---|
| 1066 | 1071 | |
|---|
| 1067 | 1072 | static int rawv6_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 1068 | | - char __user *optval, unsigned int optlen) |
|---|
| 1073 | + sockptr_t optval, unsigned int optlen) |
|---|
| 1069 | 1074 | { |
|---|
| 1070 | 1075 | switch (level) { |
|---|
| 1071 | 1076 | case SOL_RAW: |
|---|
| .. | .. |
|---|
| 1079 | 1084 | if (optname == IPV6_CHECKSUM || |
|---|
| 1080 | 1085 | optname == IPV6_HDRINCL) |
|---|
| 1081 | 1086 | break; |
|---|
| 1082 | | - /* fall through */ |
|---|
| 1087 | + fallthrough; |
|---|
| 1083 | 1088 | default: |
|---|
| 1084 | 1089 | return ipv6_setsockopt(sk, level, optname, optval, optlen); |
|---|
| 1085 | 1090 | } |
|---|
| 1086 | 1091 | |
|---|
| 1087 | 1092 | return do_rawv6_setsockopt(sk, level, optname, optval, optlen); |
|---|
| 1088 | 1093 | } |
|---|
| 1089 | | - |
|---|
| 1090 | | -#ifdef CONFIG_COMPAT |
|---|
| 1091 | | -static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 1092 | | - char __user *optval, unsigned int optlen) |
|---|
| 1093 | | -{ |
|---|
| 1094 | | - switch (level) { |
|---|
| 1095 | | - case SOL_RAW: |
|---|
| 1096 | | - break; |
|---|
| 1097 | | - case SOL_ICMPV6: |
|---|
| 1098 | | - if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) |
|---|
| 1099 | | - return -EOPNOTSUPP; |
|---|
| 1100 | | - return rawv6_seticmpfilter(sk, level, optname, optval, optlen); |
|---|
| 1101 | | - case SOL_IPV6: |
|---|
| 1102 | | - if (optname == IPV6_CHECKSUM || |
|---|
| 1103 | | - optname == IPV6_HDRINCL) |
|---|
| 1104 | | - break; |
|---|
| 1105 | | - /* fall through */ |
|---|
| 1106 | | - default: |
|---|
| 1107 | | - return compat_ipv6_setsockopt(sk, level, optname, |
|---|
| 1108 | | - optval, optlen); |
|---|
| 1109 | | - } |
|---|
| 1110 | | - return do_rawv6_setsockopt(sk, level, optname, optval, optlen); |
|---|
| 1111 | | -} |
|---|
| 1112 | | -#endif |
|---|
| 1113 | 1094 | |
|---|
| 1114 | 1095 | static int do_rawv6_getsockopt(struct sock *sk, int level, int optname, |
|---|
| 1115 | 1096 | char __user *optval, int __user *optlen) |
|---|
| .. | .. |
|---|
| 1164 | 1145 | if (optname == IPV6_CHECKSUM || |
|---|
| 1165 | 1146 | optname == IPV6_HDRINCL) |
|---|
| 1166 | 1147 | break; |
|---|
| 1167 | | - /* fall through */ |
|---|
| 1148 | + fallthrough; |
|---|
| 1168 | 1149 | default: |
|---|
| 1169 | 1150 | return ipv6_getsockopt(sk, level, optname, optval, optlen); |
|---|
| 1170 | 1151 | } |
|---|
| 1171 | 1152 | |
|---|
| 1172 | 1153 | return do_rawv6_getsockopt(sk, level, optname, optval, optlen); |
|---|
| 1173 | 1154 | } |
|---|
| 1174 | | - |
|---|
| 1175 | | -#ifdef CONFIG_COMPAT |
|---|
| 1176 | | -static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname, |
|---|
| 1177 | | - char __user *optval, int __user *optlen) |
|---|
| 1178 | | -{ |
|---|
| 1179 | | - switch (level) { |
|---|
| 1180 | | - case SOL_RAW: |
|---|
| 1181 | | - break; |
|---|
| 1182 | | - case SOL_ICMPV6: |
|---|
| 1183 | | - if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) |
|---|
| 1184 | | - return -EOPNOTSUPP; |
|---|
| 1185 | | - return rawv6_geticmpfilter(sk, level, optname, optval, optlen); |
|---|
| 1186 | | - case SOL_IPV6: |
|---|
| 1187 | | - if (optname == IPV6_CHECKSUM || |
|---|
| 1188 | | - optname == IPV6_HDRINCL) |
|---|
| 1189 | | - break; |
|---|
| 1190 | | - /* fall through */ |
|---|
| 1191 | | - default: |
|---|
| 1192 | | - return compat_ipv6_getsockopt(sk, level, optname, |
|---|
| 1193 | | - optval, optlen); |
|---|
| 1194 | | - } |
|---|
| 1195 | | - return do_rawv6_getsockopt(sk, level, optname, optval, optlen); |
|---|
| 1196 | | -} |
|---|
| 1197 | | -#endif |
|---|
| 1198 | 1155 | |
|---|
| 1199 | 1156 | static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) |
|---|
| 1200 | 1157 | { |
|---|
| .. | .. |
|---|
| 1255 | 1212 | lock_sock(sk); |
|---|
| 1256 | 1213 | ip6_flush_pending_frames(sk); |
|---|
| 1257 | 1214 | release_sock(sk); |
|---|
| 1258 | | - |
|---|
| 1259 | | - inet6_destroy_sock(sk); |
|---|
| 1260 | 1215 | } |
|---|
| 1261 | 1216 | |
|---|
| 1262 | 1217 | static int rawv6_init_sk(struct sock *sk) |
|---|
| .. | .. |
|---|
| 1300 | 1255 | .usersize = sizeof_field(struct raw6_sock, filter), |
|---|
| 1301 | 1256 | .h.raw_hash = &raw_v6_hashinfo, |
|---|
| 1302 | 1257 | #ifdef CONFIG_COMPAT |
|---|
| 1303 | | - .compat_setsockopt = compat_rawv6_setsockopt, |
|---|
| 1304 | | - .compat_getsockopt = compat_rawv6_getsockopt, |
|---|
| 1305 | 1258 | .compat_ioctl = compat_rawv6_ioctl, |
|---|
| 1306 | 1259 | #endif |
|---|
| 1307 | 1260 | .diag_destroy = raw_abort, |
|---|
| .. | .. |
|---|
| 1370 | 1323 | .getname = inet6_getname, |
|---|
| 1371 | 1324 | .poll = datagram_poll, /* ok */ |
|---|
| 1372 | 1325 | .ioctl = inet6_ioctl, /* must change */ |
|---|
| 1326 | + .gettstamp = sock_gettstamp, |
|---|
| 1373 | 1327 | .listen = sock_no_listen, /* ok */ |
|---|
| 1374 | 1328 | .shutdown = inet_shutdown, /* ok */ |
|---|
| 1375 | 1329 | .setsockopt = sock_common_setsockopt, /* ok */ |
|---|
| .. | .. |
|---|
| 1379 | 1333 | .mmap = sock_no_mmap, |
|---|
| 1380 | 1334 | .sendpage = sock_no_sendpage, |
|---|
| 1381 | 1335 | #ifdef CONFIG_COMPAT |
|---|
| 1382 | | - .compat_setsockopt = compat_sock_common_setsockopt, |
|---|
| 1383 | | - .compat_getsockopt = compat_sock_common_getsockopt, |
|---|
| 1336 | + .compat_ioctl = inet6_compat_ioctl, |
|---|
| 1384 | 1337 | #endif |
|---|
| 1385 | 1338 | }; |
|---|
| 1386 | 1339 | |
|---|