.. | .. |
---|
| 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); |
---|
.. | .. |
---|
757 | 755 | room = 576; |
---|
758 | 756 | room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen; |
---|
759 | 757 | room -= sizeof(struct icmphdr); |
---|
| 758 | + /* Guard against tiny mtu. We need to include at least one |
---|
| 759 | + * IP network header for this message to make any sense. |
---|
| 760 | + */ |
---|
| 761 | + if (room <= (int)sizeof(struct iphdr)) |
---|
| 762 | + goto ende; |
---|
760 | 763 | |
---|
761 | 764 | icmp_param.data_len = skb_in->len - icmp_param.offset; |
---|
762 | 765 | if (icmp_param.data_len > room) |
---|
.. | .. |
---|
818 | 821 | |
---|
819 | 822 | static void icmp_socket_deliver(struct sk_buff *skb, u32 info) |
---|
820 | 823 | { |
---|
821 | | - const struct iphdr *iph = (const struct iphdr *) skb->data; |
---|
| 824 | + const struct iphdr *iph = (const struct iphdr *)skb->data; |
---|
822 | 825 | const struct net_protocol *ipprot; |
---|
823 | 826 | int protocol = iph->protocol; |
---|
824 | 827 | |
---|
.. | .. |
---|
887 | 890 | case ICMP_FRAG_NEEDED: |
---|
888 | 891 | /* for documentation of the ip_no_pmtu_disc |
---|
889 | 892 | * values please see |
---|
890 | | - * Documentation/networking/ip-sysctl.txt |
---|
| 893 | + * Documentation/networking/ip-sysctl.rst |
---|
891 | 894 | */ |
---|
892 | | - switch (net->ipv4.sysctl_ip_no_pmtu_disc) { |
---|
| 895 | + switch (READ_ONCE(net->ipv4.sysctl_ip_no_pmtu_disc)) { |
---|
893 | 896 | default: |
---|
894 | 897 | net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n", |
---|
895 | 898 | &iph->daddr); |
---|
.. | .. |
---|
899 | 902 | case 3: |
---|
900 | 903 | if (!icmp_tag_validation(iph->protocol)) |
---|
901 | 904 | goto out; |
---|
902 | | - /* fall through */ |
---|
| 905 | + fallthrough; |
---|
903 | 906 | case 0: |
---|
904 | 907 | info = ntohs(icmph->un.frag.mtu); |
---|
905 | 908 | } |
---|
.. | .. |
---|
977 | 980 | return false; |
---|
978 | 981 | } |
---|
979 | 982 | |
---|
980 | | - icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway); |
---|
| 983 | + icmp_socket_deliver(skb, ntohl(icmp_hdr(skb)->un.gateway)); |
---|
981 | 984 | return true; |
---|
982 | 985 | } |
---|
983 | 986 | |
---|
.. | .. |
---|
1150 | 1153 | goto drop; |
---|
1151 | 1154 | } |
---|
1152 | 1155 | |
---|
1153 | | -void icmp_err(struct sk_buff *skb, u32 info) |
---|
| 1156 | +static bool ip_icmp_error_rfc4884_validate(const struct sk_buff *skb, int off) |
---|
| 1157 | +{ |
---|
| 1158 | + struct icmp_extobj_hdr *objh, _objh; |
---|
| 1159 | + struct icmp_ext_hdr *exth, _exth; |
---|
| 1160 | + u16 olen; |
---|
| 1161 | + |
---|
| 1162 | + exth = skb_header_pointer(skb, off, sizeof(_exth), &_exth); |
---|
| 1163 | + if (!exth) |
---|
| 1164 | + return false; |
---|
| 1165 | + if (exth->version != 2) |
---|
| 1166 | + return true; |
---|
| 1167 | + |
---|
| 1168 | + if (exth->checksum && |
---|
| 1169 | + csum_fold(skb_checksum(skb, off, skb->len - off, 0))) |
---|
| 1170 | + return false; |
---|
| 1171 | + |
---|
| 1172 | + off += sizeof(_exth); |
---|
| 1173 | + while (off < skb->len) { |
---|
| 1174 | + objh = skb_header_pointer(skb, off, sizeof(_objh), &_objh); |
---|
| 1175 | + if (!objh) |
---|
| 1176 | + return false; |
---|
| 1177 | + |
---|
| 1178 | + olen = ntohs(objh->length); |
---|
| 1179 | + if (olen < sizeof(_objh)) |
---|
| 1180 | + return false; |
---|
| 1181 | + |
---|
| 1182 | + off += olen; |
---|
| 1183 | + if (off > skb->len) |
---|
| 1184 | + return false; |
---|
| 1185 | + } |
---|
| 1186 | + |
---|
| 1187 | + return true; |
---|
| 1188 | +} |
---|
| 1189 | + |
---|
| 1190 | +void ip_icmp_error_rfc4884(const struct sk_buff *skb, |
---|
| 1191 | + struct sock_ee_data_rfc4884 *out, |
---|
| 1192 | + int thlen, int off) |
---|
| 1193 | +{ |
---|
| 1194 | + int hlen; |
---|
| 1195 | + |
---|
| 1196 | + /* original datagram headers: end of icmph to payload (skb->data) */ |
---|
| 1197 | + hlen = -skb_transport_offset(skb) - thlen; |
---|
| 1198 | + |
---|
| 1199 | + /* per rfc 4884: minimal datagram length of 128 bytes */ |
---|
| 1200 | + if (off < 128 || off < hlen) |
---|
| 1201 | + return; |
---|
| 1202 | + |
---|
| 1203 | + /* kernel has stripped headers: return payload offset in bytes */ |
---|
| 1204 | + off -= hlen; |
---|
| 1205 | + if (off + sizeof(struct icmp_ext_hdr) > skb->len) |
---|
| 1206 | + return; |
---|
| 1207 | + |
---|
| 1208 | + out->len = off; |
---|
| 1209 | + |
---|
| 1210 | + if (!ip_icmp_error_rfc4884_validate(skb, off)) |
---|
| 1211 | + out->flags |= SO_EE_RFC4884_FLAG_INVALID; |
---|
| 1212 | +} |
---|
| 1213 | +EXPORT_SYMBOL_GPL(ip_icmp_error_rfc4884); |
---|
| 1214 | + |
---|
| 1215 | +int icmp_err(struct sk_buff *skb, u32 info) |
---|
1154 | 1216 | { |
---|
1155 | 1217 | struct iphdr *iph = (struct iphdr *)skb->data; |
---|
1156 | 1218 | int offset = iph->ihl<<2; |
---|
.. | .. |
---|
1165 | 1227 | */ |
---|
1166 | 1228 | if (icmph->type != ICMP_ECHOREPLY) { |
---|
1167 | 1229 | ping_err(skb, offset, info); |
---|
1168 | | - return; |
---|
| 1230 | + return 0; |
---|
1169 | 1231 | } |
---|
1170 | 1232 | |
---|
1171 | 1233 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) |
---|
1172 | | - ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ICMP, 0); |
---|
| 1234 | + ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ICMP); |
---|
1173 | 1235 | else if (type == ICMP_REDIRECT) |
---|
1174 | | - ipv4_redirect(skb, net, 0, 0, IPPROTO_ICMP, 0); |
---|
| 1236 | + ipv4_redirect(skb, net, 0, IPPROTO_ICMP); |
---|
| 1237 | + |
---|
| 1238 | + return 0; |
---|
1175 | 1239 | } |
---|
1176 | 1240 | |
---|
1177 | 1241 | /* |
---|
.. | .. |
---|
1314 | 1378 | return 0; |
---|
1315 | 1379 | |
---|
1316 | 1380 | 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); |
---|
| 1381 | + icmp_sk_exit(net); |
---|
1320 | 1382 | return err; |
---|
1321 | 1383 | } |
---|
1322 | 1384 | |
---|