| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * INET An implementation of the TCP/IP protocol suite for the LINUX |
|---|
| 3 | 4 | * operating system. INET is implemented using the BSD Socket |
|---|
| .. | .. |
|---|
| 30 | 31 | * Alan Cox : Added IP_HDRINCL option. |
|---|
| 31 | 32 | * Alan Cox : Skip broadcast check if BSDism set. |
|---|
| 32 | 33 | * David S. Miller : New socket lookup architecture. |
|---|
| 33 | | - * |
|---|
| 34 | | - * This program is free software; you can redistribute it and/or |
|---|
| 35 | | - * modify it under the terms of the GNU General Public License |
|---|
| 36 | | - * as published by the Free Software Foundation; either version |
|---|
| 37 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 38 | 34 | */ |
|---|
| 39 | 35 | |
|---|
| 40 | 36 | #include <linux/types.h> |
|---|
| .. | .. |
|---|
| 131 | 127 | if (net_eq(sock_net(sk), net) && inet->inet_num == num && |
|---|
| 132 | 128 | !(inet->inet_daddr && inet->inet_daddr != raddr) && |
|---|
| 133 | 129 | !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && |
|---|
| 134 | | - !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif && |
|---|
| 135 | | - sk->sk_bound_dev_if != sdif)) |
|---|
| 130 | + raw_sk_bound_dev_eq(net, sk->sk_bound_dev_if, dif, sdif)) |
|---|
| 136 | 131 | goto found; /* gotcha */ |
|---|
| 137 | 132 | } |
|---|
| 138 | 133 | sk = NULL; |
|---|
| .. | .. |
|---|
| 265 | 260 | err = EHOSTUNREACH; |
|---|
| 266 | 261 | if (code > NR_ICMP_UNREACH) |
|---|
| 267 | 262 | break; |
|---|
| 268 | | - err = icmp_err_convert[code].errno; |
|---|
| 269 | | - harderr = icmp_err_convert[code].fatal; |
|---|
| 270 | 263 | if (code == ICMP_FRAG_NEEDED) { |
|---|
| 271 | 264 | harderr = inet->pmtudisc != IP_PMTUDISC_DONT; |
|---|
| 272 | 265 | err = EMSGSIZE; |
|---|
| 266 | + } else { |
|---|
| 267 | + err = icmp_err_convert[code].errno; |
|---|
| 268 | + harderr = icmp_err_convert[code].fatal; |
|---|
| 273 | 269 | } |
|---|
| 274 | 270 | } |
|---|
| 275 | 271 | |
|---|
| .. | .. |
|---|
| 337 | 333 | kfree_skb(skb); |
|---|
| 338 | 334 | return NET_RX_DROP; |
|---|
| 339 | 335 | } |
|---|
| 340 | | - nf_reset(skb); |
|---|
| 336 | + nf_reset_ct(skb); |
|---|
| 341 | 337 | |
|---|
| 342 | 338 | skb_push(skb, skb->data - skb_network_header(skb)); |
|---|
| 343 | 339 | |
|---|
| .. | .. |
|---|
| 380 | 376 | skb_reserve(skb, hlen); |
|---|
| 381 | 377 | |
|---|
| 382 | 378 | skb->priority = sk->sk_priority; |
|---|
| 383 | | - skb->mark = sk->sk_mark; |
|---|
| 379 | + skb->mark = sockc->mark; |
|---|
| 384 | 380 | skb->tstamp = sockc->transmit_time; |
|---|
| 385 | 381 | skb_dst_set(skb, &rt->dst); |
|---|
| 386 | 382 | *rtp = NULL; |
|---|
| .. | .. |
|---|
| 391 | 387 | |
|---|
| 392 | 388 | skb->ip_summed = CHECKSUM_NONE; |
|---|
| 393 | 389 | |
|---|
| 394 | | - sock_tx_timestamp(sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags); |
|---|
| 390 | + skb_setup_tx_timestamp(skb, sockc->tsflags); |
|---|
| 395 | 391 | |
|---|
| 396 | 392 | if (flags & MSG_CONFIRM) |
|---|
| 397 | 393 | skb_set_dst_pending_confirm(skb, 1); |
|---|
| .. | .. |
|---|
| 483 | 479 | skb->csum = csum_block_add( |
|---|
| 484 | 480 | skb->csum, |
|---|
| 485 | 481 | csum_partial_copy_nocheck(rfv->hdr.c + offset, |
|---|
| 486 | | - to, copy, 0), |
|---|
| 482 | + to, copy), |
|---|
| 487 | 483 | odd); |
|---|
| 488 | 484 | |
|---|
| 489 | 485 | odd = 0; |
|---|
| .. | .. |
|---|
| 608 | 604 | tos |= RTO_ONLINK; |
|---|
| 609 | 605 | |
|---|
| 610 | 606 | if (ipv4_is_multicast(daddr)) { |
|---|
| 611 | | - if (!ipc.oif) |
|---|
| 607 | + if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) |
|---|
| 612 | 608 | ipc.oif = inet->mc_index; |
|---|
| 613 | 609 | if (!saddr) |
|---|
| 614 | 610 | saddr = inet->mc_addr; |
|---|
| 615 | 611 | } else if (!ipc.oif) { |
|---|
| 616 | 612 | ipc.oif = inet->uc_index; |
|---|
| 617 | 613 | } else if (ipv4_is_lbcast(daddr) && inet->uc_index) { |
|---|
| 618 | | - /* oif is set, packet is to local broadcast and |
|---|
| 614 | + /* oif is set, packet is to local broadcast |
|---|
| 619 | 615 | * and uc_index is set. oif is most likely set |
|---|
| 620 | 616 | * by sk_bound_dev_if. If uc_index != oif check if the |
|---|
| 621 | 617 | * oif is an L3 master and uc_index is an L3 slave. |
|---|
| .. | .. |
|---|
| 628 | 624 | } |
|---|
| 629 | 625 | } |
|---|
| 630 | 626 | |
|---|
| 631 | | - flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, |
|---|
| 627 | + flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos, |
|---|
| 632 | 628 | RT_SCOPE_UNIVERSE, |
|---|
| 633 | 629 | hdrincl ? IPPROTO_RAW : sk->sk_protocol, |
|---|
| 634 | 630 | inet_sk_flowi_flags(sk) | |
|---|
| .. | .. |
|---|
| 644 | 640 | goto done; |
|---|
| 645 | 641 | } |
|---|
| 646 | 642 | |
|---|
| 647 | | - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); |
|---|
| 643 | + security_sk_classify_flow(sk, flowi4_to_flowi_common(&fl4)); |
|---|
| 648 | 644 | rt = ip_route_output_flow(net, &fl4, sk); |
|---|
| 649 | 645 | if (IS_ERR(rt)) { |
|---|
| 650 | 646 | err = PTR_ERR(rt); |
|---|
| .. | .. |
|---|
| 808 | 804 | return copied; |
|---|
| 809 | 805 | } |
|---|
| 810 | 806 | |
|---|
| 811 | | -static int raw_init(struct sock *sk) |
|---|
| 807 | +static int raw_sk_init(struct sock *sk) |
|---|
| 812 | 808 | { |
|---|
| 813 | 809 | struct raw_sock *rp = raw_sk(sk); |
|---|
| 814 | 810 | |
|---|
| .. | .. |
|---|
| 817 | 813 | return 0; |
|---|
| 818 | 814 | } |
|---|
| 819 | 815 | |
|---|
| 820 | | -static int raw_seticmpfilter(struct sock *sk, char __user *optval, int optlen) |
|---|
| 816 | +static int raw_seticmpfilter(struct sock *sk, sockptr_t optval, int optlen) |
|---|
| 821 | 817 | { |
|---|
| 822 | 818 | if (optlen > sizeof(struct icmp_filter)) |
|---|
| 823 | 819 | optlen = sizeof(struct icmp_filter); |
|---|
| 824 | | - if (copy_from_user(&raw_sk(sk)->filter, optval, optlen)) |
|---|
| 820 | + if (copy_from_sockptr(&raw_sk(sk)->filter, optval, optlen)) |
|---|
| 825 | 821 | return -EFAULT; |
|---|
| 826 | 822 | return 0; |
|---|
| 827 | 823 | } |
|---|
| .. | .. |
|---|
| 846 | 842 | } |
|---|
| 847 | 843 | |
|---|
| 848 | 844 | static int do_raw_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 849 | | - char __user *optval, unsigned int optlen) |
|---|
| 845 | + sockptr_t optval, unsigned int optlen) |
|---|
| 850 | 846 | { |
|---|
| 851 | 847 | if (optname == ICMP_FILTER) { |
|---|
| 852 | 848 | if (inet_sk(sk)->inet_num != IPPROTO_ICMP) |
|---|
| .. | .. |
|---|
| 858 | 854 | } |
|---|
| 859 | 855 | |
|---|
| 860 | 856 | static int raw_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 861 | | - char __user *optval, unsigned int optlen) |
|---|
| 857 | + sockptr_t optval, unsigned int optlen) |
|---|
| 862 | 858 | { |
|---|
| 863 | 859 | if (level != SOL_RAW) |
|---|
| 864 | 860 | return ip_setsockopt(sk, level, optname, optval, optlen); |
|---|
| 865 | 861 | return do_raw_setsockopt(sk, level, optname, optval, optlen); |
|---|
| 866 | 862 | } |
|---|
| 867 | | - |
|---|
| 868 | | -#ifdef CONFIG_COMPAT |
|---|
| 869 | | -static int compat_raw_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 870 | | - char __user *optval, unsigned int optlen) |
|---|
| 871 | | -{ |
|---|
| 872 | | - if (level != SOL_RAW) |
|---|
| 873 | | - return compat_ip_setsockopt(sk, level, optname, optval, optlen); |
|---|
| 874 | | - return do_raw_setsockopt(sk, level, optname, optval, optlen); |
|---|
| 875 | | -} |
|---|
| 876 | | -#endif |
|---|
| 877 | 863 | |
|---|
| 878 | 864 | static int do_raw_getsockopt(struct sock *sk, int level, int optname, |
|---|
| 879 | 865 | char __user *optval, int __user *optlen) |
|---|
| .. | .. |
|---|
| 894 | 880 | return ip_getsockopt(sk, level, optname, optval, optlen); |
|---|
| 895 | 881 | return do_raw_getsockopt(sk, level, optname, optval, optlen); |
|---|
| 896 | 882 | } |
|---|
| 897 | | - |
|---|
| 898 | | -#ifdef CONFIG_COMPAT |
|---|
| 899 | | -static int compat_raw_getsockopt(struct sock *sk, int level, int optname, |
|---|
| 900 | | - char __user *optval, int __user *optlen) |
|---|
| 901 | | -{ |
|---|
| 902 | | - if (level != SOL_RAW) |
|---|
| 903 | | - return compat_ip_getsockopt(sk, level, optname, optval, optlen); |
|---|
| 904 | | - return do_raw_getsockopt(sk, level, optname, optval, optlen); |
|---|
| 905 | | -} |
|---|
| 906 | | -#endif |
|---|
| 907 | 883 | |
|---|
| 908 | 884 | static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) |
|---|
| 909 | 885 | { |
|---|
| .. | .. |
|---|
| 973 | 949 | .connect = ip4_datagram_connect, |
|---|
| 974 | 950 | .disconnect = __udp_disconnect, |
|---|
| 975 | 951 | .ioctl = raw_ioctl, |
|---|
| 976 | | - .init = raw_init, |
|---|
| 952 | + .init = raw_sk_init, |
|---|
| 977 | 953 | .setsockopt = raw_setsockopt, |
|---|
| 978 | 954 | .getsockopt = raw_getsockopt, |
|---|
| 979 | 955 | .sendmsg = raw_sendmsg, |
|---|
| .. | .. |
|---|
| 988 | 964 | .usersize = sizeof_field(struct raw_sock, filter), |
|---|
| 989 | 965 | .h.raw_hash = &raw_v4_hashinfo, |
|---|
| 990 | 966 | #ifdef CONFIG_COMPAT |
|---|
| 991 | | - .compat_setsockopt = compat_raw_setsockopt, |
|---|
| 992 | | - .compat_getsockopt = compat_raw_getsockopt, |
|---|
| 993 | 967 | .compat_ioctl = compat_raw_ioctl, |
|---|
| 994 | 968 | #endif |
|---|
| 995 | 969 | .diag_destroy = raw_abort, |
|---|
| .. | .. |
|---|
| 1042 | 1016 | } |
|---|
| 1043 | 1017 | |
|---|
| 1044 | 1018 | void *raw_seq_start(struct seq_file *seq, loff_t *pos) |
|---|
| 1019 | + __acquires(&h->lock) |
|---|
| 1045 | 1020 | { |
|---|
| 1046 | 1021 | struct raw_hashinfo *h = PDE_DATA(file_inode(seq->file)); |
|---|
| 1047 | 1022 | |
|---|
| .. | .. |
|---|
| 1064 | 1039 | EXPORT_SYMBOL_GPL(raw_seq_next); |
|---|
| 1065 | 1040 | |
|---|
| 1066 | 1041 | void raw_seq_stop(struct seq_file *seq, void *v) |
|---|
| 1042 | + __releases(&h->lock) |
|---|
| 1067 | 1043 | { |
|---|
| 1068 | 1044 | struct raw_hashinfo *h = PDE_DATA(file_inode(seq->file)); |
|---|
| 1069 | 1045 | |
|---|
| .. | .. |
|---|
| 1080 | 1056 | srcp = inet->inet_num; |
|---|
| 1081 | 1057 | |
|---|
| 1082 | 1058 | seq_printf(seq, "%4d: %08X:%04X %08X:%04X" |
|---|
| 1083 | | - " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n", |
|---|
| 1059 | + " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %u\n", |
|---|
| 1084 | 1060 | i, src, srcp, dest, destp, sp->sk_state, |
|---|
| 1085 | 1061 | sk_wmem_alloc_get(sp), |
|---|
| 1086 | 1062 | sk_rmem_alloc_get(sp), |
|---|
| .. | .. |
|---|
| 1137 | 1113 | unregister_pernet_subsys(&raw_net_ops); |
|---|
| 1138 | 1114 | } |
|---|
| 1139 | 1115 | #endif /* CONFIG_PROC_FS */ |
|---|
| 1116 | + |
|---|
| 1117 | +static void raw_sysctl_init_net(struct net *net) |
|---|
| 1118 | +{ |
|---|
| 1119 | +#ifdef CONFIG_NET_L3_MASTER_DEV |
|---|
| 1120 | + net->ipv4.sysctl_raw_l3mdev_accept = 1; |
|---|
| 1121 | +#endif |
|---|
| 1122 | +} |
|---|
| 1123 | + |
|---|
| 1124 | +static int __net_init raw_sysctl_init(struct net *net) |
|---|
| 1125 | +{ |
|---|
| 1126 | + raw_sysctl_init_net(net); |
|---|
| 1127 | + return 0; |
|---|
| 1128 | +} |
|---|
| 1129 | + |
|---|
| 1130 | +static struct pernet_operations __net_initdata raw_sysctl_ops = { |
|---|
| 1131 | + .init = raw_sysctl_init, |
|---|
| 1132 | +}; |
|---|
| 1133 | + |
|---|
| 1134 | +void __init raw_init(void) |
|---|
| 1135 | +{ |
|---|
| 1136 | + raw_sysctl_init_net(&init_net); |
|---|
| 1137 | + if (register_pernet_subsys(&raw_sysctl_ops)) |
|---|
| 1138 | + panic("RAW: failed to init sysctl parameters.\n"); |
|---|
| 1139 | +} |
|---|