hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
kernel/net/ipv4/ping.c
....@@ -1,14 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * INET An implementation of the TCP/IP protocol suite for the LINUX
34 * operating system. INET is implemented using the BSD Socket
45 * interface as the means of communication with the user level.
56 *
67 * "Ping" sockets
7
- *
8
- * This program is free software; you can redistribute it and/or
9
- * modify it under the terms of the GNU General Public License
10
- * as published by the Free Software Foundation; either version
11
- * 2 of the License, or (at your option) any later version.
128 *
139 * Based on ipv4/udp.c code.
1410 *
....@@ -17,7 +13,6 @@
1713 *
1814 * Pavel gave all rights to bugs to Vasiliy,
1915 * none of the bugs are Pavel's now.
20
- *
2116 */
2217
2318 #include <linux/uaccess.h>
....@@ -305,10 +300,12 @@
305300
306301 /* Checks the bind address and possibly modifies sk->sk_bound_dev_if. */
307302 static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk,
308
- struct sockaddr *uaddr, int addr_len) {
303
+ struct sockaddr *uaddr, int addr_len)
304
+{
309305 struct net *net = sock_net(sk);
310306 if (sk->sk_family == AF_INET) {
311307 struct sockaddr_in *addr = (struct sockaddr_in *) uaddr;
308
+ u32 tb_id = RT_TABLE_LOCAL;
312309 int chk_addr_ret;
313310
314311 if (addr_len < sizeof(*addr))
....@@ -322,10 +319,12 @@
322319 pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n",
323320 sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port));
324321
325
- chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr);
326
-
327322 if (addr->sin_addr.s_addr == htonl(INADDR_ANY))
328323 chk_addr_ret = RTN_LOCAL;
324
+ else {
325
+ tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ? : tb_id;
326
+ chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id);
327
+ }
329328
330329 if ((!inet_can_nonlocal_bind(net, isk) &&
331330 chk_addr_ret != RTN_LOCAL) ||
....@@ -363,6 +362,14 @@
363362 return -ENODEV;
364363 }
365364 }
365
+
366
+ if (!dev && sk->sk_bound_dev_if) {
367
+ dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if);
368
+ if (!dev) {
369
+ rcu_read_unlock();
370
+ return -ENODEV;
371
+ }
372
+ }
366373 has_addr = pingv6_ops.ipv6_chk_addr(net, &addr->sin6_addr, dev,
367374 scoped);
368375 rcu_read_unlock();
....@@ -395,20 +402,6 @@
395402 }
396403 }
397404
398
-static void ping_clear_saddr(struct sock *sk, int dif)
399
-{
400
- sk->sk_bound_dev_if = dif;
401
- if (sk->sk_family == AF_INET) {
402
- struct inet_sock *isk = inet_sk(sk);
403
- isk->inet_rcv_saddr = isk->inet_saddr = 0;
404
-#if IS_ENABLED(CONFIG_IPV6)
405
- } else if (sk->sk_family == AF_INET6) {
406
- struct ipv6_pinfo *np = inet6_sk(sk);
407
- memset(&sk->sk_v6_rcv_saddr, 0, sizeof(sk->sk_v6_rcv_saddr));
408
- memset(&np->saddr, 0, sizeof(np->saddr));
409
-#endif
410
- }
411
-}
412405 /*
413406 * We need our own bind because there are no privileged id's == local ports.
414407 * Moreover, we don't allow binding to multi- and broadcast addresses.
....@@ -432,12 +425,13 @@
432425 goto out;
433426
434427 err = -EADDRINUSE;
435
- ping_set_saddr(sk, uaddr);
436428 snum = ntohs(((struct sockaddr_in *)uaddr)->sin_port);
437429 if (ping_get_port(sk, snum) != 0) {
438
- ping_clear_saddr(sk, dif);
430
+ /* Restore possibly modified sk->sk_bound_dev_if by ping_check_bind_addr(). */
431
+ sk->sk_bound_dev_if = dif;
439432 goto out;
440433 }
434
+ ping_set_saddr(sk, uaddr);
441435
442436 pr_debug("after bind(): num = %hu, dif = %d\n",
443437 isk->inet_num,
....@@ -659,7 +653,8 @@
659653 }
660654
661655 int ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
662
- void *user_icmph, size_t icmph_len) {
656
+ void *user_icmph, size_t icmph_len)
657
+{
663658 u8 type, code;
664659
665660 if (len > 0xFFFF)
....@@ -786,14 +781,14 @@
786781 }
787782
788783 if (ipv4_is_multicast(daddr)) {
789
- if (!ipc.oif)
784
+ if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif))
790785 ipc.oif = inet->mc_index;
791786 if (!saddr)
792787 saddr = inet->mc_addr;
793788 } else if (!ipc.oif)
794789 ipc.oif = inet->uc_index;
795790
796
- flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
791
+ flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos,
797792 RT_SCOPE_UNIVERSE, sk->sk_protocol,
798793 inet_sk_flowi_flags(sk), faddr, saddr, 0, 0,
799794 sk->sk_uid);
....@@ -801,7 +796,7 @@
801796 fl4.fl4_icmp_type = user_icmph.type;
802797 fl4.fl4_icmp_code = user_icmph.code;
803798
804
- security_sk_classify_flow(sk, flowi4_to_flowi(&fl4));
799
+ security_sk_classify_flow(sk, flowi4_to_flowi_common(&fl4));
805800 rt = ip_route_output_flow(net, &fl4, sk);
806801 if (IS_ERR(rt)) {
807802 err = PTR_ERR(rt);
....@@ -1125,7 +1120,7 @@
11251120 __u16 srcp = ntohs(inet->inet_sport);
11261121
11271122 seq_printf(f, "%5d: %08X:%04X %08X:%04X"
1128
- " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d",
1123
+ " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %u",
11291124 bucket, src, srcp, dest, destp, sp->sk_state,
11301125 sk_wmem_alloc_get(sp),
11311126 sk_rmem_alloc_get(sp),