| .. | .. |
|---|
| 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 |
|---|
| .. | .. |
|---|
| 206 | 201 | */ |
|---|
| 207 | 202 | static struct sock *icmp_sk(struct net *net) |
|---|
| 208 | 203 | { |
|---|
| 209 | | - return *this_cpu_ptr(net->ipv4.icmp_sk); |
|---|
| 204 | + return this_cpu_read(*net->ipv4.icmp_sk); |
|---|
| 210 | 205 | } |
|---|
| 211 | 206 | |
|---|
| 212 | 207 | /* Called with BH disabled */ |
|---|
| .. | .. |
|---|
| 266 | 261 | spin_lock(&icmp_global.lock); |
|---|
| 267 | 262 | delta = min_t(u32, now - icmp_global.stamp, HZ); |
|---|
| 268 | 263 | if (delta >= HZ / 50) { |
|---|
| 269 | | - incr = sysctl_icmp_msgs_per_sec * delta / HZ ; |
|---|
| 264 | + incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ; |
|---|
| 270 | 265 | if (incr) |
|---|
| 271 | 266 | WRITE_ONCE(icmp_global.stamp, now); |
|---|
| 272 | 267 | } |
|---|
| 273 | | - 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)); |
|---|
| 274 | 270 | if (credit) { |
|---|
| 275 | 271 | /* We want to use a credit of one in average, but need to randomize |
|---|
| 276 | 272 | * it for security reasons. |
|---|
| .. | .. |
|---|
| 294 | 290 | return true; |
|---|
| 295 | 291 | |
|---|
| 296 | 292 | /* Limit if icmp type is enabled in ratemask. */ |
|---|
| 297 | | - if (!((1 << type) & net->ipv4.sysctl_icmp_ratemask)) |
|---|
| 293 | + if (!((1 << type) & READ_ONCE(net->ipv4.sysctl_icmp_ratemask))) |
|---|
| 298 | 294 | return true; |
|---|
| 299 | 295 | |
|---|
| 300 | 296 | return false; |
|---|
| .. | .. |
|---|
| 332 | 328 | |
|---|
| 333 | 329 | vif = l3mdev_master_ifindex(dst->dev); |
|---|
| 334 | 330 | peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1); |
|---|
| 335 | | - 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)); |
|---|
| 336 | 333 | if (peer) |
|---|
| 337 | 334 | inet_putpeer(peer); |
|---|
| 338 | 335 | out: |
|---|
| .. | .. |
|---|
| 360 | 357 | |
|---|
| 361 | 358 | csum = skb_copy_and_csum_bits(icmp_param->skb, |
|---|
| 362 | 359 | icmp_param->offset + offset, |
|---|
| 363 | | - to, len, 0); |
|---|
| 360 | + to, len); |
|---|
| 364 | 361 | |
|---|
| 365 | 362 | skb->csum = csum_block_add(skb->csum, csum, odd); |
|---|
| 366 | 363 | if (icmp_pointers[icmp_param->data.icmph.type].error) |
|---|
| .. | .. |
|---|
| 384 | 381 | ip_flush_pending_frames(sk); |
|---|
| 385 | 382 | } else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { |
|---|
| 386 | 383 | struct icmphdr *icmph = icmp_hdr(skb); |
|---|
| 387 | | - __wsum csum = 0; |
|---|
| 384 | + __wsum csum; |
|---|
| 388 | 385 | struct sk_buff *skb1; |
|---|
| 389 | 386 | |
|---|
| 387 | + csum = csum_partial_copy_nocheck((void *)&icmp_param->data, |
|---|
| 388 | + (char *)icmph, |
|---|
| 389 | + icmp_param->head_len); |
|---|
| 390 | 390 | skb_queue_walk(&sk->sk_write_queue, skb1) { |
|---|
| 391 | 391 | csum = csum_add(csum, skb1->csum); |
|---|
| 392 | 392 | } |
|---|
| 393 | | - csum = csum_partial_copy_nocheck((void *)&icmp_param->data, |
|---|
| 394 | | - (char *)icmph, |
|---|
| 395 | | - icmp_param->head_len, csum); |
|---|
| 396 | 393 | icmph->checksum = csum_fold(csum); |
|---|
| 397 | 394 | skb->ip_summed = CHECKSUM_NONE; |
|---|
| 398 | 395 | ip_push_pending_frames(sk, fl4); |
|---|
| .. | .. |
|---|
| 435 | 432 | |
|---|
| 436 | 433 | ipcm_init(&ipc); |
|---|
| 437 | 434 | inet->tos = ip_hdr(skb)->tos; |
|---|
| 438 | | - sk->sk_mark = mark; |
|---|
| 435 | + ipc.sockc.mark = mark; |
|---|
| 439 | 436 | daddr = ipc.addr = ip_hdr(skb)->saddr; |
|---|
| 440 | 437 | saddr = fib_compute_spec_dst(skb); |
|---|
| 441 | 438 | |
|---|
| .. | .. |
|---|
| 452 | 449 | fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); |
|---|
| 453 | 450 | fl4.flowi4_proto = IPPROTO_ICMP; |
|---|
| 454 | 451 | fl4.flowi4_oif = l3mdev_master_ifindex(skb->dev); |
|---|
| 455 | | - security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); |
|---|
| 452 | + security_skb_classify_flow(skb, flowi4_to_flowi_common(&fl4)); |
|---|
| 456 | 453 | rt = ip_route_output_key(net, &fl4); |
|---|
| 457 | 454 | if (IS_ERR(rt)) |
|---|
| 458 | 455 | goto out_unlock; |
|---|
| .. | .. |
|---|
| 508 | 505 | route_lookup_dev = icmp_get_route_lookup_dev(skb_in); |
|---|
| 509 | 506 | fl4->flowi4_oif = l3mdev_master_ifindex(route_lookup_dev); |
|---|
| 510 | 507 | |
|---|
| 511 | | - security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4)); |
|---|
| 508 | + security_skb_classify_flow(skb_in, flowi4_to_flowi_common(fl4)); |
|---|
| 512 | 509 | rt = ip_route_output_key_hash(net, fl4, skb_in); |
|---|
| 513 | 510 | if (IS_ERR(rt)) |
|---|
| 514 | 511 | return rt; |
|---|
| .. | .. |
|---|
| 710 | 707 | dev = dev_get_by_index_rcu(net, inet_iif(skb_in)); |
|---|
| 711 | 708 | |
|---|
| 712 | 709 | if (dev) |
|---|
| 713 | | - saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); |
|---|
| 710 | + saddr = inet_select_addr(dev, iph->saddr, |
|---|
| 711 | + RT_SCOPE_LINK); |
|---|
| 714 | 712 | else |
|---|
| 715 | 713 | saddr = 0; |
|---|
| 716 | 714 | rcu_read_unlock(); |
|---|
| 717 | 715 | } |
|---|
| 718 | 716 | |
|---|
| 719 | | - tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) | |
|---|
| 717 | + tos = icmp_pointers[type].error ? (RT_TOS(iph->tos) | |
|---|
| 720 | 718 | IPTOS_PREC_INTERNETCONTROL) : |
|---|
| 721 | | - iph->tos; |
|---|
| 719 | + iph->tos; |
|---|
| 722 | 720 | mark = IP4_REPLY_MARK(net, skb_in->mark); |
|---|
| 723 | 721 | |
|---|
| 724 | 722 | if (__ip_options_echo(net, &icmp_param.replyopts.opt.opt, skb_in, opt)) |
|---|
| .. | .. |
|---|
| 736 | 734 | icmp_param.skb = skb_in; |
|---|
| 737 | 735 | icmp_param.offset = skb_network_offset(skb_in); |
|---|
| 738 | 736 | inet_sk(sk)->tos = tos; |
|---|
| 739 | | - sk->sk_mark = mark; |
|---|
| 740 | 737 | ipcm_init(&ipc); |
|---|
| 741 | 738 | ipc.addr = iph->saddr; |
|---|
| 742 | 739 | ipc.opt = &icmp_param.replyopts.opt; |
|---|
| 740 | + ipc.sockc.mark = mark; |
|---|
| 743 | 741 | |
|---|
| 744 | 742 | rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, mark, |
|---|
| 745 | 743 | type, code, &icmp_param); |
|---|
| .. | .. |
|---|
| 818 | 816 | |
|---|
| 819 | 817 | static void icmp_socket_deliver(struct sk_buff *skb, u32 info) |
|---|
| 820 | 818 | { |
|---|
| 821 | | - const struct iphdr *iph = (const struct iphdr *) skb->data; |
|---|
| 819 | + const struct iphdr *iph = (const struct iphdr *)skb->data; |
|---|
| 822 | 820 | const struct net_protocol *ipprot; |
|---|
| 823 | 821 | int protocol = iph->protocol; |
|---|
| 824 | 822 | |
|---|
| .. | .. |
|---|
| 887 | 885 | case ICMP_FRAG_NEEDED: |
|---|
| 888 | 886 | /* for documentation of the ip_no_pmtu_disc |
|---|
| 889 | 887 | * values please see |
|---|
| 890 | | - * Documentation/networking/ip-sysctl.txt |
|---|
| 888 | + * Documentation/networking/ip-sysctl.rst |
|---|
| 891 | 889 | */ |
|---|
| 892 | | - switch (net->ipv4.sysctl_ip_no_pmtu_disc) { |
|---|
| 890 | + switch (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc)) { |
|---|
| 893 | 891 | default: |
|---|
| 894 | 892 | net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n", |
|---|
| 895 | 893 | &iph->daddr); |
|---|
| .. | .. |
|---|
| 899 | 897 | case 3: |
|---|
| 900 | 898 | if (!icmp_tag_validation(iph->protocol)) |
|---|
| 901 | 899 | goto out; |
|---|
| 902 | | - /* fall through */ |
|---|
| 900 | + fallthrough; |
|---|
| 903 | 901 | case 0: |
|---|
| 904 | 902 | info = ntohs(icmph->un.frag.mtu); |
|---|
| 905 | 903 | } |
|---|
| .. | .. |
|---|
| 977 | 975 | return false; |
|---|
| 978 | 976 | } |
|---|
| 979 | 977 | |
|---|
| 980 | | - icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway); |
|---|
| 978 | + icmp_socket_deliver(skb, ntohl(icmp_hdr(skb)->un.gateway)); |
|---|
| 981 | 979 | return true; |
|---|
| 982 | 980 | } |
|---|
| 983 | 981 | |
|---|
| .. | .. |
|---|
| 1150 | 1148 | goto drop; |
|---|
| 1151 | 1149 | } |
|---|
| 1152 | 1150 | |
|---|
| 1153 | | -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) |
|---|
| 1154 | 1211 | { |
|---|
| 1155 | 1212 | struct iphdr *iph = (struct iphdr *)skb->data; |
|---|
| 1156 | 1213 | int offset = iph->ihl<<2; |
|---|
| .. | .. |
|---|
| 1165 | 1222 | */ |
|---|
| 1166 | 1223 | if (icmph->type != ICMP_ECHOREPLY) { |
|---|
| 1167 | 1224 | ping_err(skb, offset, info); |
|---|
| 1168 | | - return; |
|---|
| 1225 | + return 0; |
|---|
| 1169 | 1226 | } |
|---|
| 1170 | 1227 | |
|---|
| 1171 | 1228 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) |
|---|
| 1172 | | - ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ICMP, 0); |
|---|
| 1229 | + ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ICMP); |
|---|
| 1173 | 1230 | else if (type == ICMP_REDIRECT) |
|---|
| 1174 | | - ipv4_redirect(skb, net, 0, 0, IPPROTO_ICMP, 0); |
|---|
| 1231 | + ipv4_redirect(skb, net, 0, IPPROTO_ICMP); |
|---|
| 1232 | + |
|---|
| 1233 | + return 0; |
|---|
| 1175 | 1234 | } |
|---|
| 1176 | 1235 | |
|---|
| 1177 | 1236 | /* |
|---|
| .. | .. |
|---|
| 1314 | 1373 | return 0; |
|---|
| 1315 | 1374 | |
|---|
| 1316 | 1375 | fail: |
|---|
| 1317 | | - for_each_possible_cpu(i) |
|---|
| 1318 | | - inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv4.icmp_sk, i)); |
|---|
| 1319 | | - free_percpu(net->ipv4.icmp_sk); |
|---|
| 1376 | + icmp_sk_exit(net); |
|---|
| 1320 | 1377 | return err; |
|---|
| 1321 | 1378 | } |
|---|
| 1322 | 1379 | |
|---|