| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * NET3: Implementation of the ICMP protocol layer. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Alan Cox, <alan@lxorguk.ukuu.org.uk> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License |
|---|
| 8 | | - * as published by the Free Software Foundation; either version |
|---|
| 9 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 10 | 6 | * |
|---|
| 11 | 7 | * Some of the function names and the icmp unreach table for this |
|---|
| 12 | 8 | * module were derived from [icmp.c 1.0.11 06/02/93] by |
|---|
| .. | .. |
|---|
| 59 | 55 | * |
|---|
| 60 | 56 | * - Should use skb_pull() instead of all the manual checking. |
|---|
| 61 | 57 | * This would also greatly simply some upper layer error handlers. --AK |
|---|
| 62 | | - * |
|---|
| 63 | 58 | */ |
|---|
| 64 | 59 | |
|---|
| 65 | 60 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 77 | 72 | #include <linux/string.h> |
|---|
| 78 | 73 | #include <linux/netfilter_ipv4.h> |
|---|
| 79 | 74 | #include <linux/slab.h> |
|---|
| 80 | | -#include <linux/locallock.h> |
|---|
| 81 | 75 | #include <net/snmp.h> |
|---|
| 82 | 76 | #include <net/ip.h> |
|---|
| 83 | 77 | #include <net/route.h> |
|---|
| .. | .. |
|---|
| 205 | 199 | * |
|---|
| 206 | 200 | * On SMP we have one ICMP socket per-cpu. |
|---|
| 207 | 201 | */ |
|---|
| 208 | | -static DEFINE_LOCAL_IRQ_LOCK(icmp_sk_lock); |
|---|
| 209 | | - |
|---|
| 210 | 202 | static struct sock *icmp_sk(struct net *net) |
|---|
| 211 | 203 | { |
|---|
| 212 | | - return *this_cpu_ptr(net->ipv4.icmp_sk); |
|---|
| 204 | + return this_cpu_read(*net->ipv4.icmp_sk); |
|---|
| 213 | 205 | } |
|---|
| 214 | 206 | |
|---|
| 215 | 207 | /* Called with BH disabled */ |
|---|
| .. | .. |
|---|
| 217 | 209 | { |
|---|
| 218 | 210 | struct sock *sk; |
|---|
| 219 | 211 | |
|---|
| 220 | | - if (!local_trylock(icmp_sk_lock)) |
|---|
| 221 | | - return NULL; |
|---|
| 222 | | - |
|---|
| 223 | 212 | sk = icmp_sk(net); |
|---|
| 224 | 213 | |
|---|
| 225 | 214 | if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { |
|---|
| 226 | 215 | /* This can happen if the output path signals a |
|---|
| 227 | 216 | * dst_link_failure() for an outgoing ICMP packet. |
|---|
| 228 | 217 | */ |
|---|
| 229 | | - local_unlock(icmp_sk_lock); |
|---|
| 230 | 218 | return NULL; |
|---|
| 231 | 219 | } |
|---|
| 232 | 220 | return sk; |
|---|
| .. | .. |
|---|
| 235 | 223 | static inline void icmp_xmit_unlock(struct sock *sk) |
|---|
| 236 | 224 | { |
|---|
| 237 | 225 | spin_unlock(&sk->sk_lock.slock); |
|---|
| 238 | | - local_unlock(icmp_sk_lock); |
|---|
| 239 | 226 | } |
|---|
| 240 | 227 | |
|---|
| 241 | 228 | int sysctl_icmp_msgs_per_sec __read_mostly = 1000; |
|---|
| .. | .. |
|---|
| 274 | 261 | spin_lock(&icmp_global.lock); |
|---|
| 275 | 262 | delta = min_t(u32, now - icmp_global.stamp, HZ); |
|---|
| 276 | 263 | if (delta >= HZ / 50) { |
|---|
| 277 | | - incr = sysctl_icmp_msgs_per_sec * delta / HZ ; |
|---|
| 264 | + incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ; |
|---|
| 278 | 265 | if (incr) |
|---|
| 279 | 266 | WRITE_ONCE(icmp_global.stamp, now); |
|---|
| 280 | 267 | } |
|---|
| 281 | | - credit = min_t(u32, icmp_global.credit + incr, sysctl_icmp_msgs_burst); |
|---|
| 268 | + credit = min_t(u32, icmp_global.credit + incr, |
|---|
| 269 | + READ_ONCE(sysctl_icmp_msgs_burst)); |
|---|
| 282 | 270 | if (credit) { |
|---|
| 283 | 271 | /* We want to use a credit of one in average, but need to randomize |
|---|
| 284 | 272 | * it for security reasons. |
|---|
| .. | .. |
|---|
| 302 | 290 | return true; |
|---|
| 303 | 291 | |
|---|
| 304 | 292 | /* Limit if icmp type is enabled in ratemask. */ |
|---|
| 305 | | - if (!((1 << type) & net->ipv4.sysctl_icmp_ratemask)) |
|---|
| 293 | + if (!((1 << type) & READ_ONCE(net->ipv4.sysctl_icmp_ratemask))) |
|---|
| 306 | 294 | return true; |
|---|
| 307 | 295 | |
|---|
| 308 | 296 | return false; |
|---|
| .. | .. |
|---|
| 340 | 328 | |
|---|
| 341 | 329 | vif = l3mdev_master_ifindex(dst->dev); |
|---|
| 342 | 330 | peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1); |
|---|
| 343 | | - rc = inet_peer_xrlim_allow(peer, net->ipv4.sysctl_icmp_ratelimit); |
|---|
| 331 | + rc = inet_peer_xrlim_allow(peer, |
|---|
| 332 | + READ_ONCE(net->ipv4.sysctl_icmp_ratelimit)); |
|---|
| 344 | 333 | if (peer) |
|---|
| 345 | 334 | inet_putpeer(peer); |
|---|
| 346 | 335 | out: |
|---|
| .. | .. |
|---|
| 368 | 357 | |
|---|
| 369 | 358 | csum = skb_copy_and_csum_bits(icmp_param->skb, |
|---|
| 370 | 359 | icmp_param->offset + offset, |
|---|
| 371 | | - to, len, 0); |
|---|
| 360 | + to, len); |
|---|
| 372 | 361 | |
|---|
| 373 | 362 | skb->csum = csum_block_add(skb->csum, csum, odd); |
|---|
| 374 | 363 | if (icmp_pointers[icmp_param->data.icmph.type].error) |
|---|
| .. | .. |
|---|
| 392 | 381 | ip_flush_pending_frames(sk); |
|---|
| 393 | 382 | } else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { |
|---|
| 394 | 383 | struct icmphdr *icmph = icmp_hdr(skb); |
|---|
| 395 | | - __wsum csum = 0; |
|---|
| 384 | + __wsum csum; |
|---|
| 396 | 385 | struct sk_buff *skb1; |
|---|
| 397 | 386 | |
|---|
| 387 | + csum = csum_partial_copy_nocheck((void *)&icmp_param->data, |
|---|
| 388 | + (char *)icmph, |
|---|
| 389 | + icmp_param->head_len); |
|---|
| 398 | 390 | skb_queue_walk(&sk->sk_write_queue, skb1) { |
|---|
| 399 | 391 | csum = csum_add(csum, skb1->csum); |
|---|
| 400 | 392 | } |
|---|
| 401 | | - csum = csum_partial_copy_nocheck((void *)&icmp_param->data, |
|---|
| 402 | | - (char *)icmph, |
|---|
| 403 | | - icmp_param->head_len, csum); |
|---|
| 404 | 393 | icmph->checksum = csum_fold(csum); |
|---|
| 405 | 394 | skb->ip_summed = CHECKSUM_NONE; |
|---|
| 406 | 395 | ip_push_pending_frames(sk, fl4); |
|---|
| .. | .. |
|---|
| 443 | 432 | |
|---|
| 444 | 433 | ipcm_init(&ipc); |
|---|
| 445 | 434 | inet->tos = ip_hdr(skb)->tos; |
|---|
| 446 | | - sk->sk_mark = mark; |
|---|
| 435 | + ipc.sockc.mark = mark; |
|---|
| 447 | 436 | daddr = ipc.addr = ip_hdr(skb)->saddr; |
|---|
| 448 | 437 | saddr = fib_compute_spec_dst(skb); |
|---|
| 449 | 438 | |
|---|
| .. | .. |
|---|
| 460 | 449 | fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); |
|---|
| 461 | 450 | fl4.flowi4_proto = IPPROTO_ICMP; |
|---|
| 462 | 451 | fl4.flowi4_oif = l3mdev_master_ifindex(skb->dev); |
|---|
| 463 | | - security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); |
|---|
| 452 | + security_skb_classify_flow(skb, flowi4_to_flowi_common(&fl4)); |
|---|
| 464 | 453 | rt = ip_route_output_key(net, &fl4); |
|---|
| 465 | 454 | if (IS_ERR(rt)) |
|---|
| 466 | 455 | goto out_unlock; |
|---|
| .. | .. |
|---|
| 516 | 505 | route_lookup_dev = icmp_get_route_lookup_dev(skb_in); |
|---|
| 517 | 506 | fl4->flowi4_oif = l3mdev_master_ifindex(route_lookup_dev); |
|---|
| 518 | 507 | |
|---|
| 519 | | - security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4)); |
|---|
| 508 | + security_skb_classify_flow(skb_in, flowi4_to_flowi_common(fl4)); |
|---|
| 520 | 509 | rt = ip_route_output_key_hash(net, fl4, skb_in); |
|---|
| 521 | 510 | if (IS_ERR(rt)) |
|---|
| 522 | 511 | return rt; |
|---|
| .. | .. |
|---|
| 718 | 707 | dev = dev_get_by_index_rcu(net, inet_iif(skb_in)); |
|---|
| 719 | 708 | |
|---|
| 720 | 709 | if (dev) |
|---|
| 721 | | - saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); |
|---|
| 710 | + saddr = inet_select_addr(dev, iph->saddr, |
|---|
| 711 | + RT_SCOPE_LINK); |
|---|
| 722 | 712 | else |
|---|
| 723 | 713 | saddr = 0; |
|---|
| 724 | 714 | rcu_read_unlock(); |
|---|
| 725 | 715 | } |
|---|
| 726 | 716 | |
|---|
| 727 | | - tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) | |
|---|
| 717 | + tos = icmp_pointers[type].error ? (RT_TOS(iph->tos) | |
|---|
| 728 | 718 | IPTOS_PREC_INTERNETCONTROL) : |
|---|
| 729 | | - iph->tos; |
|---|
| 719 | + iph->tos; |
|---|
| 730 | 720 | mark = IP4_REPLY_MARK(net, skb_in->mark); |
|---|
| 731 | 721 | |
|---|
| 732 | 722 | if (__ip_options_echo(net, &icmp_param.replyopts.opt.opt, skb_in, opt)) |
|---|
| .. | .. |
|---|
| 744 | 734 | icmp_param.skb = skb_in; |
|---|
| 745 | 735 | icmp_param.offset = skb_network_offset(skb_in); |
|---|
| 746 | 736 | inet_sk(sk)->tos = tos; |
|---|
| 747 | | - sk->sk_mark = mark; |
|---|
| 748 | 737 | ipcm_init(&ipc); |
|---|
| 749 | 738 | ipc.addr = iph->saddr; |
|---|
| 750 | 739 | ipc.opt = &icmp_param.replyopts.opt; |
|---|
| 740 | + ipc.sockc.mark = mark; |
|---|
| 751 | 741 | |
|---|
| 752 | 742 | rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, mark, |
|---|
| 753 | 743 | type, code, &icmp_param); |
|---|
| .. | .. |
|---|
| 826 | 816 | |
|---|
| 827 | 817 | static void icmp_socket_deliver(struct sk_buff *skb, u32 info) |
|---|
| 828 | 818 | { |
|---|
| 829 | | - const struct iphdr *iph = (const struct iphdr *) skb->data; |
|---|
| 819 | + const struct iphdr *iph = (const struct iphdr *)skb->data; |
|---|
| 830 | 820 | const struct net_protocol *ipprot; |
|---|
| 831 | 821 | int protocol = iph->protocol; |
|---|
| 832 | 822 | |
|---|
| .. | .. |
|---|
| 895 | 885 | case ICMP_FRAG_NEEDED: |
|---|
| 896 | 886 | /* for documentation of the ip_no_pmtu_disc |
|---|
| 897 | 887 | * values please see |
|---|
| 898 | | - * Documentation/networking/ip-sysctl.txt |
|---|
| 888 | + * Documentation/networking/ip-sysctl.rst |
|---|
| 899 | 889 | */ |
|---|
| 900 | | - switch (net->ipv4.sysctl_ip_no_pmtu_disc) { |
|---|
| 890 | + switch (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc)) { |
|---|
| 901 | 891 | default: |
|---|
| 902 | 892 | net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n", |
|---|
| 903 | 893 | &iph->daddr); |
|---|
| .. | .. |
|---|
| 907 | 897 | case 3: |
|---|
| 908 | 898 | if (!icmp_tag_validation(iph->protocol)) |
|---|
| 909 | 899 | goto out; |
|---|
| 910 | | - /* fall through */ |
|---|
| 900 | + fallthrough; |
|---|
| 911 | 901 | case 0: |
|---|
| 912 | 902 | info = ntohs(icmph->un.frag.mtu); |
|---|
| 913 | 903 | } |
|---|
| .. | .. |
|---|
| 985 | 975 | return false; |
|---|
| 986 | 976 | } |
|---|
| 987 | 977 | |
|---|
| 988 | | - icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway); |
|---|
| 978 | + icmp_socket_deliver(skb, ntohl(icmp_hdr(skb)->un.gateway)); |
|---|
| 989 | 979 | return true; |
|---|
| 990 | 980 | } |
|---|
| 991 | 981 | |
|---|
| .. | .. |
|---|
| 1158 | 1148 | goto drop; |
|---|
| 1159 | 1149 | } |
|---|
| 1160 | 1150 | |
|---|
| 1161 | | -void icmp_err(struct sk_buff *skb, u32 info) |
|---|
| 1151 | +static bool ip_icmp_error_rfc4884_validate(const struct sk_buff *skb, int off) |
|---|
| 1152 | +{ |
|---|
| 1153 | + struct icmp_extobj_hdr *objh, _objh; |
|---|
| 1154 | + struct icmp_ext_hdr *exth, _exth; |
|---|
| 1155 | + u16 olen; |
|---|
| 1156 | + |
|---|
| 1157 | + exth = skb_header_pointer(skb, off, sizeof(_exth), &_exth); |
|---|
| 1158 | + if (!exth) |
|---|
| 1159 | + return false; |
|---|
| 1160 | + if (exth->version != 2) |
|---|
| 1161 | + return true; |
|---|
| 1162 | + |
|---|
| 1163 | + if (exth->checksum && |
|---|
| 1164 | + csum_fold(skb_checksum(skb, off, skb->len - off, 0))) |
|---|
| 1165 | + return false; |
|---|
| 1166 | + |
|---|
| 1167 | + off += sizeof(_exth); |
|---|
| 1168 | + while (off < skb->len) { |
|---|
| 1169 | + objh = skb_header_pointer(skb, off, sizeof(_objh), &_objh); |
|---|
| 1170 | + if (!objh) |
|---|
| 1171 | + return false; |
|---|
| 1172 | + |
|---|
| 1173 | + olen = ntohs(objh->length); |
|---|
| 1174 | + if (olen < sizeof(_objh)) |
|---|
| 1175 | + return false; |
|---|
| 1176 | + |
|---|
| 1177 | + off += olen; |
|---|
| 1178 | + if (off > skb->len) |
|---|
| 1179 | + return false; |
|---|
| 1180 | + } |
|---|
| 1181 | + |
|---|
| 1182 | + return true; |
|---|
| 1183 | +} |
|---|
| 1184 | + |
|---|
| 1185 | +void ip_icmp_error_rfc4884(const struct sk_buff *skb, |
|---|
| 1186 | + struct sock_ee_data_rfc4884 *out, |
|---|
| 1187 | + int thlen, int off) |
|---|
| 1188 | +{ |
|---|
| 1189 | + int hlen; |
|---|
| 1190 | + |
|---|
| 1191 | + /* original datagram headers: end of icmph to payload (skb->data) */ |
|---|
| 1192 | + hlen = -skb_transport_offset(skb) - thlen; |
|---|
| 1193 | + |
|---|
| 1194 | + /* per rfc 4884: minimal datagram length of 128 bytes */ |
|---|
| 1195 | + if (off < 128 || off < hlen) |
|---|
| 1196 | + return; |
|---|
| 1197 | + |
|---|
| 1198 | + /* kernel has stripped headers: return payload offset in bytes */ |
|---|
| 1199 | + off -= hlen; |
|---|
| 1200 | + if (off + sizeof(struct icmp_ext_hdr) > skb->len) |
|---|
| 1201 | + return; |
|---|
| 1202 | + |
|---|
| 1203 | + out->len = off; |
|---|
| 1204 | + |
|---|
| 1205 | + if (!ip_icmp_error_rfc4884_validate(skb, off)) |
|---|
| 1206 | + out->flags |= SO_EE_RFC4884_FLAG_INVALID; |
|---|
| 1207 | +} |
|---|
| 1208 | +EXPORT_SYMBOL_GPL(ip_icmp_error_rfc4884); |
|---|
| 1209 | + |
|---|
| 1210 | +int icmp_err(struct sk_buff *skb, u32 info) |
|---|
| 1162 | 1211 | { |
|---|
| 1163 | 1212 | struct iphdr *iph = (struct iphdr *)skb->data; |
|---|
| 1164 | 1213 | int offset = iph->ihl<<2; |
|---|
| .. | .. |
|---|
| 1173 | 1222 | */ |
|---|
| 1174 | 1223 | if (icmph->type != ICMP_ECHOREPLY) { |
|---|
| 1175 | 1224 | ping_err(skb, offset, info); |
|---|
| 1176 | | - return; |
|---|
| 1225 | + return 0; |
|---|
| 1177 | 1226 | } |
|---|
| 1178 | 1227 | |
|---|
| 1179 | 1228 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) |
|---|
| 1180 | | - ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ICMP, 0); |
|---|
| 1229 | + ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ICMP); |
|---|
| 1181 | 1230 | else if (type == ICMP_REDIRECT) |
|---|
| 1182 | | - ipv4_redirect(skb, net, 0, 0, IPPROTO_ICMP, 0); |
|---|
| 1231 | + ipv4_redirect(skb, net, 0, IPPROTO_ICMP); |
|---|
| 1232 | + |
|---|
| 1233 | + return 0; |
|---|
| 1183 | 1234 | } |
|---|
| 1184 | 1235 | |
|---|
| 1185 | 1236 | /* |
|---|
| .. | .. |
|---|
| 1322 | 1373 | return 0; |
|---|
| 1323 | 1374 | |
|---|
| 1324 | 1375 | fail: |
|---|
| 1325 | | - for_each_possible_cpu(i) |
|---|
| 1326 | | - inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv4.icmp_sk, i)); |
|---|
| 1327 | | - free_percpu(net->ipv4.icmp_sk); |
|---|
| 1376 | + icmp_sk_exit(net); |
|---|
| 1328 | 1377 | return err; |
|---|
| 1329 | 1378 | } |
|---|
| 1330 | 1379 | |
|---|