| .. | .. |
|---|
| 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); |
|---|
| .. | .. |
|---|
| 574 | 568 | |
|---|
| 575 | 569 | err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY; |
|---|
| 576 | 570 | if (nlk_sk(sk)->bound) |
|---|
| 577 | | - goto err; |
|---|
| 578 | | - |
|---|
| 579 | | - err = -ENOMEM; |
|---|
| 580 | | - if (BITS_PER_LONG > 32 && |
|---|
| 581 | | - unlikely(atomic_read(&table->hash.nelems) >= UINT_MAX)) |
|---|
| 582 | 571 | goto err; |
|---|
| 583 | 572 | |
|---|
| 584 | 573 | nlk_sk(sk)->portid = portid; |
|---|
| .. | .. |
|---|
| 866 | 855 | * |
|---|
| 867 | 856 | * Test to see if the opener of the socket we received the message |
|---|
| 868 | 857 | * 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. |
|---|
| 858 | + * message has the capability @cap in the user namespace @user_ns. |
|---|
| 870 | 859 | */ |
|---|
| 871 | 860 | bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, |
|---|
| 872 | 861 | struct user_namespace *user_ns, int cap) |
|---|
| .. | .. |
|---|
| 885 | 874 | * |
|---|
| 886 | 875 | * Test to see if the opener of the socket we received the message |
|---|
| 887 | 876 | * 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. |
|---|
| 877 | + * message has the capability @cap in the user namespace @user_ns. |
|---|
| 889 | 878 | */ |
|---|
| 890 | 879 | bool netlink_ns_capable(const struct sk_buff *skb, |
|---|
| 891 | 880 | struct user_namespace *user_ns, int cap) |
|---|
| .. | .. |
|---|
| 901 | 890 | * |
|---|
| 902 | 891 | * Test to see if the opener of the socket we received the message |
|---|
| 903 | 892 | * from had when the netlink socket was created and the sender of the |
|---|
| 904 | | - * message has has the capability @cap in all user namespaces. |
|---|
| 893 | + * message has the capability @cap in all user namespaces. |
|---|
| 905 | 894 | */ |
|---|
| 906 | 895 | bool netlink_capable(const struct sk_buff *skb, int cap) |
|---|
| 907 | 896 | { |
|---|
| .. | .. |
|---|
| 916 | 905 | * |
|---|
| 917 | 906 | * Test to see if the opener of the socket we received the message |
|---|
| 918 | 907 | * 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 |
|---|
| 908 | + * message has the capability @cap over the network namespace of |
|---|
| 920 | 909 | * the socket we received the message from. |
|---|
| 921 | 910 | */ |
|---|
| 922 | 911 | bool netlink_net_capable(const struct sk_buff *skb, int cap) |
|---|
| .. | .. |
|---|
| 998 | 987 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| 999 | 988 | struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; |
|---|
| 1000 | 989 | int err = 0; |
|---|
| 1001 | | - long unsigned int groups = nladdr->nl_groups; |
|---|
| 990 | + unsigned long groups; |
|---|
| 1002 | 991 | bool bound; |
|---|
| 1003 | 992 | |
|---|
| 1004 | 993 | if (addr_len < sizeof(struct sockaddr_nl)) |
|---|
| .. | .. |
|---|
| 1006 | 995 | |
|---|
| 1007 | 996 | if (nladdr->nl_family != AF_NETLINK) |
|---|
| 1008 | 997 | return -EINVAL; |
|---|
| 998 | + groups = nladdr->nl_groups; |
|---|
| 1009 | 999 | |
|---|
| 1010 | 1000 | /* Only superuser is allowed to listen multicasts */ |
|---|
| 1011 | 1001 | if (groups) { |
|---|
| .. | .. |
|---|
| 1016 | 1006 | return err; |
|---|
| 1017 | 1007 | } |
|---|
| 1018 | 1008 | |
|---|
| 1019 | | - if (nlk->ngroups == 0) |
|---|
| 1020 | | - groups = 0; |
|---|
| 1021 | | - else if (nlk->ngroups < 8*sizeof(groups)) |
|---|
| 1009 | + if (nlk->ngroups < BITS_PER_LONG) |
|---|
| 1022 | 1010 | groups &= (1UL << nlk->ngroups) - 1; |
|---|
| 1023 | 1011 | |
|---|
| 1024 | 1012 | /* Paired with WRITE_ONCE() in netlink_insert() */ |
|---|
| .. | .. |
|---|
| 1386 | 1374 | } |
|---|
| 1387 | 1375 | EXPORT_SYMBOL_GPL(netlink_has_listeners); |
|---|
| 1388 | 1376 | |
|---|
| 1377 | +bool netlink_strict_get_check(struct sk_buff *skb) |
|---|
| 1378 | +{ |
|---|
| 1379 | + const struct netlink_sock *nlk = nlk_sk(NETLINK_CB(skb).sk); |
|---|
| 1380 | + |
|---|
| 1381 | + return nlk->flags & NETLINK_F_STRICT_CHK; |
|---|
| 1382 | +} |
|---|
| 1383 | +EXPORT_SYMBOL_GPL(netlink_strict_get_check); |
|---|
| 1384 | + |
|---|
| 1389 | 1385 | static int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) |
|---|
| 1390 | 1386 | { |
|---|
| 1391 | 1387 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| .. | .. |
|---|
| 1634 | 1630 | } |
|---|
| 1635 | 1631 | |
|---|
| 1636 | 1632 | static int netlink_setsockopt(struct socket *sock, int level, int optname, |
|---|
| 1637 | | - char __user *optval, unsigned int optlen) |
|---|
| 1633 | + sockptr_t optval, unsigned int optlen) |
|---|
| 1638 | 1634 | { |
|---|
| 1639 | 1635 | struct sock *sk = sock->sk; |
|---|
| 1640 | 1636 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| .. | .. |
|---|
| 1645 | 1641 | return -ENOPROTOOPT; |
|---|
| 1646 | 1642 | |
|---|
| 1647 | 1643 | if (optlen >= sizeof(int) && |
|---|
| 1648 | | - get_user(val, (unsigned int __user *)optval)) |
|---|
| 1644 | + copy_from_sockptr(&val, optval, sizeof(val))) |
|---|
| 1649 | 1645 | return -EFAULT; |
|---|
| 1650 | 1646 | |
|---|
| 1651 | 1647 | switch (optname) { |
|---|
| .. | .. |
|---|
| 1719 | 1715 | nlk->flags |= NETLINK_F_EXT_ACK; |
|---|
| 1720 | 1716 | else |
|---|
| 1721 | 1717 | nlk->flags &= ~NETLINK_F_EXT_ACK; |
|---|
| 1718 | + err = 0; |
|---|
| 1719 | + break; |
|---|
| 1720 | + case NETLINK_GET_STRICT_CHK: |
|---|
| 1721 | + if (val) |
|---|
| 1722 | + nlk->flags |= NETLINK_F_STRICT_CHK; |
|---|
| 1723 | + else |
|---|
| 1724 | + nlk->flags &= ~NETLINK_F_STRICT_CHK; |
|---|
| 1722 | 1725 | err = 0; |
|---|
| 1723 | 1726 | break; |
|---|
| 1724 | 1727 | default: |
|---|
| .. | .. |
|---|
| 1814 | 1817 | return -EFAULT; |
|---|
| 1815 | 1818 | err = 0; |
|---|
| 1816 | 1819 | break; |
|---|
| 1820 | + case NETLINK_GET_STRICT_CHK: |
|---|
| 1821 | + if (len < sizeof(int)) |
|---|
| 1822 | + return -EINVAL; |
|---|
| 1823 | + len = sizeof(int); |
|---|
| 1824 | + val = nlk->flags & NETLINK_F_STRICT_CHK ? 1 : 0; |
|---|
| 1825 | + if (put_user(len, optlen) || put_user(val, optval)) |
|---|
| 1826 | + return -EFAULT; |
|---|
| 1827 | + err = 0; |
|---|
| 1828 | + break; |
|---|
| 1817 | 1829 | default: |
|---|
| 1818 | 1830 | err = -ENOPROTOOPT; |
|---|
| 1819 | 1831 | } |
|---|
| .. | .. |
|---|
| 1850 | 1862 | struct scm_cookie scm; |
|---|
| 1851 | 1863 | u32 netlink_skb_flags = 0; |
|---|
| 1852 | 1864 | |
|---|
| 1853 | | - if (msg->msg_flags&MSG_OOB) |
|---|
| 1865 | + if (msg->msg_flags & MSG_OOB) |
|---|
| 1854 | 1866 | return -EOPNOTSUPP; |
|---|
| 1855 | 1867 | |
|---|
| 1856 | 1868 | if (len == 0) { |
|---|
| .. | .. |
|---|
| 1919 | 1931 | refcount_inc(&skb->users); |
|---|
| 1920 | 1932 | netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL); |
|---|
| 1921 | 1933 | } |
|---|
| 1922 | | - err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags&MSG_DONTWAIT); |
|---|
| 1934 | + err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags & MSG_DONTWAIT); |
|---|
| 1923 | 1935 | |
|---|
| 1924 | 1936 | out: |
|---|
| 1925 | 1937 | scm_destroy(&scm); |
|---|
| .. | .. |
|---|
| 1932 | 1944 | struct scm_cookie scm; |
|---|
| 1933 | 1945 | struct sock *sk = sock->sk; |
|---|
| 1934 | 1946 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| 1935 | | - int noblock = flags&MSG_DONTWAIT; |
|---|
| 1947 | + int noblock = flags & MSG_DONTWAIT; |
|---|
| 1936 | 1948 | size_t copied; |
|---|
| 1937 | 1949 | struct sk_buff *skb, *data_skb; |
|---|
| 1938 | 1950 | int err, ret; |
|---|
| 1939 | 1951 | |
|---|
| 1940 | | - if (flags&MSG_OOB) |
|---|
| 1952 | + if (flags & MSG_OOB) |
|---|
| 1941 | 1953 | return -EOPNOTSUPP; |
|---|
| 1942 | 1954 | |
|---|
| 1943 | 1955 | copied = 0; |
|---|
| .. | .. |
|---|
| 1976 | 1988 | copied = len; |
|---|
| 1977 | 1989 | } |
|---|
| 1978 | 1990 | |
|---|
| 1979 | | - skb_reset_transport_header(data_skb); |
|---|
| 1980 | 1991 | err = skb_copy_datagram_msg(data_skb, 0, msg, copied); |
|---|
| 1981 | 1992 | |
|---|
| 1982 | 1993 | if (msg->msg_name) { |
|---|
| .. | .. |
|---|
| 2189 | 2200 | * It would be better to create kernel thread. |
|---|
| 2190 | 2201 | */ |
|---|
| 2191 | 2202 | |
|---|
| 2203 | +static int netlink_dump_done(struct netlink_sock *nlk, struct sk_buff *skb, |
|---|
| 2204 | + struct netlink_callback *cb, |
|---|
| 2205 | + struct netlink_ext_ack *extack) |
|---|
| 2206 | +{ |
|---|
| 2207 | + struct nlmsghdr *nlh; |
|---|
| 2208 | + |
|---|
| 2209 | + nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(nlk->dump_done_errno), |
|---|
| 2210 | + NLM_F_MULTI | cb->answer_flags); |
|---|
| 2211 | + if (WARN_ON(!nlh)) |
|---|
| 2212 | + return -ENOBUFS; |
|---|
| 2213 | + |
|---|
| 2214 | + nl_dump_check_consistent(cb, nlh); |
|---|
| 2215 | + memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, sizeof(nlk->dump_done_errno)); |
|---|
| 2216 | + |
|---|
| 2217 | + if (extack->_msg && nlk->flags & NETLINK_F_EXT_ACK) { |
|---|
| 2218 | + nlh->nlmsg_flags |= NLM_F_ACK_TLVS; |
|---|
| 2219 | + if (!nla_put_string(skb, NLMSGERR_ATTR_MSG, extack->_msg)) |
|---|
| 2220 | + nlmsg_end(skb, nlh); |
|---|
| 2221 | + } |
|---|
| 2222 | + |
|---|
| 2223 | + return 0; |
|---|
| 2224 | +} |
|---|
| 2225 | + |
|---|
| 2192 | 2226 | static int netlink_dump(struct sock *sk) |
|---|
| 2193 | 2227 | { |
|---|
| 2194 | 2228 | struct netlink_sock *nlk = nlk_sk(sk); |
|---|
| 2229 | + struct netlink_ext_ack extack = {}; |
|---|
| 2195 | 2230 | struct netlink_callback *cb; |
|---|
| 2196 | 2231 | struct sk_buff *skb = NULL; |
|---|
| 2197 | | - struct nlmsghdr *nlh; |
|---|
| 2198 | 2232 | struct module *module; |
|---|
| 2199 | 2233 | int err = -ENOBUFS; |
|---|
| 2200 | 2234 | int alloc_min_size; |
|---|
| .. | .. |
|---|
| 2241 | 2275 | * single netdev. The outcome is MSG_TRUNC error. |
|---|
| 2242 | 2276 | */ |
|---|
| 2243 | 2277 | skb_reserve(skb, skb_tailroom(skb) - alloc_size); |
|---|
| 2278 | + |
|---|
| 2279 | + /* Make sure malicious BPF programs can not read unitialized memory |
|---|
| 2280 | + * from skb->head -> skb->data |
|---|
| 2281 | + */ |
|---|
| 2282 | + skb_reset_network_header(skb); |
|---|
| 2283 | + skb_reset_mac_header(skb); |
|---|
| 2284 | + |
|---|
| 2244 | 2285 | netlink_skb_set_owner_r(skb, sk); |
|---|
| 2245 | 2286 | |
|---|
| 2246 | | - if (nlk->dump_done_errno > 0) |
|---|
| 2287 | + if (nlk->dump_done_errno > 0) { |
|---|
| 2288 | + cb->extack = &extack; |
|---|
| 2247 | 2289 | nlk->dump_done_errno = cb->dump(skb, cb); |
|---|
| 2290 | + cb->extack = NULL; |
|---|
| 2291 | + } |
|---|
| 2248 | 2292 | |
|---|
| 2249 | 2293 | if (nlk->dump_done_errno > 0 || |
|---|
| 2250 | 2294 | skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) { |
|---|
| .. | .. |
|---|
| 2257 | 2301 | return 0; |
|---|
| 2258 | 2302 | } |
|---|
| 2259 | 2303 | |
|---|
| 2260 | | - nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, |
|---|
| 2261 | | - sizeof(nlk->dump_done_errno), NLM_F_MULTI); |
|---|
| 2262 | | - if (WARN_ON(!nlh)) |
|---|
| 2304 | + if (netlink_dump_done(nlk, skb, cb, &extack)) |
|---|
| 2263 | 2305 | goto errout_skb; |
|---|
| 2264 | 2306 | |
|---|
| 2265 | | - nl_dump_check_consistent(cb, nlh); |
|---|
| 2266 | | - |
|---|
| 2267 | | - memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, |
|---|
| 2268 | | - sizeof(nlk->dump_done_errno)); |
|---|
| 2307 | +#ifdef CONFIG_COMPAT_NETLINK_MESSAGES |
|---|
| 2308 | + /* frag_list skb's data is used for compat tasks |
|---|
| 2309 | + * and the regular skb's data for normal (non-compat) tasks. |
|---|
| 2310 | + * See netlink_recvmsg(). |
|---|
| 2311 | + */ |
|---|
| 2312 | + if (unlikely(skb_shinfo(skb)->frag_list)) { |
|---|
| 2313 | + if (netlink_dump_done(nlk, skb_shinfo(skb)->frag_list, cb, &extack)) |
|---|
| 2314 | + goto errout_skb; |
|---|
| 2315 | + } |
|---|
| 2316 | +#endif |
|---|
| 2269 | 2317 | |
|---|
| 2270 | 2318 | if (sk_filter(sk, skb)) |
|---|
| 2271 | 2319 | kfree_skb(skb); |
|---|
| .. | .. |
|---|
| 2293 | 2341 | const struct nlmsghdr *nlh, |
|---|
| 2294 | 2342 | struct netlink_dump_control *control) |
|---|
| 2295 | 2343 | { |
|---|
| 2344 | + struct netlink_sock *nlk, *nlk2; |
|---|
| 2296 | 2345 | struct netlink_callback *cb; |
|---|
| 2297 | 2346 | struct sock *sk; |
|---|
| 2298 | | - struct netlink_sock *nlk; |
|---|
| 2299 | 2347 | int ret; |
|---|
| 2300 | 2348 | |
|---|
| 2301 | 2349 | refcount_inc(&skb->users); |
|---|
| .. | .. |
|---|
| 2328 | 2376 | cb->module = control->module; |
|---|
| 2329 | 2377 | cb->min_dump_alloc = control->min_dump_alloc; |
|---|
| 2330 | 2378 | cb->skb = skb; |
|---|
| 2379 | + |
|---|
| 2380 | + nlk2 = nlk_sk(NETLINK_CB(skb).sk); |
|---|
| 2381 | + cb->strict_check = !!(nlk2->flags & NETLINK_F_STRICT_CHK); |
|---|
| 2331 | 2382 | |
|---|
| 2332 | 2383 | if (control->start) { |
|---|
| 2333 | 2384 | ret = control->start(cb); |
|---|
| .. | .. |
|---|
| 2382 | 2433 | if (nlk_has_extack && extack && extack->_msg) |
|---|
| 2383 | 2434 | tlvlen += nla_total_size(strlen(extack->_msg) + 1); |
|---|
| 2384 | 2435 | |
|---|
| 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 { |
|---|
| 2436 | + if (err && !(nlk->flags & NETLINK_F_CAP_ACK)) |
|---|
| 2437 | + payload += nlmsg_len(nlh); |
|---|
| 2438 | + else |
|---|
| 2393 | 2439 | flags |= NLM_F_CAPPED; |
|---|
| 2394 | | - |
|---|
| 2395 | | - if (nlk_has_extack && extack && extack->cookie_len) |
|---|
| 2396 | | - tlvlen += nla_total_size(extack->cookie_len); |
|---|
| 2397 | | - } |
|---|
| 2440 | + if (err && nlk_has_extack && extack && extack->bad_attr) |
|---|
| 2441 | + tlvlen += nla_total_size(sizeof(u32)); |
|---|
| 2442 | + if (nlk_has_extack && extack && extack->cookie_len) |
|---|
| 2443 | + tlvlen += nla_total_size(extack->cookie_len); |
|---|
| 2444 | + if (err && nlk_has_extack && extack && extack->policy) |
|---|
| 2445 | + tlvlen += netlink_policy_dump_attr_size_estimate(extack->policy); |
|---|
| 2398 | 2446 | |
|---|
| 2399 | 2447 | if (tlvlen) |
|---|
| 2400 | 2448 | flags |= NLM_F_ACK_TLVS; |
|---|
| .. | .. |
|---|
| 2417 | 2465 | WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG, |
|---|
| 2418 | 2466 | extack->_msg)); |
|---|
| 2419 | 2467 | } |
|---|
| 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 | | - } |
|---|
| 2468 | + if (err && extack->bad_attr && |
|---|
| 2469 | + !WARN_ON((u8 *)extack->bad_attr < in_skb->data || |
|---|
| 2470 | + (u8 *)extack->bad_attr >= in_skb->data + |
|---|
| 2471 | + in_skb->len)) |
|---|
| 2472 | + WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS, |
|---|
| 2473 | + (u8 *)extack->bad_attr - |
|---|
| 2474 | + (u8 *)nlh)); |
|---|
| 2475 | + if (extack->cookie_len) |
|---|
| 2476 | + WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE, |
|---|
| 2477 | + extack->cookie_len, extack->cookie)); |
|---|
| 2478 | + if (extack->policy) |
|---|
| 2479 | + netlink_policy_dump_write_attr(skb, extack->policy, |
|---|
| 2480 | + NLMSGERR_ATTR_POLICY); |
|---|
| 2434 | 2481 | } |
|---|
| 2435 | 2482 | |
|---|
| 2436 | 2483 | nlmsg_end(skb, rep); |
|---|
| .. | .. |
|---|
| 2532 | 2579 | int link; |
|---|
| 2533 | 2580 | }; |
|---|
| 2534 | 2581 | |
|---|
| 2535 | | -static int netlink_walk_start(struct nl_seq_iter *iter) |
|---|
| 2582 | +static void netlink_walk_start(struct nl_seq_iter *iter) |
|---|
| 2536 | 2583 | { |
|---|
| 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 | | - |
|---|
| 2584 | + rhashtable_walk_enter(&nl_table[iter->link].hash, &iter->hti); |
|---|
| 2546 | 2585 | rhashtable_walk_start(&iter->hti); |
|---|
| 2547 | | - |
|---|
| 2548 | | - return 0; |
|---|
| 2549 | 2586 | } |
|---|
| 2550 | 2587 | |
|---|
| 2551 | 2588 | static void netlink_walk_stop(struct nl_seq_iter *iter) |
|---|
| .. | .. |
|---|
| 2561 | 2598 | |
|---|
| 2562 | 2599 | do { |
|---|
| 2563 | 2600 | for (;;) { |
|---|
| 2564 | | - int err; |
|---|
| 2565 | | - |
|---|
| 2566 | 2601 | nlk = rhashtable_walk_next(&iter->hti); |
|---|
| 2567 | 2602 | |
|---|
| 2568 | 2603 | if (IS_ERR(nlk)) { |
|---|
| .. | .. |
|---|
| 2579 | 2614 | if (++iter->link >= MAX_LINKS) |
|---|
| 2580 | 2615 | return NULL; |
|---|
| 2581 | 2616 | |
|---|
| 2582 | | - err = netlink_walk_start(iter); |
|---|
| 2583 | | - if (err) |
|---|
| 2584 | | - return ERR_PTR(err); |
|---|
| 2617 | + netlink_walk_start(iter); |
|---|
| 2585 | 2618 | } |
|---|
| 2586 | 2619 | } while (sock_net(&nlk->sk) != seq_file_net(seq)); |
|---|
| 2587 | 2620 | |
|---|
| .. | .. |
|---|
| 2589 | 2622 | } |
|---|
| 2590 | 2623 | |
|---|
| 2591 | 2624 | static void *netlink_seq_start(struct seq_file *seq, loff_t *posp) |
|---|
| 2625 | + __acquires(RCU) |
|---|
| 2592 | 2626 | { |
|---|
| 2593 | 2627 | struct nl_seq_iter *iter = seq->private; |
|---|
| 2594 | 2628 | void *obj = SEQ_START_TOKEN; |
|---|
| 2595 | 2629 | loff_t pos; |
|---|
| 2596 | | - int err; |
|---|
| 2597 | 2630 | |
|---|
| 2598 | 2631 | iter->link = 0; |
|---|
| 2599 | 2632 | |
|---|
| 2600 | | - err = netlink_walk_start(iter); |
|---|
| 2601 | | - if (err) |
|---|
| 2602 | | - return ERR_PTR(err); |
|---|
| 2633 | + netlink_walk_start(iter); |
|---|
| 2603 | 2634 | |
|---|
| 2604 | 2635 | for (pos = *posp; pos && obj && !IS_ERR(obj); pos--) |
|---|
| 2605 | 2636 | obj = __netlink_seq_next(seq); |
|---|
| .. | .. |
|---|
| 2613 | 2644 | return __netlink_seq_next(seq); |
|---|
| 2614 | 2645 | } |
|---|
| 2615 | 2646 | |
|---|
| 2616 | | -static void netlink_seq_stop(struct seq_file *seq, void *v) |
|---|
| 2647 | +static void netlink_native_seq_stop(struct seq_file *seq, void *v) |
|---|
| 2617 | 2648 | { |
|---|
| 2618 | 2649 | struct nl_seq_iter *iter = seq->private; |
|---|
| 2619 | 2650 | |
|---|
| .. | .. |
|---|
| 2624 | 2655 | } |
|---|
| 2625 | 2656 | |
|---|
| 2626 | 2657 | |
|---|
| 2627 | | -static int netlink_seq_show(struct seq_file *seq, void *v) |
|---|
| 2658 | +static int netlink_native_seq_show(struct seq_file *seq, void *v) |
|---|
| 2628 | 2659 | { |
|---|
| 2629 | 2660 | if (v == SEQ_START_TOKEN) { |
|---|
| 2630 | 2661 | seq_puts(seq, |
|---|
| .. | .. |
|---|
| 2634 | 2665 | struct sock *s = v; |
|---|
| 2635 | 2666 | struct netlink_sock *nlk = nlk_sk(s); |
|---|
| 2636 | 2667 | |
|---|
| 2637 | | - seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8d %-8lu\n", |
|---|
| 2668 | + seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8u %-8lu\n", |
|---|
| 2638 | 2669 | s, |
|---|
| 2639 | 2670 | s->sk_protocol, |
|---|
| 2640 | 2671 | nlk->portid, |
|---|
| .. | .. |
|---|
| 2650 | 2681 | } |
|---|
| 2651 | 2682 | return 0; |
|---|
| 2652 | 2683 | } |
|---|
| 2684 | + |
|---|
| 2685 | +#ifdef CONFIG_BPF_SYSCALL |
|---|
| 2686 | +struct bpf_iter__netlink { |
|---|
| 2687 | + __bpf_md_ptr(struct bpf_iter_meta *, meta); |
|---|
| 2688 | + __bpf_md_ptr(struct netlink_sock *, sk); |
|---|
| 2689 | +}; |
|---|
| 2690 | + |
|---|
| 2691 | +DEFINE_BPF_ITER_FUNC(netlink, struct bpf_iter_meta *meta, struct netlink_sock *sk) |
|---|
| 2692 | + |
|---|
| 2693 | +static int netlink_prog_seq_show(struct bpf_prog *prog, |
|---|
| 2694 | + struct bpf_iter_meta *meta, |
|---|
| 2695 | + void *v) |
|---|
| 2696 | +{ |
|---|
| 2697 | + struct bpf_iter__netlink ctx; |
|---|
| 2698 | + |
|---|
| 2699 | + meta->seq_num--; /* skip SEQ_START_TOKEN */ |
|---|
| 2700 | + ctx.meta = meta; |
|---|
| 2701 | + ctx.sk = nlk_sk((struct sock *)v); |
|---|
| 2702 | + return bpf_iter_run_prog(prog, &ctx); |
|---|
| 2703 | +} |
|---|
| 2704 | + |
|---|
| 2705 | +static int netlink_seq_show(struct seq_file *seq, void *v) |
|---|
| 2706 | +{ |
|---|
| 2707 | + struct bpf_iter_meta meta; |
|---|
| 2708 | + struct bpf_prog *prog; |
|---|
| 2709 | + |
|---|
| 2710 | + meta.seq = seq; |
|---|
| 2711 | + prog = bpf_iter_get_info(&meta, false); |
|---|
| 2712 | + if (!prog) |
|---|
| 2713 | + return netlink_native_seq_show(seq, v); |
|---|
| 2714 | + |
|---|
| 2715 | + if (v != SEQ_START_TOKEN) |
|---|
| 2716 | + return netlink_prog_seq_show(prog, &meta, v); |
|---|
| 2717 | + |
|---|
| 2718 | + return 0; |
|---|
| 2719 | +} |
|---|
| 2720 | + |
|---|
| 2721 | +static void netlink_seq_stop(struct seq_file *seq, void *v) |
|---|
| 2722 | +{ |
|---|
| 2723 | + struct bpf_iter_meta meta; |
|---|
| 2724 | + struct bpf_prog *prog; |
|---|
| 2725 | + |
|---|
| 2726 | + if (!v) { |
|---|
| 2727 | + meta.seq = seq; |
|---|
| 2728 | + prog = bpf_iter_get_info(&meta, true); |
|---|
| 2729 | + if (prog) |
|---|
| 2730 | + (void)netlink_prog_seq_show(prog, &meta, v); |
|---|
| 2731 | + } |
|---|
| 2732 | + |
|---|
| 2733 | + netlink_native_seq_stop(seq, v); |
|---|
| 2734 | +} |
|---|
| 2735 | +#else |
|---|
| 2736 | +static int netlink_seq_show(struct seq_file *seq, void *v) |
|---|
| 2737 | +{ |
|---|
| 2738 | + return netlink_native_seq_show(seq, v); |
|---|
| 2739 | +} |
|---|
| 2740 | + |
|---|
| 2741 | +static void netlink_seq_stop(struct seq_file *seq, void *v) |
|---|
| 2742 | +{ |
|---|
| 2743 | + netlink_native_seq_stop(seq, v); |
|---|
| 2744 | +} |
|---|
| 2745 | +#endif |
|---|
| 2653 | 2746 | |
|---|
| 2654 | 2747 | static const struct seq_operations netlink_seq_ops = { |
|---|
| 2655 | 2748 | .start = netlink_seq_start, |
|---|
| .. | .. |
|---|
| 2757 | 2850 | .automatic_shrinking = true, |
|---|
| 2758 | 2851 | }; |
|---|
| 2759 | 2852 | |
|---|
| 2853 | +#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) |
|---|
| 2854 | +BTF_ID_LIST(btf_netlink_sock_id) |
|---|
| 2855 | +BTF_ID(struct, netlink_sock) |
|---|
| 2856 | + |
|---|
| 2857 | +static const struct bpf_iter_seq_info netlink_seq_info = { |
|---|
| 2858 | + .seq_ops = &netlink_seq_ops, |
|---|
| 2859 | + .init_seq_private = bpf_iter_init_seq_net, |
|---|
| 2860 | + .fini_seq_private = bpf_iter_fini_seq_net, |
|---|
| 2861 | + .seq_priv_size = sizeof(struct nl_seq_iter), |
|---|
| 2862 | +}; |
|---|
| 2863 | + |
|---|
| 2864 | +static struct bpf_iter_reg netlink_reg_info = { |
|---|
| 2865 | + .target = "netlink", |
|---|
| 2866 | + .ctx_arg_info_size = 1, |
|---|
| 2867 | + .ctx_arg_info = { |
|---|
| 2868 | + { offsetof(struct bpf_iter__netlink, sk), |
|---|
| 2869 | + PTR_TO_BTF_ID_OR_NULL }, |
|---|
| 2870 | + }, |
|---|
| 2871 | + .seq_info = &netlink_seq_info, |
|---|
| 2872 | +}; |
|---|
| 2873 | + |
|---|
| 2874 | +static int __init bpf_iter_register(void) |
|---|
| 2875 | +{ |
|---|
| 2876 | + netlink_reg_info.ctx_arg_info[0].btf_id = *btf_netlink_sock_id; |
|---|
| 2877 | + return bpf_iter_reg_target(&netlink_reg_info); |
|---|
| 2878 | +} |
|---|
| 2879 | +#endif |
|---|
| 2880 | + |
|---|
| 2760 | 2881 | static int __init netlink_proto_init(void) |
|---|
| 2761 | 2882 | { |
|---|
| 2762 | 2883 | int i; |
|---|
| .. | .. |
|---|
| 2765 | 2886 | if (err != 0) |
|---|
| 2766 | 2887 | goto out; |
|---|
| 2767 | 2888 | |
|---|
| 2768 | | - BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > FIELD_SIZEOF(struct sk_buff, cb)); |
|---|
| 2889 | +#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) |
|---|
| 2890 | + err = bpf_iter_register(); |
|---|
| 2891 | + if (err) |
|---|
| 2892 | + goto out; |
|---|
| 2893 | +#endif |
|---|
| 2894 | + |
|---|
| 2895 | + BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof_field(struct sk_buff, cb)); |
|---|
| 2769 | 2896 | |
|---|
| 2770 | 2897 | nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); |
|---|
| 2771 | 2898 | if (!nl_table) |
|---|
| .. | .. |
|---|
| 2794 | 2921 | panic("netlink_init: Cannot allocate nl_table\n"); |
|---|
| 2795 | 2922 | } |
|---|
| 2796 | 2923 | |
|---|
| 2797 | | -#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT |
|---|
| 2798 | | -core_initcall_sync(netlink_proto_init); |
|---|
| 2799 | | -#else |
|---|
| 2800 | 2924 | core_initcall(netlink_proto_init); |
|---|
| 2801 | | -#endif |
|---|