| .. | .. |
|---|
| 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; |
|---|
| .. | .. |
|---|
| 563 | 559 | } |
|---|
| 564 | 560 | |
|---|
| 565 | 561 | ipcm_init_sk(&ipc, inet); |
|---|
| 562 | + /* Keep backward compat */ |
|---|
| 563 | + if (hdrincl) |
|---|
| 564 | + ipc.protocol = IPPROTO_RAW; |
|---|
| 566 | 565 | |
|---|
| 567 | 566 | if (msg->msg_controllen) { |
|---|
| 568 | 567 | err = ip_cmsg_send(sk, msg, &ipc, false); |
|---|
| .. | .. |
|---|
| 608 | 607 | tos |= RTO_ONLINK; |
|---|
| 609 | 608 | |
|---|
| 610 | 609 | if (ipv4_is_multicast(daddr)) { |
|---|
| 611 | | - if (!ipc.oif) |
|---|
| 610 | + if (!ipc.oif || netif_index_is_l3_master(sock_net(sk), ipc.oif)) |
|---|
| 612 | 611 | ipc.oif = inet->mc_index; |
|---|
| 613 | 612 | if (!saddr) |
|---|
| 614 | 613 | saddr = inet->mc_addr; |
|---|
| 615 | 614 | } else if (!ipc.oif) { |
|---|
| 616 | 615 | ipc.oif = inet->uc_index; |
|---|
| 617 | 616 | } else if (ipv4_is_lbcast(daddr) && inet->uc_index) { |
|---|
| 618 | | - /* oif is set, packet is to local broadcast and |
|---|
| 617 | + /* oif is set, packet is to local broadcast |
|---|
| 619 | 618 | * and uc_index is set. oif is most likely set |
|---|
| 620 | 619 | * by sk_bound_dev_if. If uc_index != oif check if the |
|---|
| 621 | 620 | * oif is an L3 master and uc_index is an L3 slave. |
|---|
| .. | .. |
|---|
| 628 | 627 | } |
|---|
| 629 | 628 | } |
|---|
| 630 | 629 | |
|---|
| 631 | | - flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, |
|---|
| 630 | + flowi4_init_output(&fl4, ipc.oif, ipc.sockc.mark, tos, |
|---|
| 632 | 631 | RT_SCOPE_UNIVERSE, |
|---|
| 633 | | - hdrincl ? IPPROTO_RAW : sk->sk_protocol, |
|---|
| 632 | + hdrincl ? ipc.protocol : sk->sk_protocol, |
|---|
| 634 | 633 | inet_sk_flowi_flags(sk) | |
|---|
| 635 | 634 | (hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), |
|---|
| 636 | 635 | daddr, saddr, 0, 0, sk->sk_uid); |
|---|
| .. | .. |
|---|
| 644 | 643 | goto done; |
|---|
| 645 | 644 | } |
|---|
| 646 | 645 | |
|---|
| 647 | | - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); |
|---|
| 646 | + security_sk_classify_flow(sk, flowi4_to_flowi_common(&fl4)); |
|---|
| 648 | 647 | rt = ip_route_output_flow(net, &fl4, sk); |
|---|
| 649 | 648 | if (IS_ERR(rt)) { |
|---|
| 650 | 649 | err = PTR_ERR(rt); |
|---|
| .. | .. |
|---|
| 808 | 807 | return copied; |
|---|
| 809 | 808 | } |
|---|
| 810 | 809 | |
|---|
| 811 | | -static int raw_init(struct sock *sk) |
|---|
| 810 | +static int raw_sk_init(struct sock *sk) |
|---|
| 812 | 811 | { |
|---|
| 813 | 812 | struct raw_sock *rp = raw_sk(sk); |
|---|
| 814 | 813 | |
|---|
| .. | .. |
|---|
| 817 | 816 | return 0; |
|---|
| 818 | 817 | } |
|---|
| 819 | 818 | |
|---|
| 820 | | -static int raw_seticmpfilter(struct sock *sk, char __user *optval, int optlen) |
|---|
| 819 | +static int raw_seticmpfilter(struct sock *sk, sockptr_t optval, int optlen) |
|---|
| 821 | 820 | { |
|---|
| 822 | 821 | if (optlen > sizeof(struct icmp_filter)) |
|---|
| 823 | 822 | optlen = sizeof(struct icmp_filter); |
|---|
| 824 | | - if (copy_from_user(&raw_sk(sk)->filter, optval, optlen)) |
|---|
| 823 | + if (copy_from_sockptr(&raw_sk(sk)->filter, optval, optlen)) |
|---|
| 825 | 824 | return -EFAULT; |
|---|
| 826 | 825 | return 0; |
|---|
| 827 | 826 | } |
|---|
| .. | .. |
|---|
| 846 | 845 | } |
|---|
| 847 | 846 | |
|---|
| 848 | 847 | static int do_raw_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 849 | | - char __user *optval, unsigned int optlen) |
|---|
| 848 | + sockptr_t optval, unsigned int optlen) |
|---|
| 850 | 849 | { |
|---|
| 851 | 850 | if (optname == ICMP_FILTER) { |
|---|
| 852 | 851 | if (inet_sk(sk)->inet_num != IPPROTO_ICMP) |
|---|
| .. | .. |
|---|
| 858 | 857 | } |
|---|
| 859 | 858 | |
|---|
| 860 | 859 | static int raw_setsockopt(struct sock *sk, int level, int optname, |
|---|
| 861 | | - char __user *optval, unsigned int optlen) |
|---|
| 860 | + sockptr_t optval, unsigned int optlen) |
|---|
| 862 | 861 | { |
|---|
| 863 | 862 | if (level != SOL_RAW) |
|---|
| 864 | 863 | return ip_setsockopt(sk, level, optname, optval, optlen); |
|---|
| 865 | 864 | return do_raw_setsockopt(sk, level, optname, optval, optlen); |
|---|
| 866 | 865 | } |
|---|
| 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 | 866 | |
|---|
| 878 | 867 | static int do_raw_getsockopt(struct sock *sk, int level, int optname, |
|---|
| 879 | 868 | char __user *optval, int __user *optlen) |
|---|
| .. | .. |
|---|
| 894 | 883 | return ip_getsockopt(sk, level, optname, optval, optlen); |
|---|
| 895 | 884 | return do_raw_getsockopt(sk, level, optname, optval, optlen); |
|---|
| 896 | 885 | } |
|---|
| 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 | 886 | |
|---|
| 908 | 887 | static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) |
|---|
| 909 | 888 | { |
|---|
| .. | .. |
|---|
| 973 | 952 | .connect = ip4_datagram_connect, |
|---|
| 974 | 953 | .disconnect = __udp_disconnect, |
|---|
| 975 | 954 | .ioctl = raw_ioctl, |
|---|
| 976 | | - .init = raw_init, |
|---|
| 955 | + .init = raw_sk_init, |
|---|
| 977 | 956 | .setsockopt = raw_setsockopt, |
|---|
| 978 | 957 | .getsockopt = raw_getsockopt, |
|---|
| 979 | 958 | .sendmsg = raw_sendmsg, |
|---|
| .. | .. |
|---|
| 988 | 967 | .usersize = sizeof_field(struct raw_sock, filter), |
|---|
| 989 | 968 | .h.raw_hash = &raw_v4_hashinfo, |
|---|
| 990 | 969 | #ifdef CONFIG_COMPAT |
|---|
| 991 | | - .compat_setsockopt = compat_raw_setsockopt, |
|---|
| 992 | | - .compat_getsockopt = compat_raw_getsockopt, |
|---|
| 993 | 970 | .compat_ioctl = compat_raw_ioctl, |
|---|
| 994 | 971 | #endif |
|---|
| 995 | 972 | .diag_destroy = raw_abort, |
|---|
| .. | .. |
|---|
| 1042 | 1019 | } |
|---|
| 1043 | 1020 | |
|---|
| 1044 | 1021 | void *raw_seq_start(struct seq_file *seq, loff_t *pos) |
|---|
| 1022 | + __acquires(&h->lock) |
|---|
| 1045 | 1023 | { |
|---|
| 1046 | 1024 | struct raw_hashinfo *h = PDE_DATA(file_inode(seq->file)); |
|---|
| 1047 | 1025 | |
|---|
| .. | .. |
|---|
| 1064 | 1042 | EXPORT_SYMBOL_GPL(raw_seq_next); |
|---|
| 1065 | 1043 | |
|---|
| 1066 | 1044 | void raw_seq_stop(struct seq_file *seq, void *v) |
|---|
| 1045 | + __releases(&h->lock) |
|---|
| 1067 | 1046 | { |
|---|
| 1068 | 1047 | struct raw_hashinfo *h = PDE_DATA(file_inode(seq->file)); |
|---|
| 1069 | 1048 | |
|---|
| .. | .. |
|---|
| 1080 | 1059 | srcp = inet->inet_num; |
|---|
| 1081 | 1060 | |
|---|
| 1082 | 1061 | seq_printf(seq, "%4d: %08X:%04X %08X:%04X" |
|---|
| 1083 | | - " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n", |
|---|
| 1062 | + " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %u\n", |
|---|
| 1084 | 1063 | i, src, srcp, dest, destp, sp->sk_state, |
|---|
| 1085 | 1064 | sk_wmem_alloc_get(sp), |
|---|
| 1086 | 1065 | sk_rmem_alloc_get(sp), |
|---|
| .. | .. |
|---|
| 1137 | 1116 | unregister_pernet_subsys(&raw_net_ops); |
|---|
| 1138 | 1117 | } |
|---|
| 1139 | 1118 | #endif /* CONFIG_PROC_FS */ |
|---|
| 1119 | + |
|---|
| 1120 | +static void raw_sysctl_init_net(struct net *net) |
|---|
| 1121 | +{ |
|---|
| 1122 | +#ifdef CONFIG_NET_L3_MASTER_DEV |
|---|
| 1123 | + net->ipv4.sysctl_raw_l3mdev_accept = 1; |
|---|
| 1124 | +#endif |
|---|
| 1125 | +} |
|---|
| 1126 | + |
|---|
| 1127 | +static int __net_init raw_sysctl_init(struct net *net) |
|---|
| 1128 | +{ |
|---|
| 1129 | + raw_sysctl_init_net(net); |
|---|
| 1130 | + return 0; |
|---|
| 1131 | +} |
|---|
| 1132 | + |
|---|
| 1133 | +static struct pernet_operations __net_initdata raw_sysctl_ops = { |
|---|
| 1134 | + .init = raw_sysctl_init, |
|---|
| 1135 | +}; |
|---|
| 1136 | + |
|---|
| 1137 | +void __init raw_init(void) |
|---|
| 1138 | +{ |
|---|
| 1139 | + raw_sysctl_init_net(&init_net); |
|---|
| 1140 | + if (register_pernet_subsys(&raw_sysctl_ops)) |
|---|
| 1141 | + panic("RAW: failed to init sysctl parameters.\n"); |
|---|
| 1142 | +} |
|---|