| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * NETLINK Kernel-user communication protocol. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Authors: Alan Cox <alan@lxorguk.ukuu.org.uk> |
|---|
| 5 | 6 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> |
|---|
| 6 | 7 | * Patrick McHardy <kaber@trash.net> |
|---|
| 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. |
|---|
| 12 | 8 | * |
|---|
| 13 | 9 | * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith |
|---|
| 14 | 10 | * added netlink_proto_exit |
|---|
| .. | .. |
|---|
| 64 | 60 | #include <linux/genetlink.h> |
|---|
| 65 | 61 | #include <linux/net_namespace.h> |
|---|
| 66 | 62 | #include <linux/nospec.h> |
|---|
| 63 | +#include <linux/btf_ids.h> |
|---|
| 67 | 64 | |
|---|
| 68 | 65 | #include <net/net_namespace.h> |
|---|
| 69 | 66 | #include <net/netns/generic.h> |
|---|
| .. | .. |
|---|
| 75 | 72 | |
|---|
| 76 | 73 | struct listeners { |
|---|
| 77 | 74 | struct rcu_head rcu; |
|---|
| 78 | | - unsigned long masks[0]; |
|---|
| 75 | + unsigned long masks[]; |
|---|
| 79 | 76 | }; |
|---|
| 80 | 77 | |
|---|
| 81 | 78 | /* state bits */ |
|---|
| .. | .. |
|---|
| 152 | 149 | |
|---|
| 153 | 150 | static inline u32 netlink_group_mask(u32 group) |
|---|
| 154 | 151 | { |
|---|
| 152 | + if (group > 32) |
|---|
| 153 | + return 0; |
|---|
| 155 | 154 | return group ? 1 << (group - 1) : 0; |
|---|
| 156 | 155 | } |
|---|
| 157 | 156 | |
|---|
| .. | .. |
|---|
| 245 | 244 | return 0; |
|---|
| 246 | 245 | } |
|---|
| 247 | 246 | |
|---|
| 248 | | -static void __net_exit netlink_tap_exit_net(struct net *net) |
|---|
| 249 | | -{ |
|---|
| 250 | | -} |
|---|
| 251 | | - |
|---|
| 252 | 247 | static struct pernet_operations netlink_tap_net_ops = { |
|---|
| 253 | 248 | .init = netlink_tap_init_net, |
|---|
| 254 | | - .exit = netlink_tap_exit_net, |
|---|
| 255 | 249 | .id = &netlink_tap_net_id, |
|---|
| 256 | 250 | .size = sizeof(struct netlink_tap_net), |
|---|
| 257 | 251 | }; |
|---|
| .. | .. |
|---|
| 361 | 355 | { |
|---|
| 362 | 356 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| 363 | 357 | |
|---|
| 364 | | - if (skb_queue_empty(&sk->sk_receive_queue)) |
|---|
| 358 | + if (skb_queue_empty_lockless(&sk->sk_receive_queue)) |
|---|
| 365 | 359 | clear_bit(NETLINK_S_CONGESTED, &nlk->state); |
|---|
| 366 | 360 | if (!test_bit(NETLINK_S_CONGESTED, &nlk->state)) |
|---|
| 367 | 361 | wake_up_interruptible(&nlk->wait); |
|---|
| .. | .. |
|---|
| 576 | 570 | if (nlk_sk(sk)->bound) |
|---|
| 577 | 571 | goto err; |
|---|
| 578 | 572 | |
|---|
| 579 | | - err = -ENOMEM; |
|---|
| 580 | | - if (BITS_PER_LONG > 32 && |
|---|
| 581 | | - unlikely(atomic_read(&table->hash.nelems) >= UINT_MAX)) |
|---|
| 582 | | - goto err; |
|---|
| 573 | + /* portid can be read locklessly from netlink_getname(). */ |
|---|
| 574 | + WRITE_ONCE(nlk_sk(sk)->portid, portid); |
|---|
| 583 | 575 | |
|---|
| 584 | | - nlk_sk(sk)->portid = portid; |
|---|
| 585 | 576 | sock_hold(sk); |
|---|
| 586 | 577 | |
|---|
| 587 | 578 | err = __netlink_insert(table, sk); |
|---|
| .. | .. |
|---|
| 866 | 857 | * |
|---|
| 867 | 858 | * Test to see if the opener of the socket we received the message |
|---|
| 868 | 859 | * from had when the netlink socket was created and the sender of the |
|---|
| 869 | | - * message has has the capability @cap in the user namespace @user_ns. |
|---|
| 860 | + * message has the capability @cap in the user namespace @user_ns. |
|---|
| 870 | 861 | */ |
|---|
| 871 | 862 | bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, |
|---|
| 872 | 863 | struct user_namespace *user_ns, int cap) |
|---|
| .. | .. |
|---|
| 885 | 876 | * |
|---|
| 886 | 877 | * Test to see if the opener of the socket we received the message |
|---|
| 887 | 878 | * from had when the netlink socket was created and the sender of the |
|---|
| 888 | | - * message has has the capability @cap in the user namespace @user_ns. |
|---|
| 879 | + * message has the capability @cap in the user namespace @user_ns. |
|---|
| 889 | 880 | */ |
|---|
| 890 | 881 | bool netlink_ns_capable(const struct sk_buff *skb, |
|---|
| 891 | 882 | struct user_namespace *user_ns, int cap) |
|---|
| .. | .. |
|---|
| 901 | 892 | * |
|---|
| 902 | 893 | * Test to see if the opener of the socket we received the message |
|---|
| 903 | 894 | * from had when the netlink socket was created and the sender of the |
|---|
| 904 | | - * message has has the capability @cap in all user namespaces. |
|---|
| 895 | + * message has the capability @cap in all user namespaces. |
|---|
| 905 | 896 | */ |
|---|
| 906 | 897 | bool netlink_capable(const struct sk_buff *skb, int cap) |
|---|
| 907 | 898 | { |
|---|
| .. | .. |
|---|
| 916 | 907 | * |
|---|
| 917 | 908 | * Test to see if the opener of the socket we received the message |
|---|
| 918 | 909 | * from had when the netlink socket was created and the sender of the |
|---|
| 919 | | - * message has has the capability @cap over the network namespace of |
|---|
| 910 | + * message has the capability @cap over the network namespace of |
|---|
| 920 | 911 | * the socket we received the message from. |
|---|
| 921 | 912 | */ |
|---|
| 922 | 913 | bool netlink_net_capable(const struct sk_buff *skb, int cap) |
|---|
| .. | .. |
|---|
| 998 | 989 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| 999 | 990 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
|---|
| 1000 | 991 | int err = 0; |
|---|
| 1001 | | - long unsigned int groups = nladdr->nl_groups; |
|---|
| 992 | + unsigned long groups; |
|---|
| 1002 | 993 | bool bound; |
|---|
| 1003 | 994 | |
|---|
| 1004 | 995 | if (addr_len < sizeof(struct sockaddr_nl)) |
|---|
| .. | .. |
|---|
| 1006 | 997 | |
|---|
| 1007 | 998 | if (nladdr->nl_family != AF_NETLINK) |
|---|
| 1008 | 999 | return -EINVAL; |
|---|
| 1000 | + groups = nladdr->nl_groups; |
|---|
| 1009 | 1001 | |
|---|
| 1010 | 1002 | /* Only superuser is allowed to listen multicasts */ |
|---|
| 1011 | 1003 | if (groups) { |
|---|
| .. | .. |
|---|
| 1016 | 1008 | return err; |
|---|
| 1017 | 1009 | } |
|---|
| 1018 | 1010 | |
|---|
| 1019 | | - if (nlk->ngroups == 0) |
|---|
| 1020 | | - groups = 0; |
|---|
| 1021 | | - else if (nlk->ngroups < 8*sizeof(groups)) |
|---|
| 1011 | + if (nlk->ngroups < BITS_PER_LONG) |
|---|
| 1022 | 1012 | groups &= (1UL << nlk->ngroups) - 1; |
|---|
| 1023 | 1013 | |
|---|
| 1024 | 1014 | /* Paired with WRITE_ONCE() in netlink_insert() */ |
|---|
| .. | .. |
|---|
| 1091 | 1081 | return -EINVAL; |
|---|
| 1092 | 1082 | |
|---|
| 1093 | 1083 | if (addr->sa_family == AF_UNSPEC) { |
|---|
| 1094 | | - sk->sk_state = NETLINK_UNCONNECTED; |
|---|
| 1095 | | - nlk->dst_portid = 0; |
|---|
| 1096 | | - nlk->dst_group = 0; |
|---|
| 1084 | + /* paired with READ_ONCE() in netlink_getsockbyportid() */ |
|---|
| 1085 | + WRITE_ONCE(sk->sk_state, NETLINK_UNCONNECTED); |
|---|
| 1086 | + /* dst_portid and dst_group can be read locklessly */ |
|---|
| 1087 | + WRITE_ONCE(nlk->dst_portid, 0); |
|---|
| 1088 | + WRITE_ONCE(nlk->dst_group, 0); |
|---|
| 1097 | 1089 | return 0; |
|---|
| 1098 | 1090 | } |
|---|
| 1099 | 1091 | if (addr->sa_family != AF_NETLINK) |
|---|
| .. | .. |
|---|
| 1114 | 1106 | err = netlink_autobind(sock); |
|---|
| 1115 | 1107 | |
|---|
| 1116 | 1108 | if (err == 0) { |
|---|
| 1117 | | - sk->sk_state = NETLINK_CONNECTED; |
|---|
| 1118 | | - nlk->dst_portid = nladdr->nl_pid; |
|---|
| 1119 | | - nlk->dst_group = ffs(nladdr->nl_groups); |
|---|
| 1109 | + /* paired with READ_ONCE() in netlink_getsockbyportid() */ |
|---|
| 1110 | + WRITE_ONCE(sk->sk_state, NETLINK_CONNECTED); |
|---|
| 1111 | + /* dst_portid and dst_group can be read locklessly */ |
|---|
| 1112 | + WRITE_ONCE(nlk->dst_portid, nladdr->nl_pid); |
|---|
| 1113 | + WRITE_ONCE(nlk->dst_group, ffs(nladdr->nl_groups)); |
|---|
| 1120 | 1114 | } |
|---|
| 1121 | 1115 | |
|---|
| 1122 | 1116 | return err; |
|---|
| .. | .. |
|---|
| 1133 | 1127 | nladdr->nl_pad = 0; |
|---|
| 1134 | 1128 | |
|---|
| 1135 | 1129 | if (peer) { |
|---|
| 1136 | | - nladdr->nl_pid = nlk->dst_portid; |
|---|
| 1137 | | - nladdr->nl_groups = netlink_group_mask(nlk->dst_group); |
|---|
| 1130 | + /* Paired with WRITE_ONCE() in netlink_connect() */ |
|---|
| 1131 | + nladdr->nl_pid = READ_ONCE(nlk->dst_portid); |
|---|
| 1132 | + nladdr->nl_groups = netlink_group_mask(READ_ONCE(nlk->dst_group)); |
|---|
| 1138 | 1133 | } else { |
|---|
| 1139 | | - nladdr->nl_pid = nlk->portid; |
|---|
| 1134 | + /* Paired with WRITE_ONCE() in netlink_insert() */ |
|---|
| 1135 | + nladdr->nl_pid = READ_ONCE(nlk->portid); |
|---|
| 1140 | 1136 | netlink_lock_table(); |
|---|
| 1141 | 1137 | nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; |
|---|
| 1142 | 1138 | netlink_unlock_table(); |
|---|
| .. | .. |
|---|
| 1163 | 1159 | |
|---|
| 1164 | 1160 | /* Don't bother queuing skb if kernel socket has no input function */ |
|---|
| 1165 | 1161 | nlk = nlk_sk(sock); |
|---|
| 1166 | | - if (sock->sk_state == NETLINK_CONNECTED && |
|---|
| 1167 | | - nlk->dst_portid != nlk_sk(ssk)->portid) { |
|---|
| 1162 | + /* dst_portid and sk_state can be changed in netlink_connect() */ |
|---|
| 1163 | + if (READ_ONCE(sock->sk_state) == NETLINK_CONNECTED && |
|---|
| 1164 | + READ_ONCE(nlk->dst_portid) != nlk_sk(ssk)->portid) { |
|---|
| 1168 | 1165 | sock_put(sock); |
|---|
| 1169 | 1166 | return ERR_PTR(-ECONNREFUSED); |
|---|
| 1170 | 1167 | } |
|---|
| .. | .. |
|---|
| 1386 | 1383 | } |
|---|
| 1387 | 1384 | EXPORT_SYMBOL_GPL(netlink_has_listeners); |
|---|
| 1388 | 1385 | |
|---|
| 1386 | +bool netlink_strict_get_check(struct sk_buff *skb) |
|---|
| 1387 | +{ |
|---|
| 1388 | + const struct netlink_sock *nlk = nlk_sk(NETLINK_CB(skb).sk); |
|---|
| 1389 | + |
|---|
| 1390 | + return nlk->flags & NETLINK_F_STRICT_CHK; |
|---|
| 1391 | +} |
|---|
| 1392 | +EXPORT_SYMBOL_GPL(netlink_strict_get_check); |
|---|
| 1393 | + |
|---|
| 1389 | 1394 | static int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) |
|---|
| 1390 | 1395 | { |
|---|
| 1391 | 1396 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| .. | .. |
|---|
| 1597 | 1602 | int netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code) |
|---|
| 1598 | 1603 | { |
|---|
| 1599 | 1604 | struct netlink_set_err_data info; |
|---|
| 1605 | + unsigned long flags; |
|---|
| 1600 | 1606 | struct sock *sk; |
|---|
| 1601 | 1607 | int ret = 0; |
|---|
| 1602 | 1608 | |
|---|
| .. | .. |
|---|
| 1606 | 1612 | /* sk->sk_err wants a positive error value */ |
|---|
| 1607 | 1613 | info.code = -code; |
|---|
| 1608 | 1614 | |
|---|
| 1609 | | - read_lock(&nl_table_lock); |
|---|
| 1615 | + read_lock_irqsave(&nl_table_lock, flags); |
|---|
| 1610 | 1616 | |
|---|
| 1611 | 1617 | sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) |
|---|
| 1612 | 1618 | ret += do_one_set_err(sk, &info); |
|---|
| 1613 | 1619 | |
|---|
| 1614 | | - read_unlock(&nl_table_lock); |
|---|
| 1620 | + read_unlock_irqrestore(&nl_table_lock, flags); |
|---|
| 1615 | 1621 | return ret; |
|---|
| 1616 | 1622 | } |
|---|
| 1617 | 1623 | EXPORT_SYMBOL(netlink_set_err); |
|---|
| .. | .. |
|---|
| 1634 | 1640 | } |
|---|
| 1635 | 1641 | |
|---|
| 1636 | 1642 | static int netlink_setsockopt(struct socket *sock, int level, int optname, |
|---|
| 1637 | | - char __user *optval, unsigned int optlen) |
|---|
| 1643 | + sockptr_t optval, unsigned int optlen) |
|---|
| 1638 | 1644 | { |
|---|
| 1639 | 1645 | struct sock *sk = sock->sk; |
|---|
| 1640 | 1646 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| .. | .. |
|---|
| 1645 | 1651 | return -ENOPROTOOPT; |
|---|
| 1646 | 1652 | |
|---|
| 1647 | 1653 | if (optlen >= sizeof(int) && |
|---|
| 1648 | | - get_user(val, (unsigned int __user *)optval)) |
|---|
| 1654 | + copy_from_sockptr(&val, optval, sizeof(val))) |
|---|
| 1649 | 1655 | return -EFAULT; |
|---|
| 1650 | 1656 | |
|---|
| 1651 | 1657 | switch (optname) { |
|---|
| .. | .. |
|---|
| 1721 | 1727 | nlk->flags &= ~NETLINK_F_EXT_ACK; |
|---|
| 1722 | 1728 | err = 0; |
|---|
| 1723 | 1729 | break; |
|---|
| 1730 | + case NETLINK_GET_STRICT_CHK: |
|---|
| 1731 | + if (val) |
|---|
| 1732 | + nlk->flags |= NETLINK_F_STRICT_CHK; |
|---|
| 1733 | + else |
|---|
| 1734 | + nlk->flags &= ~NETLINK_F_STRICT_CHK; |
|---|
| 1735 | + err = 0; |
|---|
| 1736 | + break; |
|---|
| 1724 | 1737 | default: |
|---|
| 1725 | 1738 | err = -ENOPROTOOPT; |
|---|
| 1726 | 1739 | } |
|---|
| .. | .. |
|---|
| 1732 | 1745 | { |
|---|
| 1733 | 1746 | struct sock *sk = sock->sk; |
|---|
| 1734 | 1747 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| 1735 | | - int len, val, err; |
|---|
| 1748 | + unsigned int flag; |
|---|
| 1749 | + int len, val; |
|---|
| 1736 | 1750 | |
|---|
| 1737 | 1751 | if (level != SOL_NETLINK) |
|---|
| 1738 | 1752 | return -ENOPROTOOPT; |
|---|
| .. | .. |
|---|
| 1744 | 1758 | |
|---|
| 1745 | 1759 | switch (optname) { |
|---|
| 1746 | 1760 | case NETLINK_PKTINFO: |
|---|
| 1747 | | - if (len < sizeof(int)) |
|---|
| 1748 | | - return -EINVAL; |
|---|
| 1749 | | - len = sizeof(int); |
|---|
| 1750 | | - val = nlk->flags & NETLINK_F_RECV_PKTINFO ? 1 : 0; |
|---|
| 1751 | | - if (put_user(len, optlen) || |
|---|
| 1752 | | - put_user(val, optval)) |
|---|
| 1753 | | - return -EFAULT; |
|---|
| 1754 | | - err = 0; |
|---|
| 1761 | + flag = NETLINK_F_RECV_PKTINFO; |
|---|
| 1755 | 1762 | break; |
|---|
| 1756 | 1763 | case NETLINK_BROADCAST_ERROR: |
|---|
| 1757 | | - if (len < sizeof(int)) |
|---|
| 1758 | | - return -EINVAL; |
|---|
| 1759 | | - len = sizeof(int); |
|---|
| 1760 | | - val = nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR ? 1 : 0; |
|---|
| 1761 | | - if (put_user(len, optlen) || |
|---|
| 1762 | | - put_user(val, optval)) |
|---|
| 1763 | | - return -EFAULT; |
|---|
| 1764 | | - err = 0; |
|---|
| 1764 | + flag = NETLINK_F_BROADCAST_SEND_ERROR; |
|---|
| 1765 | 1765 | break; |
|---|
| 1766 | 1766 | case NETLINK_NO_ENOBUFS: |
|---|
| 1767 | | - if (len < sizeof(int)) |
|---|
| 1768 | | - return -EINVAL; |
|---|
| 1769 | | - len = sizeof(int); |
|---|
| 1770 | | - val = nlk->flags & NETLINK_F_RECV_NO_ENOBUFS ? 1 : 0; |
|---|
| 1771 | | - if (put_user(len, optlen) || |
|---|
| 1772 | | - put_user(val, optval)) |
|---|
| 1773 | | - return -EFAULT; |
|---|
| 1774 | | - err = 0; |
|---|
| 1767 | + flag = NETLINK_F_RECV_NO_ENOBUFS; |
|---|
| 1775 | 1768 | break; |
|---|
| 1776 | 1769 | case NETLINK_LIST_MEMBERSHIPS: { |
|---|
| 1777 | | - int pos, idx, shift; |
|---|
| 1770 | + int pos, idx, shift, err = 0; |
|---|
| 1778 | 1771 | |
|---|
| 1779 | | - err = 0; |
|---|
| 1780 | 1772 | netlink_lock_table(); |
|---|
| 1781 | 1773 | for (pos = 0; pos * 8 < nlk->ngroups; pos += sizeof(u32)) { |
|---|
| 1782 | 1774 | if (len - pos < sizeof(u32)) |
|---|
| .. | .. |
|---|
| 1790 | 1782 | break; |
|---|
| 1791 | 1783 | } |
|---|
| 1792 | 1784 | } |
|---|
| 1793 | | - if (put_user(ALIGN(nlk->ngroups / 8, sizeof(u32)), optlen)) |
|---|
| 1785 | + if (put_user(ALIGN(BITS_TO_BYTES(nlk->ngroups), sizeof(u32)), optlen)) |
|---|
| 1794 | 1786 | err = -EFAULT; |
|---|
| 1795 | 1787 | netlink_unlock_table(); |
|---|
| 1796 | | - break; |
|---|
| 1788 | + return err; |
|---|
| 1797 | 1789 | } |
|---|
| 1798 | 1790 | case NETLINK_CAP_ACK: |
|---|
| 1799 | | - if (len < sizeof(int)) |
|---|
| 1800 | | - return -EINVAL; |
|---|
| 1801 | | - len = sizeof(int); |
|---|
| 1802 | | - val = nlk->flags & NETLINK_F_CAP_ACK ? 1 : 0; |
|---|
| 1803 | | - if (put_user(len, optlen) || |
|---|
| 1804 | | - put_user(val, optval)) |
|---|
| 1805 | | - return -EFAULT; |
|---|
| 1806 | | - err = 0; |
|---|
| 1791 | + flag = NETLINK_F_CAP_ACK; |
|---|
| 1807 | 1792 | break; |
|---|
| 1808 | 1793 | case NETLINK_EXT_ACK: |
|---|
| 1809 | | - if (len < sizeof(int)) |
|---|
| 1810 | | - return -EINVAL; |
|---|
| 1811 | | - len = sizeof(int); |
|---|
| 1812 | | - val = nlk->flags & NETLINK_F_EXT_ACK ? 1 : 0; |
|---|
| 1813 | | - if (put_user(len, optlen) || put_user(val, optval)) |
|---|
| 1814 | | - return -EFAULT; |
|---|
| 1815 | | - err = 0; |
|---|
| 1794 | + flag = NETLINK_F_EXT_ACK; |
|---|
| 1795 | + break; |
|---|
| 1796 | + case NETLINK_GET_STRICT_CHK: |
|---|
| 1797 | + flag = NETLINK_F_STRICT_CHK; |
|---|
| 1816 | 1798 | break; |
|---|
| 1817 | 1799 | default: |
|---|
| 1818 | | - err = -ENOPROTOOPT; |
|---|
| 1800 | + return -ENOPROTOOPT; |
|---|
| 1819 | 1801 | } |
|---|
| 1820 | | - return err; |
|---|
| 1802 | + |
|---|
| 1803 | + if (len < sizeof(int)) |
|---|
| 1804 | + return -EINVAL; |
|---|
| 1805 | + |
|---|
| 1806 | + len = sizeof(int); |
|---|
| 1807 | + val = nlk->flags & flag ? 1 : 0; |
|---|
| 1808 | + |
|---|
| 1809 | + if (put_user(len, optlen) || |
|---|
| 1810 | + copy_to_user(optval, &val, len)) |
|---|
| 1811 | + return -EFAULT; |
|---|
| 1812 | + |
|---|
| 1813 | + return 0; |
|---|
| 1821 | 1814 | } |
|---|
| 1822 | 1815 | |
|---|
| 1823 | 1816 | static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) |
|---|
| .. | .. |
|---|
| 1850 | 1843 | struct scm_cookie scm; |
|---|
| 1851 | 1844 | u32 netlink_skb_flags = 0; |
|---|
| 1852 | 1845 | |
|---|
| 1853 | | - if (msg->msg_flags&MSG_OOB) |
|---|
| 1846 | + if (msg->msg_flags & MSG_OOB) |
|---|
| 1854 | 1847 | return -EOPNOTSUPP; |
|---|
| 1855 | 1848 | |
|---|
| 1856 | 1849 | if (len == 0) { |
|---|
| .. | .. |
|---|
| 1876 | 1869 | goto out; |
|---|
| 1877 | 1870 | netlink_skb_flags |= NETLINK_SKB_DST; |
|---|
| 1878 | 1871 | } else { |
|---|
| 1879 | | - dst_portid = nlk->dst_portid; |
|---|
| 1880 | | - dst_group = nlk->dst_group; |
|---|
| 1872 | + /* Paired with WRITE_ONCE() in netlink_connect() */ |
|---|
| 1873 | + dst_portid = READ_ONCE(nlk->dst_portid); |
|---|
| 1874 | + dst_group = READ_ONCE(nlk->dst_group); |
|---|
| 1881 | 1875 | } |
|---|
| 1882 | 1876 | |
|---|
| 1883 | 1877 | /* Paired with WRITE_ONCE() in netlink_insert() */ |
|---|
| .. | .. |
|---|
| 1919 | 1913 | refcount_inc(&skb->users); |
|---|
| 1920 | 1914 | netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL); |
|---|
| 1921 | 1915 | } |
|---|
| 1922 | | - err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags&MSG_DONTWAIT); |
|---|
| 1916 | + err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags & MSG_DONTWAIT); |
|---|
| 1923 | 1917 | |
|---|
| 1924 | 1918 | out: |
|---|
| 1925 | 1919 | scm_destroy(&scm); |
|---|
| .. | .. |
|---|
| 1932 | 1926 | struct scm_cookie scm; |
|---|
| 1933 | 1927 | struct sock *sk = sock->sk; |
|---|
| 1934 | 1928 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| 1935 | | - int noblock = flags&MSG_DONTWAIT; |
|---|
| 1929 | + int noblock = flags & MSG_DONTWAIT; |
|---|
| 1936 | 1930 | size_t copied; |
|---|
| 1937 | 1931 | struct sk_buff *skb, *data_skb; |
|---|
| 1938 | 1932 | int err, ret; |
|---|
| 1939 | 1933 | |
|---|
| 1940 | | - if (flags&MSG_OOB) |
|---|
| 1934 | + if (flags & MSG_OOB) |
|---|
| 1941 | 1935 | return -EOPNOTSUPP; |
|---|
| 1942 | 1936 | |
|---|
| 1943 | 1937 | copied = 0; |
|---|
| .. | .. |
|---|
| 1976 | 1970 | copied = len; |
|---|
| 1977 | 1971 | } |
|---|
| 1978 | 1972 | |
|---|
| 1979 | | - skb_reset_transport_header(data_skb); |
|---|
| 1980 | 1973 | err = skb_copy_datagram_msg(data_skb, 0, msg, copied); |
|---|
| 1981 | 1974 | |
|---|
| 1982 | 1975 | if (msg->msg_name) { |
|---|
| .. | .. |
|---|
| 2000 | 1993 | |
|---|
| 2001 | 1994 | skb_free_datagram(sk, skb); |
|---|
| 2002 | 1995 | |
|---|
| 2003 | | - if (nlk->cb_running && |
|---|
| 1996 | + if (READ_ONCE(nlk->cb_running) && |
|---|
| 2004 | 1997 | atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { |
|---|
| 2005 | 1998 | ret = netlink_dump(sk); |
|---|
| 2006 | 1999 | if (ret) { |
|---|
| .. | .. |
|---|
| 2189 | 2182 | * It would be better to create kernel thread. |
|---|
| 2190 | 2183 | */ |
|---|
| 2191 | 2184 | |
|---|
| 2185 | +static int netlink_dump_done(struct netlink_sock *nlk, struct sk_buff *skb, |
|---|
| 2186 | + struct netlink_callback *cb, |
|---|
| 2187 | + struct netlink_ext_ack *extack) |
|---|
| 2188 | +{ |
|---|
| 2189 | + struct nlmsghdr *nlh; |
|---|
| 2190 | + |
|---|
| 2191 | + nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(nlk->dump_done_errno), |
|---|
| 2192 | + NLM_F_MULTI | cb->answer_flags); |
|---|
| 2193 | + if (WARN_ON(!nlh)) |
|---|
| 2194 | + return -ENOBUFS; |
|---|
| 2195 | + |
|---|
| 2196 | + nl_dump_check_consistent(cb, nlh); |
|---|
| 2197 | + memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, sizeof(nlk->dump_done_errno)); |
|---|
| 2198 | + |
|---|
| 2199 | + if (extack->_msg && nlk->flags & NETLINK_F_EXT_ACK) { |
|---|
| 2200 | + nlh->nlmsg_flags |= NLM_F_ACK_TLVS; |
|---|
| 2201 | + if (!nla_put_string(skb, NLMSGERR_ATTR_MSG, extack->_msg)) |
|---|
| 2202 | + nlmsg_end(skb, nlh); |
|---|
| 2203 | + } |
|---|
| 2204 | + |
|---|
| 2205 | + return 0; |
|---|
| 2206 | +} |
|---|
| 2207 | + |
|---|
| 2192 | 2208 | static int netlink_dump(struct sock *sk) |
|---|
| 2193 | 2209 | { |
|---|
| 2194 | 2210 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| 2211 | + struct netlink_ext_ack extack = {}; |
|---|
| 2195 | 2212 | struct netlink_callback *cb; |
|---|
| 2196 | 2213 | struct sk_buff *skb = NULL; |
|---|
| 2197 | | - struct nlmsghdr *nlh; |
|---|
| 2198 | 2214 | struct module *module; |
|---|
| 2199 | 2215 | int err = -ENOBUFS; |
|---|
| 2200 | 2216 | int alloc_min_size; |
|---|
| .. | .. |
|---|
| 2241 | 2257 | * single netdev. The outcome is MSG_TRUNC error. |
|---|
| 2242 | 2258 | */ |
|---|
| 2243 | 2259 | skb_reserve(skb, skb_tailroom(skb) - alloc_size); |
|---|
| 2260 | + |
|---|
| 2261 | + /* Make sure malicious BPF programs can not read unitialized memory |
|---|
| 2262 | + * from skb->head -> skb->data |
|---|
| 2263 | + */ |
|---|
| 2264 | + skb_reset_network_header(skb); |
|---|
| 2265 | + skb_reset_mac_header(skb); |
|---|
| 2266 | + |
|---|
| 2244 | 2267 | netlink_skb_set_owner_r(skb, sk); |
|---|
| 2245 | 2268 | |
|---|
| 2246 | | - if (nlk->dump_done_errno > 0) |
|---|
| 2269 | + if (nlk->dump_done_errno > 0) { |
|---|
| 2270 | + cb->extack = &extack; |
|---|
| 2247 | 2271 | nlk->dump_done_errno = cb->dump(skb, cb); |
|---|
| 2272 | + cb->extack = NULL; |
|---|
| 2273 | + } |
|---|
| 2248 | 2274 | |
|---|
| 2249 | 2275 | if (nlk->dump_done_errno > 0 || |
|---|
| 2250 | 2276 | skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) { |
|---|
| .. | .. |
|---|
| 2257 | 2283 | return 0; |
|---|
| 2258 | 2284 | } |
|---|
| 2259 | 2285 | |
|---|
| 2260 | | - nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, |
|---|
| 2261 | | - sizeof(nlk->dump_done_errno), NLM_F_MULTI); |
|---|
| 2262 | | - if (WARN_ON(!nlh)) |
|---|
| 2286 | + if (netlink_dump_done(nlk, skb, cb, &extack)) |
|---|
| 2263 | 2287 | goto errout_skb; |
|---|
| 2264 | 2288 | |
|---|
| 2265 | | - nl_dump_check_consistent(cb, nlh); |
|---|
| 2266 | | - |
|---|
| 2267 | | - memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, |
|---|
| 2268 | | - sizeof(nlk->dump_done_errno)); |
|---|
| 2289 | +#ifdef CONFIG_COMPAT_NETLINK_MESSAGES |
|---|
| 2290 | + /* frag_list skb's data is used for compat tasks |
|---|
| 2291 | + * and the regular skb's data for normal (non-compat) tasks. |
|---|
| 2292 | + * See netlink_recvmsg(). |
|---|
| 2293 | + */ |
|---|
| 2294 | + if (unlikely(skb_shinfo(skb)->frag_list)) { |
|---|
| 2295 | + if (netlink_dump_done(nlk, skb_shinfo(skb)->frag_list, cb, &extack)) |
|---|
| 2296 | + goto errout_skb; |
|---|
| 2297 | + } |
|---|
| 2298 | +#endif |
|---|
| 2269 | 2299 | |
|---|
| 2270 | 2300 | if (sk_filter(sk, skb)) |
|---|
| 2271 | 2301 | kfree_skb(skb); |
|---|
| .. | .. |
|---|
| 2275 | 2305 | if (cb->done) |
|---|
| 2276 | 2306 | cb->done(cb); |
|---|
| 2277 | 2307 | |
|---|
| 2278 | | - nlk->cb_running = false; |
|---|
| 2308 | + WRITE_ONCE(nlk->cb_running, false); |
|---|
| 2279 | 2309 | module = cb->module; |
|---|
| 2280 | 2310 | skb = cb->skb; |
|---|
| 2281 | 2311 | mutex_unlock(nlk->cb_mutex); |
|---|
| .. | .. |
|---|
| 2293 | 2323 | const struct nlmsghdr *nlh, |
|---|
| 2294 | 2324 | struct netlink_dump_control *control) |
|---|
| 2295 | 2325 | { |
|---|
| 2326 | + struct netlink_sock *nlk, *nlk2; |
|---|
| 2296 | 2327 | struct netlink_callback *cb; |
|---|
| 2297 | 2328 | struct sock *sk; |
|---|
| 2298 | | - struct netlink_sock *nlk; |
|---|
| 2299 | 2329 | int ret; |
|---|
| 2300 | 2330 | |
|---|
| 2301 | 2331 | refcount_inc(&skb->users); |
|---|
| .. | .. |
|---|
| 2329 | 2359 | cb->min_dump_alloc = control->min_dump_alloc; |
|---|
| 2330 | 2360 | cb->skb = skb; |
|---|
| 2331 | 2361 | |
|---|
| 2362 | + nlk2 = nlk_sk(NETLINK_CB(skb).sk); |
|---|
| 2363 | + cb->strict_check = !!(nlk2->flags & NETLINK_F_STRICT_CHK); |
|---|
| 2364 | + |
|---|
| 2332 | 2365 | if (control->start) { |
|---|
| 2333 | 2366 | ret = control->start(cb); |
|---|
| 2334 | 2367 | if (ret) |
|---|
| 2335 | 2368 | goto error_put; |
|---|
| 2336 | 2369 | } |
|---|
| 2337 | 2370 | |
|---|
| 2338 | | - nlk->cb_running = true; |
|---|
| 2371 | + WRITE_ONCE(nlk->cb_running, true); |
|---|
| 2339 | 2372 | nlk->dump_done_errno = INT_MAX; |
|---|
| 2340 | 2373 | |
|---|
| 2341 | 2374 | mutex_unlock(nlk->cb_mutex); |
|---|
| .. | .. |
|---|
| 2382 | 2415 | if (nlk_has_extack && extack && extack->_msg) |
|---|
| 2383 | 2416 | tlvlen += nla_total_size(strlen(extack->_msg) + 1); |
|---|
| 2384 | 2417 | |
|---|
| 2385 | | - if (err) { |
|---|
| 2386 | | - if (!(nlk->flags & NETLINK_F_CAP_ACK)) |
|---|
| 2387 | | - payload += nlmsg_len(nlh); |
|---|
| 2388 | | - else |
|---|
| 2389 | | - flags |= NLM_F_CAPPED; |
|---|
| 2390 | | - if (nlk_has_extack && extack && extack->bad_attr) |
|---|
| 2391 | | - tlvlen += nla_total_size(sizeof(u32)); |
|---|
| 2392 | | - } else { |
|---|
| 2418 | + if (err && !(nlk->flags & NETLINK_F_CAP_ACK)) |
|---|
| 2419 | + payload += nlmsg_len(nlh); |
|---|
| 2420 | + else |
|---|
| 2393 | 2421 | flags |= NLM_F_CAPPED; |
|---|
| 2394 | | - |
|---|
| 2395 | | - if (nlk_has_extack && extack && extack->cookie_len) |
|---|
| 2396 | | - tlvlen += nla_total_size(extack->cookie_len); |
|---|
| 2397 | | - } |
|---|
| 2422 | + if (err && nlk_has_extack && extack && extack->bad_attr) |
|---|
| 2423 | + tlvlen += nla_total_size(sizeof(u32)); |
|---|
| 2424 | + if (nlk_has_extack && extack && extack->cookie_len) |
|---|
| 2425 | + tlvlen += nla_total_size(extack->cookie_len); |
|---|
| 2426 | + if (err && nlk_has_extack && extack && extack->policy) |
|---|
| 2427 | + tlvlen += netlink_policy_dump_attr_size_estimate(extack->policy); |
|---|
| 2398 | 2428 | |
|---|
| 2399 | 2429 | if (tlvlen) |
|---|
| 2400 | 2430 | flags |= NLM_F_ACK_TLVS; |
|---|
| .. | .. |
|---|
| 2417 | 2447 | WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG, |
|---|
| 2418 | 2448 | extack->_msg)); |
|---|
| 2419 | 2449 | } |
|---|
| 2420 | | - if (err) { |
|---|
| 2421 | | - if (extack->bad_attr && |
|---|
| 2422 | | - !WARN_ON((u8 *)extack->bad_attr < in_skb->data || |
|---|
| 2423 | | - (u8 *)extack->bad_attr >= in_skb->data + |
|---|
| 2424 | | - in_skb->len)) |
|---|
| 2425 | | - WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS, |
|---|
| 2426 | | - (u8 *)extack->bad_attr - |
|---|
| 2427 | | - (u8 *)nlh)); |
|---|
| 2428 | | - } else { |
|---|
| 2429 | | - if (extack->cookie_len) |
|---|
| 2430 | | - WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE, |
|---|
| 2431 | | - extack->cookie_len, |
|---|
| 2432 | | - extack->cookie)); |
|---|
| 2433 | | - } |
|---|
| 2450 | + if (err && extack->bad_attr && |
|---|
| 2451 | + !WARN_ON((u8 *)extack->bad_attr < in_skb->data || |
|---|
| 2452 | + (u8 *)extack->bad_attr >= in_skb->data + |
|---|
| 2453 | + in_skb->len)) |
|---|
| 2454 | + WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS, |
|---|
| 2455 | + (u8 *)extack->bad_attr - |
|---|
| 2456 | + (u8 *)nlh)); |
|---|
| 2457 | + if (extack->cookie_len) |
|---|
| 2458 | + WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE, |
|---|
| 2459 | + extack->cookie_len, extack->cookie)); |
|---|
| 2460 | + if (extack->policy) |
|---|
| 2461 | + netlink_policy_dump_write_attr(skb, extack->policy, |
|---|
| 2462 | + NLMSGERR_ATTR_POLICY); |
|---|
| 2434 | 2463 | } |
|---|
| 2435 | 2464 | |
|---|
| 2436 | 2465 | nlmsg_end(skb, rep); |
|---|
| .. | .. |
|---|
| 2532 | 2561 | int link; |
|---|
| 2533 | 2562 | }; |
|---|
| 2534 | 2563 | |
|---|
| 2535 | | -static int netlink_walk_start(struct nl_seq_iter *iter) |
|---|
| 2564 | +static void netlink_walk_start(struct nl_seq_iter *iter) |
|---|
| 2536 | 2565 | { |
|---|
| 2537 | | - int err; |
|---|
| 2538 | | - |
|---|
| 2539 | | - err = rhashtable_walk_init(&nl_table[iter->link].hash, &iter->hti, |
|---|
| 2540 | | - GFP_KERNEL); |
|---|
| 2541 | | - if (err) { |
|---|
| 2542 | | - iter->link = MAX_LINKS; |
|---|
| 2543 | | - return err; |
|---|
| 2544 | | - } |
|---|
| 2545 | | - |
|---|
| 2566 | + rhashtable_walk_enter(&nl_table[iter->link].hash, &iter->hti); |
|---|
| 2546 | 2567 | rhashtable_walk_start(&iter->hti); |
|---|
| 2547 | | - |
|---|
| 2548 | | - return 0; |
|---|
| 2549 | 2568 | } |
|---|
| 2550 | 2569 | |
|---|
| 2551 | 2570 | static void netlink_walk_stop(struct nl_seq_iter *iter) |
|---|
| .. | .. |
|---|
| 2561 | 2580 | |
|---|
| 2562 | 2581 | do { |
|---|
| 2563 | 2582 | for (;;) { |
|---|
| 2564 | | - int err; |
|---|
| 2565 | | - |
|---|
| 2566 | 2583 | nlk = rhashtable_walk_next(&iter->hti); |
|---|
| 2567 | 2584 | |
|---|
| 2568 | 2585 | if (IS_ERR(nlk)) { |
|---|
| .. | .. |
|---|
| 2579 | 2596 | if (++iter->link >= MAX_LINKS) |
|---|
| 2580 | 2597 | return NULL; |
|---|
| 2581 | 2598 | |
|---|
| 2582 | | - err = netlink_walk_start(iter); |
|---|
| 2583 | | - if (err) |
|---|
| 2584 | | - return ERR_PTR(err); |
|---|
| 2599 | + netlink_walk_start(iter); |
|---|
| 2585 | 2600 | } |
|---|
| 2586 | 2601 | } while (sock_net(&nlk->sk) != seq_file_net(seq)); |
|---|
| 2587 | 2602 | |
|---|
| .. | .. |
|---|
| 2589 | 2604 | } |
|---|
| 2590 | 2605 | |
|---|
| 2591 | 2606 | static void *netlink_seq_start(struct seq_file *seq, loff_t *posp) |
|---|
| 2607 | + __acquires(RCU) |
|---|
| 2592 | 2608 | { |
|---|
| 2593 | 2609 | struct nl_seq_iter *iter = seq->private; |
|---|
| 2594 | 2610 | void *obj = SEQ_START_TOKEN; |
|---|
| 2595 | 2611 | loff_t pos; |
|---|
| 2596 | | - int err; |
|---|
| 2597 | 2612 | |
|---|
| 2598 | 2613 | iter->link = 0; |
|---|
| 2599 | 2614 | |
|---|
| 2600 | | - err = netlink_walk_start(iter); |
|---|
| 2601 | | - if (err) |
|---|
| 2602 | | - return ERR_PTR(err); |
|---|
| 2615 | + netlink_walk_start(iter); |
|---|
| 2603 | 2616 | |
|---|
| 2604 | 2617 | for (pos = *posp; pos && obj && !IS_ERR(obj); pos--) |
|---|
| 2605 | 2618 | obj = __netlink_seq_next(seq); |
|---|
| .. | .. |
|---|
| 2613 | 2626 | return __netlink_seq_next(seq); |
|---|
| 2614 | 2627 | } |
|---|
| 2615 | 2628 | |
|---|
| 2616 | | -static void netlink_seq_stop(struct seq_file *seq, void *v) |
|---|
| 2629 | +static void netlink_native_seq_stop(struct seq_file *seq, void *v) |
|---|
| 2617 | 2630 | { |
|---|
| 2618 | 2631 | struct nl_seq_iter *iter = seq->private; |
|---|
| 2619 | 2632 | |
|---|
| .. | .. |
|---|
| 2624 | 2637 | } |
|---|
| 2625 | 2638 | |
|---|
| 2626 | 2639 | |
|---|
| 2627 | | -static int netlink_seq_show(struct seq_file *seq, void *v) |
|---|
| 2640 | +static int netlink_native_seq_show(struct seq_file *seq, void *v) |
|---|
| 2628 | 2641 | { |
|---|
| 2629 | 2642 | if (v == SEQ_START_TOKEN) { |
|---|
| 2630 | 2643 | seq_puts(seq, |
|---|
| .. | .. |
|---|
| 2634 | 2647 | struct sock *s = v; |
|---|
| 2635 | 2648 | struct netlink_sock *nlk = nlk_sk(s); |
|---|
| 2636 | 2649 | |
|---|
| 2637 | | - seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8d %-8lu\n", |
|---|
| 2650 | + seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8u %-8lu\n", |
|---|
| 2638 | 2651 | s, |
|---|
| 2639 | 2652 | s->sk_protocol, |
|---|
| 2640 | 2653 | nlk->portid, |
|---|
| 2641 | 2654 | nlk->groups ? (u32)nlk->groups[0] : 0, |
|---|
| 2642 | 2655 | sk_rmem_alloc_get(s), |
|---|
| 2643 | 2656 | sk_wmem_alloc_get(s), |
|---|
| 2644 | | - nlk->cb_running, |
|---|
| 2657 | + READ_ONCE(nlk->cb_running), |
|---|
| 2645 | 2658 | refcount_read(&s->sk_refcnt), |
|---|
| 2646 | 2659 | atomic_read(&s->sk_drops), |
|---|
| 2647 | 2660 | sock_i_ino(s) |
|---|
| .. | .. |
|---|
| 2650 | 2663 | } |
|---|
| 2651 | 2664 | return 0; |
|---|
| 2652 | 2665 | } |
|---|
| 2666 | + |
|---|
| 2667 | +#ifdef CONFIG_BPF_SYSCALL |
|---|
| 2668 | +struct bpf_iter__netlink { |
|---|
| 2669 | + __bpf_md_ptr(struct bpf_iter_meta *, meta); |
|---|
| 2670 | + __bpf_md_ptr(struct netlink_sock *, sk); |
|---|
| 2671 | +}; |
|---|
| 2672 | + |
|---|
| 2673 | +DEFINE_BPF_ITER_FUNC(netlink, struct bpf_iter_meta *meta, struct netlink_sock *sk) |
|---|
| 2674 | + |
|---|
| 2675 | +static int netlink_prog_seq_show(struct bpf_prog *prog, |
|---|
| 2676 | + struct bpf_iter_meta *meta, |
|---|
| 2677 | + void *v) |
|---|
| 2678 | +{ |
|---|
| 2679 | + struct bpf_iter__netlink ctx; |
|---|
| 2680 | + |
|---|
| 2681 | + meta->seq_num--; /* skip SEQ_START_TOKEN */ |
|---|
| 2682 | + ctx.meta = meta; |
|---|
| 2683 | + ctx.sk = nlk_sk((struct sock *)v); |
|---|
| 2684 | + return bpf_iter_run_prog(prog, &ctx); |
|---|
| 2685 | +} |
|---|
| 2686 | + |
|---|
| 2687 | +static int netlink_seq_show(struct seq_file *seq, void *v) |
|---|
| 2688 | +{ |
|---|
| 2689 | + struct bpf_iter_meta meta; |
|---|
| 2690 | + struct bpf_prog *prog; |
|---|
| 2691 | + |
|---|
| 2692 | + meta.seq = seq; |
|---|
| 2693 | + prog = bpf_iter_get_info(&meta, false); |
|---|
| 2694 | + if (!prog) |
|---|
| 2695 | + return netlink_native_seq_show(seq, v); |
|---|
| 2696 | + |
|---|
| 2697 | + if (v != SEQ_START_TOKEN) |
|---|
| 2698 | + return netlink_prog_seq_show(prog, &meta, v); |
|---|
| 2699 | + |
|---|
| 2700 | + return 0; |
|---|
| 2701 | +} |
|---|
| 2702 | + |
|---|
| 2703 | +static void netlink_seq_stop(struct seq_file *seq, void *v) |
|---|
| 2704 | +{ |
|---|
| 2705 | + struct bpf_iter_meta meta; |
|---|
| 2706 | + struct bpf_prog *prog; |
|---|
| 2707 | + |
|---|
| 2708 | + if (!v) { |
|---|
| 2709 | + meta.seq = seq; |
|---|
| 2710 | + prog = bpf_iter_get_info(&meta, true); |
|---|
| 2711 | + if (prog) |
|---|
| 2712 | + (void)netlink_prog_seq_show(prog, &meta, v); |
|---|
| 2713 | + } |
|---|
| 2714 | + |
|---|
| 2715 | + netlink_native_seq_stop(seq, v); |
|---|
| 2716 | +} |
|---|
| 2717 | +#else |
|---|
| 2718 | +static int netlink_seq_show(struct seq_file *seq, void *v) |
|---|
| 2719 | +{ |
|---|
| 2720 | + return netlink_native_seq_show(seq, v); |
|---|
| 2721 | +} |
|---|
| 2722 | + |
|---|
| 2723 | +static void netlink_seq_stop(struct seq_file *seq, void *v) |
|---|
| 2724 | +{ |
|---|
| 2725 | + netlink_native_seq_stop(seq, v); |
|---|
| 2726 | +} |
|---|
| 2727 | +#endif |
|---|
| 2653 | 2728 | |
|---|
| 2654 | 2729 | static const struct seq_operations netlink_seq_ops = { |
|---|
| 2655 | 2730 | .start = netlink_seq_start, |
|---|
| .. | .. |
|---|
| 2757 | 2832 | .automatic_shrinking = true, |
|---|
| 2758 | 2833 | }; |
|---|
| 2759 | 2834 | |
|---|
| 2835 | +#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) |
|---|
| 2836 | +BTF_ID_LIST(btf_netlink_sock_id) |
|---|
| 2837 | +BTF_ID(struct, netlink_sock) |
|---|
| 2838 | + |
|---|
| 2839 | +static const struct bpf_iter_seq_info netlink_seq_info = { |
|---|
| 2840 | + .seq_ops = &netlink_seq_ops, |
|---|
| 2841 | + .init_seq_private = bpf_iter_init_seq_net, |
|---|
| 2842 | + .fini_seq_private = bpf_iter_fini_seq_net, |
|---|
| 2843 | + .seq_priv_size = sizeof(struct nl_seq_iter), |
|---|
| 2844 | +}; |
|---|
| 2845 | + |
|---|
| 2846 | +static struct bpf_iter_reg netlink_reg_info = { |
|---|
| 2847 | + .target = "netlink", |
|---|
| 2848 | + .ctx_arg_info_size = 1, |
|---|
| 2849 | + .ctx_arg_info = { |
|---|
| 2850 | + { offsetof(struct bpf_iter__netlink, sk), |
|---|
| 2851 | + PTR_TO_BTF_ID_OR_NULL }, |
|---|
| 2852 | + }, |
|---|
| 2853 | + .seq_info = &netlink_seq_info, |
|---|
| 2854 | +}; |
|---|
| 2855 | + |
|---|
| 2856 | +static int __init bpf_iter_register(void) |
|---|
| 2857 | +{ |
|---|
| 2858 | + netlink_reg_info.ctx_arg_info[0].btf_id = *btf_netlink_sock_id; |
|---|
| 2859 | + return bpf_iter_reg_target(&netlink_reg_info); |
|---|
| 2860 | +} |
|---|
| 2861 | +#endif |
|---|
| 2862 | + |
|---|
| 2760 | 2863 | static int __init netlink_proto_init(void) |
|---|
| 2761 | 2864 | { |
|---|
| 2762 | 2865 | int i; |
|---|
| .. | .. |
|---|
| 2765 | 2868 | if (err != 0) |
|---|
| 2766 | 2869 | goto out; |
|---|
| 2767 | 2870 | |
|---|
| 2768 | | - BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > FIELD_SIZEOF(struct sk_buff, cb)); |
|---|
| 2871 | +#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) |
|---|
| 2872 | + err = bpf_iter_register(); |
|---|
| 2873 | + if (err) |
|---|
| 2874 | + goto out; |
|---|
| 2875 | +#endif |
|---|
| 2876 | + |
|---|
| 2877 | + BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof_field(struct sk_buff, cb)); |
|---|
| 2769 | 2878 | |
|---|
| 2770 | 2879 | nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); |
|---|
| 2771 | 2880 | if (!nl_table) |
|---|
| .. | .. |
|---|
| 2794 | 2903 | panic("netlink_init: Cannot allocate nl_table\n"); |
|---|
| 2795 | 2904 | } |
|---|
| 2796 | 2905 | |
|---|
| 2797 | | -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT |
|---|
| 2798 | | -core_initcall_sync(netlink_proto_init); |
|---|
| 2799 | | -#else |
|---|
| 2800 | 2906 | core_initcall(netlink_proto_init); |
|---|
| 2801 | | -#endif |
|---|