162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NETLINK Kernel-user communication protocol. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors: Alan Cox <alan@lxorguk.ukuu.org.uk> 662306a36Sopenharmony_ci * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 762306a36Sopenharmony_ci * Patrick McHardy <kaber@trash.net> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith 1062306a36Sopenharmony_ci * added netlink_proto_exit 1162306a36Sopenharmony_ci * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br> 1262306a36Sopenharmony_ci * use nlk_sk, as sk->protinfo is on a diet 8) 1362306a36Sopenharmony_ci * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org> 1462306a36Sopenharmony_ci * - inc module use count of module that owns 1562306a36Sopenharmony_ci * the kernel socket in case userspace opens 1662306a36Sopenharmony_ci * socket of same protocol 1762306a36Sopenharmony_ci * - remove all module support, since netlink is 1862306a36Sopenharmony_ci * mandatory if CONFIG_NET=y these days 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/module.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/bpf.h> 2462306a36Sopenharmony_ci#include <linux/capability.h> 2562306a36Sopenharmony_ci#include <linux/kernel.h> 2662306a36Sopenharmony_ci#include <linux/filter.h> 2762306a36Sopenharmony_ci#include <linux/init.h> 2862306a36Sopenharmony_ci#include <linux/signal.h> 2962306a36Sopenharmony_ci#include <linux/sched.h> 3062306a36Sopenharmony_ci#include <linux/errno.h> 3162306a36Sopenharmony_ci#include <linux/string.h> 3262306a36Sopenharmony_ci#include <linux/stat.h> 3362306a36Sopenharmony_ci#include <linux/socket.h> 3462306a36Sopenharmony_ci#include <linux/un.h> 3562306a36Sopenharmony_ci#include <linux/fcntl.h> 3662306a36Sopenharmony_ci#include <linux/termios.h> 3762306a36Sopenharmony_ci#include <linux/sockios.h> 3862306a36Sopenharmony_ci#include <linux/net.h> 3962306a36Sopenharmony_ci#include <linux/fs.h> 4062306a36Sopenharmony_ci#include <linux/slab.h> 4162306a36Sopenharmony_ci#include <linux/uaccess.h> 4262306a36Sopenharmony_ci#include <linux/skbuff.h> 4362306a36Sopenharmony_ci#include <linux/netdevice.h> 4462306a36Sopenharmony_ci#include <linux/rtnetlink.h> 4562306a36Sopenharmony_ci#include <linux/proc_fs.h> 4662306a36Sopenharmony_ci#include <linux/seq_file.h> 4762306a36Sopenharmony_ci#include <linux/notifier.h> 4862306a36Sopenharmony_ci#include <linux/security.h> 4962306a36Sopenharmony_ci#include <linux/jhash.h> 5062306a36Sopenharmony_ci#include <linux/jiffies.h> 5162306a36Sopenharmony_ci#include <linux/random.h> 5262306a36Sopenharmony_ci#include <linux/bitops.h> 5362306a36Sopenharmony_ci#include <linux/mm.h> 5462306a36Sopenharmony_ci#include <linux/types.h> 5562306a36Sopenharmony_ci#include <linux/audit.h> 5662306a36Sopenharmony_ci#include <linux/mutex.h> 5762306a36Sopenharmony_ci#include <linux/vmalloc.h> 5862306a36Sopenharmony_ci#include <linux/if_arp.h> 5962306a36Sopenharmony_ci#include <linux/rhashtable.h> 6062306a36Sopenharmony_ci#include <asm/cacheflush.h> 6162306a36Sopenharmony_ci#include <linux/hash.h> 6262306a36Sopenharmony_ci#include <linux/genetlink.h> 6362306a36Sopenharmony_ci#include <linux/net_namespace.h> 6462306a36Sopenharmony_ci#include <linux/nospec.h> 6562306a36Sopenharmony_ci#include <linux/btf_ids.h> 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#include <net/net_namespace.h> 6862306a36Sopenharmony_ci#include <net/netns/generic.h> 6962306a36Sopenharmony_ci#include <net/sock.h> 7062306a36Sopenharmony_ci#include <net/scm.h> 7162306a36Sopenharmony_ci#include <net/netlink.h> 7262306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 7362306a36Sopenharmony_ci#include <trace/events/netlink.h> 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#include "af_netlink.h" 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistruct listeners { 7862306a36Sopenharmony_ci struct rcu_head rcu; 7962306a36Sopenharmony_ci unsigned long masks[]; 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* state bits */ 8362306a36Sopenharmony_ci#define NETLINK_S_CONGESTED 0x0 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic inline int netlink_is_kernel(struct sock *sk) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci return nlk_test_bit(KERNEL_SOCKET, sk); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistruct netlink_table *nl_table __read_mostly; 9162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nl_table); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic struct lock_class_key nlk_cb_mutex_keys[MAX_LINKS]; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic const char *const nlk_cb_mutex_key_strings[MAX_LINKS + 1] = { 9862306a36Sopenharmony_ci "nlk_cb_mutex-ROUTE", 9962306a36Sopenharmony_ci "nlk_cb_mutex-1", 10062306a36Sopenharmony_ci "nlk_cb_mutex-USERSOCK", 10162306a36Sopenharmony_ci "nlk_cb_mutex-FIREWALL", 10262306a36Sopenharmony_ci "nlk_cb_mutex-SOCK_DIAG", 10362306a36Sopenharmony_ci "nlk_cb_mutex-NFLOG", 10462306a36Sopenharmony_ci "nlk_cb_mutex-XFRM", 10562306a36Sopenharmony_ci "nlk_cb_mutex-SELINUX", 10662306a36Sopenharmony_ci "nlk_cb_mutex-ISCSI", 10762306a36Sopenharmony_ci "nlk_cb_mutex-AUDIT", 10862306a36Sopenharmony_ci "nlk_cb_mutex-FIB_LOOKUP", 10962306a36Sopenharmony_ci "nlk_cb_mutex-CONNECTOR", 11062306a36Sopenharmony_ci "nlk_cb_mutex-NETFILTER", 11162306a36Sopenharmony_ci "nlk_cb_mutex-IP6_FW", 11262306a36Sopenharmony_ci "nlk_cb_mutex-DNRTMSG", 11362306a36Sopenharmony_ci "nlk_cb_mutex-KOBJECT_UEVENT", 11462306a36Sopenharmony_ci "nlk_cb_mutex-GENERIC", 11562306a36Sopenharmony_ci "nlk_cb_mutex-17", 11662306a36Sopenharmony_ci "nlk_cb_mutex-SCSITRANSPORT", 11762306a36Sopenharmony_ci "nlk_cb_mutex-ECRYPTFS", 11862306a36Sopenharmony_ci "nlk_cb_mutex-RDMA", 11962306a36Sopenharmony_ci "nlk_cb_mutex-CRYPTO", 12062306a36Sopenharmony_ci "nlk_cb_mutex-SMC", 12162306a36Sopenharmony_ci "nlk_cb_mutex-23", 12262306a36Sopenharmony_ci "nlk_cb_mutex-24", 12362306a36Sopenharmony_ci "nlk_cb_mutex-25", 12462306a36Sopenharmony_ci "nlk_cb_mutex-26", 12562306a36Sopenharmony_ci "nlk_cb_mutex-27", 12662306a36Sopenharmony_ci "nlk_cb_mutex-28", 12762306a36Sopenharmony_ci "nlk_cb_mutex-29", 12862306a36Sopenharmony_ci "nlk_cb_mutex-30", 12962306a36Sopenharmony_ci "nlk_cb_mutex-31", 13062306a36Sopenharmony_ci "nlk_cb_mutex-MAX_LINKS" 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic int netlink_dump(struct sock *sk); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* nl_table locking explained: 13662306a36Sopenharmony_ci * Lookup and traversal are protected with an RCU read-side lock. Insertion 13762306a36Sopenharmony_ci * and removal are protected with per bucket lock while using RCU list 13862306a36Sopenharmony_ci * modification primitives and may run in parallel to RCU protected lookups. 13962306a36Sopenharmony_ci * Destruction of the Netlink socket may only occur *after* nl_table_lock has 14062306a36Sopenharmony_ci * been acquired * either during or after the socket has been removed from 14162306a36Sopenharmony_ci * the list and after an RCU grace period. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ciDEFINE_RWLOCK(nl_table_lock); 14462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nl_table_lock); 14562306a36Sopenharmony_cistatic atomic_t nl_table_users = ATOMIC_INIT(0); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock)); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic BLOCKING_NOTIFIER_HEAD(netlink_chain); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic const struct rhashtable_params netlink_rhashtable_params; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_civoid do_trace_netlink_extack(const char *msg) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci trace_netlink_extack(msg); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ciEXPORT_SYMBOL(do_trace_netlink_extack); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic inline u32 netlink_group_mask(u32 group) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci if (group > 32) 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci return group ? 1 << (group - 1) : 0; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb, 16862306a36Sopenharmony_ci gfp_t gfp_mask) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci unsigned int len = skb->len; 17162306a36Sopenharmony_ci struct sk_buff *new; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci new = alloc_skb(len, gfp_mask); 17462306a36Sopenharmony_ci if (new == NULL) 17562306a36Sopenharmony_ci return NULL; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci NETLINK_CB(new).portid = NETLINK_CB(skb).portid; 17862306a36Sopenharmony_ci NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group; 17962306a36Sopenharmony_ci NETLINK_CB(new).creds = NETLINK_CB(skb).creds; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci skb_put_data(new, skb->data, len); 18262306a36Sopenharmony_ci return new; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic unsigned int netlink_tap_net_id; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistruct netlink_tap_net { 18862306a36Sopenharmony_ci struct list_head netlink_tap_all; 18962306a36Sopenharmony_ci struct mutex netlink_tap_lock; 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciint netlink_add_tap(struct netlink_tap *nt) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct net *net = dev_net(nt->dev); 19562306a36Sopenharmony_ci struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (unlikely(nt->dev->type != ARPHRD_NETLINK)) 19862306a36Sopenharmony_ci return -EINVAL; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci mutex_lock(&nn->netlink_tap_lock); 20162306a36Sopenharmony_ci list_add_rcu(&nt->list, &nn->netlink_tap_all); 20262306a36Sopenharmony_ci mutex_unlock(&nn->netlink_tap_lock); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci __module_get(nt->module); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(netlink_add_tap); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int __netlink_remove_tap(struct netlink_tap *nt) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct net *net = dev_net(nt->dev); 21362306a36Sopenharmony_ci struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id); 21462306a36Sopenharmony_ci bool found = false; 21562306a36Sopenharmony_ci struct netlink_tap *tmp; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci mutex_lock(&nn->netlink_tap_lock); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci list_for_each_entry(tmp, &nn->netlink_tap_all, list) { 22062306a36Sopenharmony_ci if (nt == tmp) { 22162306a36Sopenharmony_ci list_del_rcu(&nt->list); 22262306a36Sopenharmony_ci found = true; 22362306a36Sopenharmony_ci goto out; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci pr_warn("__netlink_remove_tap: %p not found\n", nt); 22862306a36Sopenharmony_ciout: 22962306a36Sopenharmony_ci mutex_unlock(&nn->netlink_tap_lock); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (found) 23262306a36Sopenharmony_ci module_put(nt->module); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return found ? 0 : -ENODEV; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciint netlink_remove_tap(struct netlink_tap *nt) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci int ret; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci ret = __netlink_remove_tap(nt); 24262306a36Sopenharmony_ci synchronize_net(); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci return ret; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(netlink_remove_tap); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic __net_init int netlink_tap_init_net(struct net *net) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci INIT_LIST_HEAD(&nn->netlink_tap_all); 25362306a36Sopenharmony_ci mutex_init(&nn->netlink_tap_lock); 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic struct pernet_operations netlink_tap_net_ops = { 25862306a36Sopenharmony_ci .init = netlink_tap_init_net, 25962306a36Sopenharmony_ci .id = &netlink_tap_net_id, 26062306a36Sopenharmony_ci .size = sizeof(struct netlink_tap_net), 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic bool netlink_filter_tap(const struct sk_buff *skb) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct sock *sk = skb->sk; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci /* We take the more conservative approach and 26862306a36Sopenharmony_ci * whitelist socket protocols that may pass. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci switch (sk->sk_protocol) { 27162306a36Sopenharmony_ci case NETLINK_ROUTE: 27262306a36Sopenharmony_ci case NETLINK_USERSOCK: 27362306a36Sopenharmony_ci case NETLINK_SOCK_DIAG: 27462306a36Sopenharmony_ci case NETLINK_NFLOG: 27562306a36Sopenharmony_ci case NETLINK_XFRM: 27662306a36Sopenharmony_ci case NETLINK_FIB_LOOKUP: 27762306a36Sopenharmony_ci case NETLINK_NETFILTER: 27862306a36Sopenharmony_ci case NETLINK_GENERIC: 27962306a36Sopenharmony_ci return true; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci return false; 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int __netlink_deliver_tap_skb(struct sk_buff *skb, 28662306a36Sopenharmony_ci struct net_device *dev) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct sk_buff *nskb; 28962306a36Sopenharmony_ci struct sock *sk = skb->sk; 29062306a36Sopenharmony_ci int ret = -ENOMEM; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (!net_eq(dev_net(dev), sock_net(sk))) 29362306a36Sopenharmony_ci return 0; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci dev_hold(dev); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (is_vmalloc_addr(skb->head)) 29862306a36Sopenharmony_ci nskb = netlink_to_full_skb(skb, GFP_ATOMIC); 29962306a36Sopenharmony_ci else 30062306a36Sopenharmony_ci nskb = skb_clone(skb, GFP_ATOMIC); 30162306a36Sopenharmony_ci if (nskb) { 30262306a36Sopenharmony_ci nskb->dev = dev; 30362306a36Sopenharmony_ci nskb->protocol = htons((u16) sk->sk_protocol); 30462306a36Sopenharmony_ci nskb->pkt_type = netlink_is_kernel(sk) ? 30562306a36Sopenharmony_ci PACKET_KERNEL : PACKET_USER; 30662306a36Sopenharmony_ci skb_reset_network_header(nskb); 30762306a36Sopenharmony_ci ret = dev_queue_xmit(nskb); 30862306a36Sopenharmony_ci if (unlikely(ret > 0)) 30962306a36Sopenharmony_ci ret = net_xmit_errno(ret); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci dev_put(dev); 31362306a36Sopenharmony_ci return ret; 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic void __netlink_deliver_tap(struct sk_buff *skb, struct netlink_tap_net *nn) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci int ret; 31962306a36Sopenharmony_ci struct netlink_tap *tmp; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci if (!netlink_filter_tap(skb)) 32262306a36Sopenharmony_ci return; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci list_for_each_entry_rcu(tmp, &nn->netlink_tap_all, list) { 32562306a36Sopenharmony_ci ret = __netlink_deliver_tap_skb(skb, tmp->dev); 32662306a36Sopenharmony_ci if (unlikely(ret)) 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic void netlink_deliver_tap(struct net *net, struct sk_buff *skb) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci rcu_read_lock(); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci if (unlikely(!list_empty(&nn->netlink_tap_all))) 33862306a36Sopenharmony_ci __netlink_deliver_tap(skb, nn); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci rcu_read_unlock(); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic void netlink_deliver_tap_kernel(struct sock *dst, struct sock *src, 34462306a36Sopenharmony_ci struct sk_buff *skb) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci if (!(netlink_is_kernel(dst) && netlink_is_kernel(src))) 34762306a36Sopenharmony_ci netlink_deliver_tap(sock_net(dst), skb); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic void netlink_overrun(struct sock *sk) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci if (!nlk_test_bit(RECV_NO_ENOBUFS, sk)) { 35362306a36Sopenharmony_ci if (!test_and_set_bit(NETLINK_S_CONGESTED, 35462306a36Sopenharmony_ci &nlk_sk(sk)->state)) { 35562306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err, ENOBUFS); 35662306a36Sopenharmony_ci sk_error_report(sk); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci atomic_inc(&sk->sk_drops); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void netlink_rcv_wake(struct sock *sk) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (skb_queue_empty_lockless(&sk->sk_receive_queue)) 36762306a36Sopenharmony_ci clear_bit(NETLINK_S_CONGESTED, &nlk->state); 36862306a36Sopenharmony_ci if (!test_bit(NETLINK_S_CONGESTED, &nlk->state)) 36962306a36Sopenharmony_ci wake_up_interruptible(&nlk->wait); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic void netlink_skb_destructor(struct sk_buff *skb) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci if (is_vmalloc_addr(skb->head)) { 37562306a36Sopenharmony_ci if (!skb->cloned || 37662306a36Sopenharmony_ci !atomic_dec_return(&(skb_shinfo(skb)->dataref))) 37762306a36Sopenharmony_ci vfree_atomic(skb->head); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci skb->head = NULL; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci if (skb->sk != NULL) 38262306a36Sopenharmony_ci sock_rfree(skb); 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci WARN_ON(skb->sk != NULL); 38862306a36Sopenharmony_ci skb->sk = sk; 38962306a36Sopenharmony_ci skb->destructor = netlink_skb_destructor; 39062306a36Sopenharmony_ci atomic_add(skb->truesize, &sk->sk_rmem_alloc); 39162306a36Sopenharmony_ci sk_mem_charge(sk, skb->truesize); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic void netlink_sock_destruct(struct sock *sk) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (nlk->cb_running) { 39962306a36Sopenharmony_ci if (nlk->cb.done) 40062306a36Sopenharmony_ci nlk->cb.done(&nlk->cb); 40162306a36Sopenharmony_ci module_put(nlk->cb.module); 40262306a36Sopenharmony_ci kfree_skb(nlk->cb.skb); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (!sock_flag(sk, SOCK_DEAD)) { 40862306a36Sopenharmony_ci printk(KERN_ERR "Freeing alive netlink socket %p\n", sk); 40962306a36Sopenharmony_ci return; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci WARN_ON(atomic_read(&sk->sk_rmem_alloc)); 41362306a36Sopenharmony_ci WARN_ON(refcount_read(&sk->sk_wmem_alloc)); 41462306a36Sopenharmony_ci WARN_ON(nlk_sk(sk)->groups); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic void netlink_sock_destruct_work(struct work_struct *work) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct netlink_sock *nlk = container_of(work, struct netlink_sock, 42062306a36Sopenharmony_ci work); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci sk_free(&nlk->sk); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on 42662306a36Sopenharmony_ci * SMP. Look, when several writers sleep and reader wakes them up, all but one 42762306a36Sopenharmony_ci * immediately hit write lock and grab all the cpus. Exclusive sleep solves 42862306a36Sopenharmony_ci * this, _but_ remember, it adds useless work on UP machines. 42962306a36Sopenharmony_ci */ 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_civoid netlink_table_grab(void) 43262306a36Sopenharmony_ci __acquires(nl_table_lock) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci might_sleep(); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci write_lock_irq(&nl_table_lock); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (atomic_read(&nl_table_users)) { 43962306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci add_wait_queue_exclusive(&nl_table_wait, &wait); 44262306a36Sopenharmony_ci for (;;) { 44362306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 44462306a36Sopenharmony_ci if (atomic_read(&nl_table_users) == 0) 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci write_unlock_irq(&nl_table_lock); 44762306a36Sopenharmony_ci schedule(); 44862306a36Sopenharmony_ci write_lock_irq(&nl_table_lock); 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 45262306a36Sopenharmony_ci remove_wait_queue(&nl_table_wait, &wait); 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_civoid netlink_table_ungrab(void) 45762306a36Sopenharmony_ci __releases(nl_table_lock) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci write_unlock_irq(&nl_table_lock); 46062306a36Sopenharmony_ci wake_up(&nl_table_wait); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic inline void 46462306a36Sopenharmony_cinetlink_lock_table(void) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci unsigned long flags; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* read_lock() synchronizes us to netlink_table_grab */ 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci read_lock_irqsave(&nl_table_lock, flags); 47162306a36Sopenharmony_ci atomic_inc(&nl_table_users); 47262306a36Sopenharmony_ci read_unlock_irqrestore(&nl_table_lock, flags); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic inline void 47662306a36Sopenharmony_cinetlink_unlock_table(void) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci if (atomic_dec_and_test(&nl_table_users)) 47962306a36Sopenharmony_ci wake_up(&nl_table_wait); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistruct netlink_compare_arg 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci possible_net_t pnet; 48562306a36Sopenharmony_ci u32 portid; 48662306a36Sopenharmony_ci}; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci/* Doing sizeof directly may yield 4 extra bytes on 64-bit. */ 48962306a36Sopenharmony_ci#define netlink_compare_arg_len \ 49062306a36Sopenharmony_ci (offsetof(struct netlink_compare_arg, portid) + sizeof(u32)) 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic inline int netlink_compare(struct rhashtable_compare_arg *arg, 49362306a36Sopenharmony_ci const void *ptr) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci const struct netlink_compare_arg *x = arg->key; 49662306a36Sopenharmony_ci const struct netlink_sock *nlk = ptr; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return nlk->portid != x->portid || 49962306a36Sopenharmony_ci !net_eq(sock_net(&nlk->sk), read_pnet(&x->pnet)); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic void netlink_compare_arg_init(struct netlink_compare_arg *arg, 50362306a36Sopenharmony_ci struct net *net, u32 portid) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci memset(arg, 0, sizeof(*arg)); 50662306a36Sopenharmony_ci write_pnet(&arg->pnet, net); 50762306a36Sopenharmony_ci arg->portid = portid; 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic struct sock *__netlink_lookup(struct netlink_table *table, u32 portid, 51162306a36Sopenharmony_ci struct net *net) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci struct netlink_compare_arg arg; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci netlink_compare_arg_init(&arg, net, portid); 51662306a36Sopenharmony_ci return rhashtable_lookup_fast(&table->hash, &arg, 51762306a36Sopenharmony_ci netlink_rhashtable_params); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic int __netlink_insert(struct netlink_table *table, struct sock *sk) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci struct netlink_compare_arg arg; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci netlink_compare_arg_init(&arg, sock_net(sk), nlk_sk(sk)->portid); 52562306a36Sopenharmony_ci return rhashtable_lookup_insert_key(&table->hash, &arg, 52662306a36Sopenharmony_ci &nlk_sk(sk)->node, 52762306a36Sopenharmony_ci netlink_rhashtable_params); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic struct sock *netlink_lookup(struct net *net, int protocol, u32 portid) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci struct netlink_table *table = &nl_table[protocol]; 53362306a36Sopenharmony_ci struct sock *sk; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci rcu_read_lock(); 53662306a36Sopenharmony_ci sk = __netlink_lookup(table, portid, net); 53762306a36Sopenharmony_ci if (sk) 53862306a36Sopenharmony_ci sock_hold(sk); 53962306a36Sopenharmony_ci rcu_read_unlock(); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return sk; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic const struct proto_ops netlink_ops; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic void 54762306a36Sopenharmony_cinetlink_update_listeners(struct sock *sk) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct netlink_table *tbl = &nl_table[sk->sk_protocol]; 55062306a36Sopenharmony_ci unsigned long mask; 55162306a36Sopenharmony_ci unsigned int i; 55262306a36Sopenharmony_ci struct listeners *listeners; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci listeners = nl_deref_protected(tbl->listeners); 55562306a36Sopenharmony_ci if (!listeners) 55662306a36Sopenharmony_ci return; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci for (i = 0; i < NLGRPLONGS(tbl->groups); i++) { 55962306a36Sopenharmony_ci mask = 0; 56062306a36Sopenharmony_ci sk_for_each_bound(sk, &tbl->mc_list) { 56162306a36Sopenharmony_ci if (i < NLGRPLONGS(nlk_sk(sk)->ngroups)) 56262306a36Sopenharmony_ci mask |= nlk_sk(sk)->groups[i]; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci listeners->masks[i] = mask; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci /* this function is only called with the netlink table "grabbed", which 56762306a36Sopenharmony_ci * makes sure updates are visible before bind or setsockopt return. */ 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_cistatic int netlink_insert(struct sock *sk, u32 portid) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct netlink_table *table = &nl_table[sk->sk_protocol]; 57362306a36Sopenharmony_ci int err; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci lock_sock(sk); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY; 57862306a36Sopenharmony_ci if (nlk_sk(sk)->bound) 57962306a36Sopenharmony_ci goto err; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* portid can be read locklessly from netlink_getname(). */ 58262306a36Sopenharmony_ci WRITE_ONCE(nlk_sk(sk)->portid, portid); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci sock_hold(sk); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci err = __netlink_insert(table, sk); 58762306a36Sopenharmony_ci if (err) { 58862306a36Sopenharmony_ci /* In case the hashtable backend returns with -EBUSY 58962306a36Sopenharmony_ci * from here, it must not escape to the caller. 59062306a36Sopenharmony_ci */ 59162306a36Sopenharmony_ci if (unlikely(err == -EBUSY)) 59262306a36Sopenharmony_ci err = -EOVERFLOW; 59362306a36Sopenharmony_ci if (err == -EEXIST) 59462306a36Sopenharmony_ci err = -EADDRINUSE; 59562306a36Sopenharmony_ci sock_put(sk); 59662306a36Sopenharmony_ci goto err; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci /* We need to ensure that the socket is hashed and visible. */ 60062306a36Sopenharmony_ci smp_wmb(); 60162306a36Sopenharmony_ci /* Paired with lockless reads from netlink_bind(), 60262306a36Sopenharmony_ci * netlink_connect() and netlink_sendmsg(). 60362306a36Sopenharmony_ci */ 60462306a36Sopenharmony_ci WRITE_ONCE(nlk_sk(sk)->bound, portid); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cierr: 60762306a36Sopenharmony_ci release_sock(sk); 60862306a36Sopenharmony_ci return err; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic void netlink_remove(struct sock *sk) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct netlink_table *table; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci table = &nl_table[sk->sk_protocol]; 61662306a36Sopenharmony_ci if (!rhashtable_remove_fast(&table->hash, &nlk_sk(sk)->node, 61762306a36Sopenharmony_ci netlink_rhashtable_params)) { 61862306a36Sopenharmony_ci WARN_ON(refcount_read(&sk->sk_refcnt) == 1); 61962306a36Sopenharmony_ci __sock_put(sk); 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci netlink_table_grab(); 62362306a36Sopenharmony_ci if (nlk_sk(sk)->subscriptions) { 62462306a36Sopenharmony_ci __sk_del_bind_node(sk); 62562306a36Sopenharmony_ci netlink_update_listeners(sk); 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci if (sk->sk_protocol == NETLINK_GENERIC) 62862306a36Sopenharmony_ci atomic_inc(&genl_sk_destructing_cnt); 62962306a36Sopenharmony_ci netlink_table_ungrab(); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic struct proto netlink_proto = { 63362306a36Sopenharmony_ci .name = "NETLINK", 63462306a36Sopenharmony_ci .owner = THIS_MODULE, 63562306a36Sopenharmony_ci .obj_size = sizeof(struct netlink_sock), 63662306a36Sopenharmony_ci}; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic int __netlink_create(struct net *net, struct socket *sock, 63962306a36Sopenharmony_ci struct mutex *cb_mutex, int protocol, 64062306a36Sopenharmony_ci int kern) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct sock *sk; 64362306a36Sopenharmony_ci struct netlink_sock *nlk; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci sock->ops = &netlink_ops; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto, kern); 64862306a36Sopenharmony_ci if (!sk) 64962306a36Sopenharmony_ci return -ENOMEM; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci sock_init_data(sock, sk); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci nlk = nlk_sk(sk); 65462306a36Sopenharmony_ci if (cb_mutex) { 65562306a36Sopenharmony_ci nlk->cb_mutex = cb_mutex; 65662306a36Sopenharmony_ci } else { 65762306a36Sopenharmony_ci nlk->cb_mutex = &nlk->cb_def_mutex; 65862306a36Sopenharmony_ci mutex_init(nlk->cb_mutex); 65962306a36Sopenharmony_ci lockdep_set_class_and_name(nlk->cb_mutex, 66062306a36Sopenharmony_ci nlk_cb_mutex_keys + protocol, 66162306a36Sopenharmony_ci nlk_cb_mutex_key_strings[protocol]); 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci init_waitqueue_head(&nlk->wait); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci sk->sk_destruct = netlink_sock_destruct; 66662306a36Sopenharmony_ci sk->sk_protocol = protocol; 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic int netlink_create(struct net *net, struct socket *sock, int protocol, 67162306a36Sopenharmony_ci int kern) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct module *module = NULL; 67462306a36Sopenharmony_ci struct mutex *cb_mutex; 67562306a36Sopenharmony_ci struct netlink_sock *nlk; 67662306a36Sopenharmony_ci int (*bind)(struct net *net, int group); 67762306a36Sopenharmony_ci void (*unbind)(struct net *net, int group); 67862306a36Sopenharmony_ci void (*release)(struct sock *sock, unsigned long *groups); 67962306a36Sopenharmony_ci int err = 0; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci sock->state = SS_UNCONNECTED; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) 68462306a36Sopenharmony_ci return -ESOCKTNOSUPPORT; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (protocol < 0 || protocol >= MAX_LINKS) 68762306a36Sopenharmony_ci return -EPROTONOSUPPORT; 68862306a36Sopenharmony_ci protocol = array_index_nospec(protocol, MAX_LINKS); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci netlink_lock_table(); 69162306a36Sopenharmony_ci#ifdef CONFIG_MODULES 69262306a36Sopenharmony_ci if (!nl_table[protocol].registered) { 69362306a36Sopenharmony_ci netlink_unlock_table(); 69462306a36Sopenharmony_ci request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); 69562306a36Sopenharmony_ci netlink_lock_table(); 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci#endif 69862306a36Sopenharmony_ci if (nl_table[protocol].registered && 69962306a36Sopenharmony_ci try_module_get(nl_table[protocol].module)) 70062306a36Sopenharmony_ci module = nl_table[protocol].module; 70162306a36Sopenharmony_ci else 70262306a36Sopenharmony_ci err = -EPROTONOSUPPORT; 70362306a36Sopenharmony_ci cb_mutex = nl_table[protocol].cb_mutex; 70462306a36Sopenharmony_ci bind = nl_table[protocol].bind; 70562306a36Sopenharmony_ci unbind = nl_table[protocol].unbind; 70662306a36Sopenharmony_ci release = nl_table[protocol].release; 70762306a36Sopenharmony_ci netlink_unlock_table(); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (err < 0) 71062306a36Sopenharmony_ci goto out; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci err = __netlink_create(net, sock, cb_mutex, protocol, kern); 71362306a36Sopenharmony_ci if (err < 0) 71462306a36Sopenharmony_ci goto out_module; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci sock_prot_inuse_add(net, &netlink_proto, 1); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci nlk = nlk_sk(sock->sk); 71962306a36Sopenharmony_ci nlk->module = module; 72062306a36Sopenharmony_ci nlk->netlink_bind = bind; 72162306a36Sopenharmony_ci nlk->netlink_unbind = unbind; 72262306a36Sopenharmony_ci nlk->netlink_release = release; 72362306a36Sopenharmony_ciout: 72462306a36Sopenharmony_ci return err; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ciout_module: 72762306a36Sopenharmony_ci module_put(module); 72862306a36Sopenharmony_ci goto out; 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic void deferred_put_nlk_sk(struct rcu_head *head) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu); 73462306a36Sopenharmony_ci struct sock *sk = &nlk->sk; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci kfree(nlk->groups); 73762306a36Sopenharmony_ci nlk->groups = NULL; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (!refcount_dec_and_test(&sk->sk_refcnt)) 74062306a36Sopenharmony_ci return; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (nlk->cb_running && nlk->cb.done) { 74362306a36Sopenharmony_ci INIT_WORK(&nlk->work, netlink_sock_destruct_work); 74462306a36Sopenharmony_ci schedule_work(&nlk->work); 74562306a36Sopenharmony_ci return; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci sk_free(sk); 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic int netlink_release(struct socket *sock) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct sock *sk = sock->sk; 75462306a36Sopenharmony_ci struct netlink_sock *nlk; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (!sk) 75762306a36Sopenharmony_ci return 0; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci netlink_remove(sk); 76062306a36Sopenharmony_ci sock_orphan(sk); 76162306a36Sopenharmony_ci nlk = nlk_sk(sk); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* 76462306a36Sopenharmony_ci * OK. Socket is unlinked, any packets that arrive now 76562306a36Sopenharmony_ci * will be purged. 76662306a36Sopenharmony_ci */ 76762306a36Sopenharmony_ci if (nlk->netlink_release) 76862306a36Sopenharmony_ci nlk->netlink_release(sk, nlk->groups); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* must not acquire netlink_table_lock in any way again before unbind 77162306a36Sopenharmony_ci * and notifying genetlink is done as otherwise it might deadlock 77262306a36Sopenharmony_ci */ 77362306a36Sopenharmony_ci if (nlk->netlink_unbind) { 77462306a36Sopenharmony_ci int i; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci for (i = 0; i < nlk->ngroups; i++) 77762306a36Sopenharmony_ci if (test_bit(i, nlk->groups)) 77862306a36Sopenharmony_ci nlk->netlink_unbind(sock_net(sk), i + 1); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci if (sk->sk_protocol == NETLINK_GENERIC && 78162306a36Sopenharmony_ci atomic_dec_return(&genl_sk_destructing_cnt) == 0) 78262306a36Sopenharmony_ci wake_up(&genl_sk_destructing_waitq); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci sock->sk = NULL; 78562306a36Sopenharmony_ci wake_up_interruptible_all(&nlk->wait); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci skb_queue_purge(&sk->sk_write_queue); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (nlk->portid && nlk->bound) { 79062306a36Sopenharmony_ci struct netlink_notify n = { 79162306a36Sopenharmony_ci .net = sock_net(sk), 79262306a36Sopenharmony_ci .protocol = sk->sk_protocol, 79362306a36Sopenharmony_ci .portid = nlk->portid, 79462306a36Sopenharmony_ci }; 79562306a36Sopenharmony_ci blocking_notifier_call_chain(&netlink_chain, 79662306a36Sopenharmony_ci NETLINK_URELEASE, &n); 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci module_put(nlk->module); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (netlink_is_kernel(sk)) { 80262306a36Sopenharmony_ci netlink_table_grab(); 80362306a36Sopenharmony_ci BUG_ON(nl_table[sk->sk_protocol].registered == 0); 80462306a36Sopenharmony_ci if (--nl_table[sk->sk_protocol].registered == 0) { 80562306a36Sopenharmony_ci struct listeners *old; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci old = nl_deref_protected(nl_table[sk->sk_protocol].listeners); 80862306a36Sopenharmony_ci RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL); 80962306a36Sopenharmony_ci kfree_rcu(old, rcu); 81062306a36Sopenharmony_ci nl_table[sk->sk_protocol].module = NULL; 81162306a36Sopenharmony_ci nl_table[sk->sk_protocol].bind = NULL; 81262306a36Sopenharmony_ci nl_table[sk->sk_protocol].unbind = NULL; 81362306a36Sopenharmony_ci nl_table[sk->sk_protocol].flags = 0; 81462306a36Sopenharmony_ci nl_table[sk->sk_protocol].registered = 0; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci netlink_table_ungrab(); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* Because struct net might disappear soon, do not keep a pointer. */ 82262306a36Sopenharmony_ci if (!sk->sk_net_refcnt && sock_net(sk) != &init_net) { 82362306a36Sopenharmony_ci __netns_tracker_free(sock_net(sk), &sk->ns_tracker, false); 82462306a36Sopenharmony_ci /* Because of deferred_put_nlk_sk and use of work queue, 82562306a36Sopenharmony_ci * it is possible netns will be freed before this socket. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci sock_net_set(sk, &init_net); 82862306a36Sopenharmony_ci __netns_tracker_alloc(&init_net, &sk->ns_tracker, 82962306a36Sopenharmony_ci false, GFP_KERNEL); 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci call_rcu(&nlk->rcu, deferred_put_nlk_sk); 83262306a36Sopenharmony_ci return 0; 83362306a36Sopenharmony_ci} 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cistatic int netlink_autobind(struct socket *sock) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci struct sock *sk = sock->sk; 83862306a36Sopenharmony_ci struct net *net = sock_net(sk); 83962306a36Sopenharmony_ci struct netlink_table *table = &nl_table[sk->sk_protocol]; 84062306a36Sopenharmony_ci s32 portid = task_tgid_vnr(current); 84162306a36Sopenharmony_ci int err; 84262306a36Sopenharmony_ci s32 rover = -4096; 84362306a36Sopenharmony_ci bool ok; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ciretry: 84662306a36Sopenharmony_ci cond_resched(); 84762306a36Sopenharmony_ci rcu_read_lock(); 84862306a36Sopenharmony_ci ok = !__netlink_lookup(table, portid, net); 84962306a36Sopenharmony_ci rcu_read_unlock(); 85062306a36Sopenharmony_ci if (!ok) { 85162306a36Sopenharmony_ci /* Bind collision, search negative portid values. */ 85262306a36Sopenharmony_ci if (rover == -4096) 85362306a36Sopenharmony_ci /* rover will be in range [S32_MIN, -4097] */ 85462306a36Sopenharmony_ci rover = S32_MIN + get_random_u32_below(-4096 - S32_MIN); 85562306a36Sopenharmony_ci else if (rover >= -4096) 85662306a36Sopenharmony_ci rover = -4097; 85762306a36Sopenharmony_ci portid = rover--; 85862306a36Sopenharmony_ci goto retry; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci err = netlink_insert(sk, portid); 86262306a36Sopenharmony_ci if (err == -EADDRINUSE) 86362306a36Sopenharmony_ci goto retry; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci /* If 2 threads race to autobind, that is fine. */ 86662306a36Sopenharmony_ci if (err == -EBUSY) 86762306a36Sopenharmony_ci err = 0; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci return err; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci/** 87362306a36Sopenharmony_ci * __netlink_ns_capable - General netlink message capability test 87462306a36Sopenharmony_ci * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace. 87562306a36Sopenharmony_ci * @user_ns: The user namespace of the capability to use 87662306a36Sopenharmony_ci * @cap: The capability to use 87762306a36Sopenharmony_ci * 87862306a36Sopenharmony_ci * Test to see if the opener of the socket we received the message 87962306a36Sopenharmony_ci * from had when the netlink socket was created and the sender of the 88062306a36Sopenharmony_ci * message has the capability @cap in the user namespace @user_ns. 88162306a36Sopenharmony_ci */ 88262306a36Sopenharmony_cibool __netlink_ns_capable(const struct netlink_skb_parms *nsp, 88362306a36Sopenharmony_ci struct user_namespace *user_ns, int cap) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci return ((nsp->flags & NETLINK_SKB_DST) || 88662306a36Sopenharmony_ci file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) && 88762306a36Sopenharmony_ci ns_capable(user_ns, cap); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ciEXPORT_SYMBOL(__netlink_ns_capable); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci/** 89262306a36Sopenharmony_ci * netlink_ns_capable - General netlink message capability test 89362306a36Sopenharmony_ci * @skb: socket buffer holding a netlink command from userspace 89462306a36Sopenharmony_ci * @user_ns: The user namespace of the capability to use 89562306a36Sopenharmony_ci * @cap: The capability to use 89662306a36Sopenharmony_ci * 89762306a36Sopenharmony_ci * Test to see if the opener of the socket we received the message 89862306a36Sopenharmony_ci * from had when the netlink socket was created and the sender of the 89962306a36Sopenharmony_ci * message has the capability @cap in the user namespace @user_ns. 90062306a36Sopenharmony_ci */ 90162306a36Sopenharmony_cibool netlink_ns_capable(const struct sk_buff *skb, 90262306a36Sopenharmony_ci struct user_namespace *user_ns, int cap) 90362306a36Sopenharmony_ci{ 90462306a36Sopenharmony_ci return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_ns_capable); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci/** 90962306a36Sopenharmony_ci * netlink_capable - Netlink global message capability test 91062306a36Sopenharmony_ci * @skb: socket buffer holding a netlink command from userspace 91162306a36Sopenharmony_ci * @cap: The capability to use 91262306a36Sopenharmony_ci * 91362306a36Sopenharmony_ci * Test to see if the opener of the socket we received the message 91462306a36Sopenharmony_ci * from had when the netlink socket was created and the sender of the 91562306a36Sopenharmony_ci * message has the capability @cap in all user namespaces. 91662306a36Sopenharmony_ci */ 91762306a36Sopenharmony_cibool netlink_capable(const struct sk_buff *skb, int cap) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci return netlink_ns_capable(skb, &init_user_ns, cap); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_capable); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci/** 92462306a36Sopenharmony_ci * netlink_net_capable - Netlink network namespace message capability test 92562306a36Sopenharmony_ci * @skb: socket buffer holding a netlink command from userspace 92662306a36Sopenharmony_ci * @cap: The capability to use 92762306a36Sopenharmony_ci * 92862306a36Sopenharmony_ci * Test to see if the opener of the socket we received the message 92962306a36Sopenharmony_ci * from had when the netlink socket was created and the sender of the 93062306a36Sopenharmony_ci * message has the capability @cap over the network namespace of 93162306a36Sopenharmony_ci * the socket we received the message from. 93262306a36Sopenharmony_ci */ 93362306a36Sopenharmony_cibool netlink_net_capable(const struct sk_buff *skb, int cap) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap); 93662306a36Sopenharmony_ci} 93762306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_net_capable); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_cistatic inline int netlink_allowed(const struct socket *sock, unsigned int flag) 94062306a36Sopenharmony_ci{ 94162306a36Sopenharmony_ci return (nl_table[sock->sk->sk_protocol].flags & flag) || 94262306a36Sopenharmony_ci ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN); 94362306a36Sopenharmony_ci} 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_cistatic void 94662306a36Sopenharmony_cinetlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (nlk->subscriptions && !subscriptions) 95162306a36Sopenharmony_ci __sk_del_bind_node(sk); 95262306a36Sopenharmony_ci else if (!nlk->subscriptions && subscriptions) 95362306a36Sopenharmony_ci sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); 95462306a36Sopenharmony_ci nlk->subscriptions = subscriptions; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic int netlink_realloc_groups(struct sock *sk) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 96062306a36Sopenharmony_ci unsigned int groups; 96162306a36Sopenharmony_ci unsigned long *new_groups; 96262306a36Sopenharmony_ci int err = 0; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci netlink_table_grab(); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci groups = nl_table[sk->sk_protocol].groups; 96762306a36Sopenharmony_ci if (!nl_table[sk->sk_protocol].registered) { 96862306a36Sopenharmony_ci err = -ENOENT; 96962306a36Sopenharmony_ci goto out_unlock; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (nlk->ngroups >= groups) 97362306a36Sopenharmony_ci goto out_unlock; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC); 97662306a36Sopenharmony_ci if (new_groups == NULL) { 97762306a36Sopenharmony_ci err = -ENOMEM; 97862306a36Sopenharmony_ci goto out_unlock; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci memset((char *)new_groups + NLGRPSZ(nlk->ngroups), 0, 98162306a36Sopenharmony_ci NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups)); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci nlk->groups = new_groups; 98462306a36Sopenharmony_ci nlk->ngroups = groups; 98562306a36Sopenharmony_ci out_unlock: 98662306a36Sopenharmony_ci netlink_table_ungrab(); 98762306a36Sopenharmony_ci return err; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic void netlink_undo_bind(int group, long unsigned int groups, 99162306a36Sopenharmony_ci struct sock *sk) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 99462306a36Sopenharmony_ci int undo; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (!nlk->netlink_unbind) 99762306a36Sopenharmony_ci return; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci for (undo = 0; undo < group; undo++) 100062306a36Sopenharmony_ci if (test_bit(undo, &groups)) 100162306a36Sopenharmony_ci nlk->netlink_unbind(sock_net(sk), undo + 1); 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic int netlink_bind(struct socket *sock, struct sockaddr *addr, 100562306a36Sopenharmony_ci int addr_len) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci struct sock *sk = sock->sk; 100862306a36Sopenharmony_ci struct net *net = sock_net(sk); 100962306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 101062306a36Sopenharmony_ci struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; 101162306a36Sopenharmony_ci int err = 0; 101262306a36Sopenharmony_ci unsigned long groups; 101362306a36Sopenharmony_ci bool bound; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci if (addr_len < sizeof(struct sockaddr_nl)) 101662306a36Sopenharmony_ci return -EINVAL; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (nladdr->nl_family != AF_NETLINK) 101962306a36Sopenharmony_ci return -EINVAL; 102062306a36Sopenharmony_ci groups = nladdr->nl_groups; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci /* Only superuser is allowed to listen multicasts */ 102362306a36Sopenharmony_ci if (groups) { 102462306a36Sopenharmony_ci if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) 102562306a36Sopenharmony_ci return -EPERM; 102662306a36Sopenharmony_ci err = netlink_realloc_groups(sk); 102762306a36Sopenharmony_ci if (err) 102862306a36Sopenharmony_ci return err; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci if (nlk->ngroups < BITS_PER_LONG) 103262306a36Sopenharmony_ci groups &= (1UL << nlk->ngroups) - 1; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci /* Paired with WRITE_ONCE() in netlink_insert() */ 103562306a36Sopenharmony_ci bound = READ_ONCE(nlk->bound); 103662306a36Sopenharmony_ci if (bound) { 103762306a36Sopenharmony_ci /* Ensure nlk->portid is up-to-date. */ 103862306a36Sopenharmony_ci smp_rmb(); 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci if (nladdr->nl_pid != nlk->portid) 104162306a36Sopenharmony_ci return -EINVAL; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci if (nlk->netlink_bind && groups) { 104562306a36Sopenharmony_ci int group; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* nl_groups is a u32, so cap the maximum groups we can bind */ 104862306a36Sopenharmony_ci for (group = 0; group < BITS_PER_TYPE(u32); group++) { 104962306a36Sopenharmony_ci if (!test_bit(group, &groups)) 105062306a36Sopenharmony_ci continue; 105162306a36Sopenharmony_ci err = nlk->netlink_bind(net, group + 1); 105262306a36Sopenharmony_ci if (!err) 105362306a36Sopenharmony_ci continue; 105462306a36Sopenharmony_ci netlink_undo_bind(group, groups, sk); 105562306a36Sopenharmony_ci return err; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci /* No need for barriers here as we return to user-space without 106062306a36Sopenharmony_ci * using any of the bound attributes. 106162306a36Sopenharmony_ci */ 106262306a36Sopenharmony_ci netlink_lock_table(); 106362306a36Sopenharmony_ci if (!bound) { 106462306a36Sopenharmony_ci err = nladdr->nl_pid ? 106562306a36Sopenharmony_ci netlink_insert(sk, nladdr->nl_pid) : 106662306a36Sopenharmony_ci netlink_autobind(sock); 106762306a36Sopenharmony_ci if (err) { 106862306a36Sopenharmony_ci netlink_undo_bind(BITS_PER_TYPE(u32), groups, sk); 106962306a36Sopenharmony_ci goto unlock; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) 107462306a36Sopenharmony_ci goto unlock; 107562306a36Sopenharmony_ci netlink_unlock_table(); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci netlink_table_grab(); 107862306a36Sopenharmony_ci netlink_update_subscriptions(sk, nlk->subscriptions + 107962306a36Sopenharmony_ci hweight32(groups) - 108062306a36Sopenharmony_ci hweight32(nlk->groups[0])); 108162306a36Sopenharmony_ci nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | groups; 108262306a36Sopenharmony_ci netlink_update_listeners(sk); 108362306a36Sopenharmony_ci netlink_table_ungrab(); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci return 0; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ciunlock: 108862306a36Sopenharmony_ci netlink_unlock_table(); 108962306a36Sopenharmony_ci return err; 109062306a36Sopenharmony_ci} 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic int netlink_connect(struct socket *sock, struct sockaddr *addr, 109362306a36Sopenharmony_ci int alen, int flags) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci int err = 0; 109662306a36Sopenharmony_ci struct sock *sk = sock->sk; 109762306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 109862306a36Sopenharmony_ci struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (alen < sizeof(addr->sa_family)) 110162306a36Sopenharmony_ci return -EINVAL; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (addr->sa_family == AF_UNSPEC) { 110462306a36Sopenharmony_ci /* paired with READ_ONCE() in netlink_getsockbyportid() */ 110562306a36Sopenharmony_ci WRITE_ONCE(sk->sk_state, NETLINK_UNCONNECTED); 110662306a36Sopenharmony_ci /* dst_portid and dst_group can be read locklessly */ 110762306a36Sopenharmony_ci WRITE_ONCE(nlk->dst_portid, 0); 110862306a36Sopenharmony_ci WRITE_ONCE(nlk->dst_group, 0); 110962306a36Sopenharmony_ci return 0; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci if (addr->sa_family != AF_NETLINK) 111262306a36Sopenharmony_ci return -EINVAL; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci if (alen < sizeof(struct sockaddr_nl)) 111562306a36Sopenharmony_ci return -EINVAL; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci if ((nladdr->nl_groups || nladdr->nl_pid) && 111862306a36Sopenharmony_ci !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) 111962306a36Sopenharmony_ci return -EPERM; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* No need for barriers here as we return to user-space without 112262306a36Sopenharmony_ci * using any of the bound attributes. 112362306a36Sopenharmony_ci * Paired with WRITE_ONCE() in netlink_insert(). 112462306a36Sopenharmony_ci */ 112562306a36Sopenharmony_ci if (!READ_ONCE(nlk->bound)) 112662306a36Sopenharmony_ci err = netlink_autobind(sock); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (err == 0) { 112962306a36Sopenharmony_ci /* paired with READ_ONCE() in netlink_getsockbyportid() */ 113062306a36Sopenharmony_ci WRITE_ONCE(sk->sk_state, NETLINK_CONNECTED); 113162306a36Sopenharmony_ci /* dst_portid and dst_group can be read locklessly */ 113262306a36Sopenharmony_ci WRITE_ONCE(nlk->dst_portid, nladdr->nl_pid); 113362306a36Sopenharmony_ci WRITE_ONCE(nlk->dst_group, ffs(nladdr->nl_groups)); 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci return err; 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic int netlink_getname(struct socket *sock, struct sockaddr *addr, 114062306a36Sopenharmony_ci int peer) 114162306a36Sopenharmony_ci{ 114262306a36Sopenharmony_ci struct sock *sk = sock->sk; 114362306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 114462306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_nl *, nladdr, addr); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci nladdr->nl_family = AF_NETLINK; 114762306a36Sopenharmony_ci nladdr->nl_pad = 0; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (peer) { 115062306a36Sopenharmony_ci /* Paired with WRITE_ONCE() in netlink_connect() */ 115162306a36Sopenharmony_ci nladdr->nl_pid = READ_ONCE(nlk->dst_portid); 115262306a36Sopenharmony_ci nladdr->nl_groups = netlink_group_mask(READ_ONCE(nlk->dst_group)); 115362306a36Sopenharmony_ci } else { 115462306a36Sopenharmony_ci /* Paired with WRITE_ONCE() in netlink_insert() */ 115562306a36Sopenharmony_ci nladdr->nl_pid = READ_ONCE(nlk->portid); 115662306a36Sopenharmony_ci netlink_lock_table(); 115762306a36Sopenharmony_ci nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; 115862306a36Sopenharmony_ci netlink_unlock_table(); 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci return sizeof(*nladdr); 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic int netlink_ioctl(struct socket *sock, unsigned int cmd, 116462306a36Sopenharmony_ci unsigned long arg) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci /* try to hand this ioctl down to the NIC drivers. 116762306a36Sopenharmony_ci */ 116862306a36Sopenharmony_ci return -ENOIOCTLCMD; 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic struct sock *netlink_getsockbyportid(struct sock *ssk, u32 portid) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci struct sock *sock; 117462306a36Sopenharmony_ci struct netlink_sock *nlk; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci sock = netlink_lookup(sock_net(ssk), ssk->sk_protocol, portid); 117762306a36Sopenharmony_ci if (!sock) 117862306a36Sopenharmony_ci return ERR_PTR(-ECONNREFUSED); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* Don't bother queuing skb if kernel socket has no input function */ 118162306a36Sopenharmony_ci nlk = nlk_sk(sock); 118262306a36Sopenharmony_ci /* dst_portid and sk_state can be changed in netlink_connect() */ 118362306a36Sopenharmony_ci if (READ_ONCE(sock->sk_state) == NETLINK_CONNECTED && 118462306a36Sopenharmony_ci READ_ONCE(nlk->dst_portid) != nlk_sk(ssk)->portid) { 118562306a36Sopenharmony_ci sock_put(sock); 118662306a36Sopenharmony_ci return ERR_PTR(-ECONNREFUSED); 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci return sock; 118962306a36Sopenharmony_ci} 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_cistruct sock *netlink_getsockbyfilp(struct file *filp) 119262306a36Sopenharmony_ci{ 119362306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 119462306a36Sopenharmony_ci struct sock *sock; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (!S_ISSOCK(inode->i_mode)) 119762306a36Sopenharmony_ci return ERR_PTR(-ENOTSOCK); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci sock = SOCKET_I(inode)->sk; 120062306a36Sopenharmony_ci if (sock->sk_family != AF_NETLINK) 120162306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci sock_hold(sock); 120462306a36Sopenharmony_ci return sock; 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_cistatic struct sk_buff *netlink_alloc_large_skb(unsigned int size, 120862306a36Sopenharmony_ci int broadcast) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci struct sk_buff *skb; 121162306a36Sopenharmony_ci void *data; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (size <= NLMSG_GOODSIZE || broadcast) 121462306a36Sopenharmony_ci return alloc_skb(size, GFP_KERNEL); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci size = SKB_DATA_ALIGN(size) + 121762306a36Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci data = vmalloc(size); 122062306a36Sopenharmony_ci if (data == NULL) 122162306a36Sopenharmony_ci return NULL; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci skb = __build_skb(data, size); 122462306a36Sopenharmony_ci if (skb == NULL) 122562306a36Sopenharmony_ci vfree(data); 122662306a36Sopenharmony_ci else 122762306a36Sopenharmony_ci skb->destructor = netlink_skb_destructor; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci return skb; 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci/* 123362306a36Sopenharmony_ci * Attach a skb to a netlink socket. 123462306a36Sopenharmony_ci * The caller must hold a reference to the destination socket. On error, the 123562306a36Sopenharmony_ci * reference is dropped. The skb is not send to the destination, just all 123662306a36Sopenharmony_ci * all error checks are performed and memory in the queue is reserved. 123762306a36Sopenharmony_ci * Return values: 123862306a36Sopenharmony_ci * < 0: error. skb freed, reference to sock dropped. 123962306a36Sopenharmony_ci * 0: continue 124062306a36Sopenharmony_ci * 1: repeat lookup - reference dropped while waiting for socket memory. 124162306a36Sopenharmony_ci */ 124262306a36Sopenharmony_ciint netlink_attachskb(struct sock *sk, struct sk_buff *skb, 124362306a36Sopenharmony_ci long *timeo, struct sock *ssk) 124462306a36Sopenharmony_ci{ 124562306a36Sopenharmony_ci struct netlink_sock *nlk; 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci nlk = nlk_sk(sk); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || 125062306a36Sopenharmony_ci test_bit(NETLINK_S_CONGESTED, &nlk->state))) { 125162306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 125262306a36Sopenharmony_ci if (!*timeo) { 125362306a36Sopenharmony_ci if (!ssk || netlink_is_kernel(ssk)) 125462306a36Sopenharmony_ci netlink_overrun(sk); 125562306a36Sopenharmony_ci sock_put(sk); 125662306a36Sopenharmony_ci kfree_skb(skb); 125762306a36Sopenharmony_ci return -EAGAIN; 125862306a36Sopenharmony_ci } 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci __set_current_state(TASK_INTERRUPTIBLE); 126162306a36Sopenharmony_ci add_wait_queue(&nlk->wait, &wait); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || 126462306a36Sopenharmony_ci test_bit(NETLINK_S_CONGESTED, &nlk->state)) && 126562306a36Sopenharmony_ci !sock_flag(sk, SOCK_DEAD)) 126662306a36Sopenharmony_ci *timeo = schedule_timeout(*timeo); 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 126962306a36Sopenharmony_ci remove_wait_queue(&nlk->wait, &wait); 127062306a36Sopenharmony_ci sock_put(sk); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci if (signal_pending(current)) { 127362306a36Sopenharmony_ci kfree_skb(skb); 127462306a36Sopenharmony_ci return sock_intr_errno(*timeo); 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci return 1; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci netlink_skb_set_owner_r(skb, sk); 127962306a36Sopenharmony_ci return 0; 128062306a36Sopenharmony_ci} 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_cistatic int __netlink_sendskb(struct sock *sk, struct sk_buff *skb) 128362306a36Sopenharmony_ci{ 128462306a36Sopenharmony_ci int len = skb->len; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci netlink_deliver_tap(sock_net(sk), skb); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci skb_queue_tail(&sk->sk_receive_queue, skb); 128962306a36Sopenharmony_ci sk->sk_data_ready(sk); 129062306a36Sopenharmony_ci return len; 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ciint netlink_sendskb(struct sock *sk, struct sk_buff *skb) 129462306a36Sopenharmony_ci{ 129562306a36Sopenharmony_ci int len = __netlink_sendskb(sk, skb); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci sock_put(sk); 129862306a36Sopenharmony_ci return len; 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_civoid netlink_detachskb(struct sock *sk, struct sk_buff *skb) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci kfree_skb(skb); 130462306a36Sopenharmony_ci sock_put(sk); 130562306a36Sopenharmony_ci} 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_cistatic struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci int delta; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci WARN_ON(skb->sk != NULL); 131262306a36Sopenharmony_ci delta = skb->end - skb->tail; 131362306a36Sopenharmony_ci if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize) 131462306a36Sopenharmony_ci return skb; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci if (skb_shared(skb)) { 131762306a36Sopenharmony_ci struct sk_buff *nskb = skb_clone(skb, allocation); 131862306a36Sopenharmony_ci if (!nskb) 131962306a36Sopenharmony_ci return skb; 132062306a36Sopenharmony_ci consume_skb(skb); 132162306a36Sopenharmony_ci skb = nskb; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci pskb_expand_head(skb, 0, -delta, 132562306a36Sopenharmony_ci (allocation & ~__GFP_DIRECT_RECLAIM) | 132662306a36Sopenharmony_ci __GFP_NOWARN | __GFP_NORETRY); 132762306a36Sopenharmony_ci return skb; 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb, 133162306a36Sopenharmony_ci struct sock *ssk) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci int ret; 133462306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci ret = -ECONNREFUSED; 133762306a36Sopenharmony_ci if (nlk->netlink_rcv != NULL) { 133862306a36Sopenharmony_ci ret = skb->len; 133962306a36Sopenharmony_ci netlink_skb_set_owner_r(skb, sk); 134062306a36Sopenharmony_ci NETLINK_CB(skb).sk = ssk; 134162306a36Sopenharmony_ci netlink_deliver_tap_kernel(sk, ssk, skb); 134262306a36Sopenharmony_ci nlk->netlink_rcv(skb); 134362306a36Sopenharmony_ci consume_skb(skb); 134462306a36Sopenharmony_ci } else { 134562306a36Sopenharmony_ci kfree_skb(skb); 134662306a36Sopenharmony_ci } 134762306a36Sopenharmony_ci sock_put(sk); 134862306a36Sopenharmony_ci return ret; 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ciint netlink_unicast(struct sock *ssk, struct sk_buff *skb, 135262306a36Sopenharmony_ci u32 portid, int nonblock) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci struct sock *sk; 135562306a36Sopenharmony_ci int err; 135662306a36Sopenharmony_ci long timeo; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci skb = netlink_trim(skb, gfp_any()); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci timeo = sock_sndtimeo(ssk, nonblock); 136162306a36Sopenharmony_ciretry: 136262306a36Sopenharmony_ci sk = netlink_getsockbyportid(ssk, portid); 136362306a36Sopenharmony_ci if (IS_ERR(sk)) { 136462306a36Sopenharmony_ci kfree_skb(skb); 136562306a36Sopenharmony_ci return PTR_ERR(sk); 136662306a36Sopenharmony_ci } 136762306a36Sopenharmony_ci if (netlink_is_kernel(sk)) 136862306a36Sopenharmony_ci return netlink_unicast_kernel(sk, skb, ssk); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci if (sk_filter(sk, skb)) { 137162306a36Sopenharmony_ci err = skb->len; 137262306a36Sopenharmony_ci kfree_skb(skb); 137362306a36Sopenharmony_ci sock_put(sk); 137462306a36Sopenharmony_ci return err; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci err = netlink_attachskb(sk, skb, &timeo, ssk); 137862306a36Sopenharmony_ci if (err == 1) 137962306a36Sopenharmony_ci goto retry; 138062306a36Sopenharmony_ci if (err) 138162306a36Sopenharmony_ci return err; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci return netlink_sendskb(sk, skb); 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_unicast); 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ciint netlink_has_listeners(struct sock *sk, unsigned int group) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci int res = 0; 139062306a36Sopenharmony_ci struct listeners *listeners; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci BUG_ON(!netlink_is_kernel(sk)); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci rcu_read_lock(); 139562306a36Sopenharmony_ci listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (listeners && group - 1 < nl_table[sk->sk_protocol].groups) 139862306a36Sopenharmony_ci res = test_bit(group - 1, listeners->masks); 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci rcu_read_unlock(); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci return res; 140362306a36Sopenharmony_ci} 140462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(netlink_has_listeners); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_cibool netlink_strict_get_check(struct sk_buff *skb) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci return nlk_test_bit(STRICT_CHK, NETLINK_CB(skb).sk); 140962306a36Sopenharmony_ci} 141062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(netlink_strict_get_check); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_cistatic int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) 141362306a36Sopenharmony_ci{ 141462306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && 141762306a36Sopenharmony_ci !test_bit(NETLINK_S_CONGESTED, &nlk->state)) { 141862306a36Sopenharmony_ci netlink_skb_set_owner_r(skb, sk); 141962306a36Sopenharmony_ci __netlink_sendskb(sk, skb); 142062306a36Sopenharmony_ci return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1); 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci return -1; 142362306a36Sopenharmony_ci} 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_cistruct netlink_broadcast_data { 142662306a36Sopenharmony_ci struct sock *exclude_sk; 142762306a36Sopenharmony_ci struct net *net; 142862306a36Sopenharmony_ci u32 portid; 142962306a36Sopenharmony_ci u32 group; 143062306a36Sopenharmony_ci int failure; 143162306a36Sopenharmony_ci int delivery_failure; 143262306a36Sopenharmony_ci int congested; 143362306a36Sopenharmony_ci int delivered; 143462306a36Sopenharmony_ci gfp_t allocation; 143562306a36Sopenharmony_ci struct sk_buff *skb, *skb2; 143662306a36Sopenharmony_ci int (*tx_filter)(struct sock *dsk, struct sk_buff *skb, void *data); 143762306a36Sopenharmony_ci void *tx_data; 143862306a36Sopenharmony_ci}; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_cistatic void do_one_broadcast(struct sock *sk, 144162306a36Sopenharmony_ci struct netlink_broadcast_data *p) 144262306a36Sopenharmony_ci{ 144362306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 144462306a36Sopenharmony_ci int val; 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci if (p->exclude_sk == sk) 144762306a36Sopenharmony_ci return; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups || 145062306a36Sopenharmony_ci !test_bit(p->group - 1, nlk->groups)) 145162306a36Sopenharmony_ci return; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if (!net_eq(sock_net(sk), p->net)) { 145462306a36Sopenharmony_ci if (!nlk_test_bit(LISTEN_ALL_NSID, sk)) 145562306a36Sopenharmony_ci return; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci if (!peernet_has_id(sock_net(sk), p->net)) 145862306a36Sopenharmony_ci return; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci if (!file_ns_capable(sk->sk_socket->file, p->net->user_ns, 146162306a36Sopenharmony_ci CAP_NET_BROADCAST)) 146262306a36Sopenharmony_ci return; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (p->failure) { 146662306a36Sopenharmony_ci netlink_overrun(sk); 146762306a36Sopenharmony_ci return; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci sock_hold(sk); 147162306a36Sopenharmony_ci if (p->skb2 == NULL) { 147262306a36Sopenharmony_ci if (skb_shared(p->skb)) { 147362306a36Sopenharmony_ci p->skb2 = skb_clone(p->skb, p->allocation); 147462306a36Sopenharmony_ci } else { 147562306a36Sopenharmony_ci p->skb2 = skb_get(p->skb); 147662306a36Sopenharmony_ci /* 147762306a36Sopenharmony_ci * skb ownership may have been set when 147862306a36Sopenharmony_ci * delivered to a previous socket. 147962306a36Sopenharmony_ci */ 148062306a36Sopenharmony_ci skb_orphan(p->skb2); 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci } 148362306a36Sopenharmony_ci if (p->skb2 == NULL) { 148462306a36Sopenharmony_ci netlink_overrun(sk); 148562306a36Sopenharmony_ci /* Clone failed. Notify ALL listeners. */ 148662306a36Sopenharmony_ci p->failure = 1; 148762306a36Sopenharmony_ci if (nlk_test_bit(BROADCAST_SEND_ERROR, sk)) 148862306a36Sopenharmony_ci p->delivery_failure = 1; 148962306a36Sopenharmony_ci goto out; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) { 149362306a36Sopenharmony_ci kfree_skb(p->skb2); 149462306a36Sopenharmony_ci p->skb2 = NULL; 149562306a36Sopenharmony_ci goto out; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci if (sk_filter(sk, p->skb2)) { 149962306a36Sopenharmony_ci kfree_skb(p->skb2); 150062306a36Sopenharmony_ci p->skb2 = NULL; 150162306a36Sopenharmony_ci goto out; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); 150462306a36Sopenharmony_ci if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED) 150562306a36Sopenharmony_ci NETLINK_CB(p->skb2).nsid_is_set = true; 150662306a36Sopenharmony_ci val = netlink_broadcast_deliver(sk, p->skb2); 150762306a36Sopenharmony_ci if (val < 0) { 150862306a36Sopenharmony_ci netlink_overrun(sk); 150962306a36Sopenharmony_ci if (nlk_test_bit(BROADCAST_SEND_ERROR, sk)) 151062306a36Sopenharmony_ci p->delivery_failure = 1; 151162306a36Sopenharmony_ci } else { 151262306a36Sopenharmony_ci p->congested |= val; 151362306a36Sopenharmony_ci p->delivered = 1; 151462306a36Sopenharmony_ci p->skb2 = NULL; 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ciout: 151762306a36Sopenharmony_ci sock_put(sk); 151862306a36Sopenharmony_ci} 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ciint netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, 152162306a36Sopenharmony_ci u32 portid, 152262306a36Sopenharmony_ci u32 group, gfp_t allocation, 152362306a36Sopenharmony_ci int (*filter)(struct sock *dsk, 152462306a36Sopenharmony_ci struct sk_buff *skb, void *data), 152562306a36Sopenharmony_ci void *filter_data) 152662306a36Sopenharmony_ci{ 152762306a36Sopenharmony_ci struct net *net = sock_net(ssk); 152862306a36Sopenharmony_ci struct netlink_broadcast_data info; 152962306a36Sopenharmony_ci struct sock *sk; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci skb = netlink_trim(skb, allocation); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci info.exclude_sk = ssk; 153462306a36Sopenharmony_ci info.net = net; 153562306a36Sopenharmony_ci info.portid = portid; 153662306a36Sopenharmony_ci info.group = group; 153762306a36Sopenharmony_ci info.failure = 0; 153862306a36Sopenharmony_ci info.delivery_failure = 0; 153962306a36Sopenharmony_ci info.congested = 0; 154062306a36Sopenharmony_ci info.delivered = 0; 154162306a36Sopenharmony_ci info.allocation = allocation; 154262306a36Sopenharmony_ci info.skb = skb; 154362306a36Sopenharmony_ci info.skb2 = NULL; 154462306a36Sopenharmony_ci info.tx_filter = filter; 154562306a36Sopenharmony_ci info.tx_data = filter_data; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci /* While we sleep in clone, do not allow to change socket list */ 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci netlink_lock_table(); 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) 155262306a36Sopenharmony_ci do_one_broadcast(sk, &info); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci consume_skb(skb); 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci netlink_unlock_table(); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (info.delivery_failure) { 155962306a36Sopenharmony_ci kfree_skb(info.skb2); 156062306a36Sopenharmony_ci return -ENOBUFS; 156162306a36Sopenharmony_ci } 156262306a36Sopenharmony_ci consume_skb(info.skb2); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci if (info.delivered) { 156562306a36Sopenharmony_ci if (info.congested && gfpflags_allow_blocking(allocation)) 156662306a36Sopenharmony_ci yield(); 156762306a36Sopenharmony_ci return 0; 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci return -ESRCH; 157062306a36Sopenharmony_ci} 157162306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_broadcast_filtered); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ciint netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 portid, 157462306a36Sopenharmony_ci u32 group, gfp_t allocation) 157562306a36Sopenharmony_ci{ 157662306a36Sopenharmony_ci return netlink_broadcast_filtered(ssk, skb, portid, group, allocation, 157762306a36Sopenharmony_ci NULL, NULL); 157862306a36Sopenharmony_ci} 157962306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_broadcast); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_cistruct netlink_set_err_data { 158262306a36Sopenharmony_ci struct sock *exclude_sk; 158362306a36Sopenharmony_ci u32 portid; 158462306a36Sopenharmony_ci u32 group; 158562306a36Sopenharmony_ci int code; 158662306a36Sopenharmony_ci}; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_cistatic int do_one_set_err(struct sock *sk, struct netlink_set_err_data *p) 158962306a36Sopenharmony_ci{ 159062306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 159162306a36Sopenharmony_ci int ret = 0; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci if (sk == p->exclude_sk) 159462306a36Sopenharmony_ci goto out; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci if (!net_eq(sock_net(sk), sock_net(p->exclude_sk))) 159762306a36Sopenharmony_ci goto out; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups || 160062306a36Sopenharmony_ci !test_bit(p->group - 1, nlk->groups)) 160162306a36Sopenharmony_ci goto out; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci if (p->code == ENOBUFS && nlk_test_bit(RECV_NO_ENOBUFS, sk)) { 160462306a36Sopenharmony_ci ret = 1; 160562306a36Sopenharmony_ci goto out; 160662306a36Sopenharmony_ci } 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err, p->code); 160962306a36Sopenharmony_ci sk_error_report(sk); 161062306a36Sopenharmony_ciout: 161162306a36Sopenharmony_ci return ret; 161262306a36Sopenharmony_ci} 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci/** 161562306a36Sopenharmony_ci * netlink_set_err - report error to broadcast listeners 161662306a36Sopenharmony_ci * @ssk: the kernel netlink socket, as returned by netlink_kernel_create() 161762306a36Sopenharmony_ci * @portid: the PORTID of a process that we want to skip (if any) 161862306a36Sopenharmony_ci * @group: the broadcast group that will notice the error 161962306a36Sopenharmony_ci * @code: error code, must be negative (as usual in kernelspace) 162062306a36Sopenharmony_ci * 162162306a36Sopenharmony_ci * This function returns the number of broadcast listeners that have set the 162262306a36Sopenharmony_ci * NETLINK_NO_ENOBUFS socket option. 162362306a36Sopenharmony_ci */ 162462306a36Sopenharmony_ciint netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code) 162562306a36Sopenharmony_ci{ 162662306a36Sopenharmony_ci struct netlink_set_err_data info; 162762306a36Sopenharmony_ci unsigned long flags; 162862306a36Sopenharmony_ci struct sock *sk; 162962306a36Sopenharmony_ci int ret = 0; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci info.exclude_sk = ssk; 163262306a36Sopenharmony_ci info.portid = portid; 163362306a36Sopenharmony_ci info.group = group; 163462306a36Sopenharmony_ci /* sk->sk_err wants a positive error value */ 163562306a36Sopenharmony_ci info.code = -code; 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci read_lock_irqsave(&nl_table_lock, flags); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) 164062306a36Sopenharmony_ci ret += do_one_set_err(sk, &info); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci read_unlock_irqrestore(&nl_table_lock, flags); 164362306a36Sopenharmony_ci return ret; 164462306a36Sopenharmony_ci} 164562306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_set_err); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci/* must be called with netlink table grabbed */ 164862306a36Sopenharmony_cistatic void netlink_update_socket_mc(struct netlink_sock *nlk, 164962306a36Sopenharmony_ci unsigned int group, 165062306a36Sopenharmony_ci int is_new) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci int old, new = !!is_new, subscriptions; 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci old = test_bit(group - 1, nlk->groups); 165562306a36Sopenharmony_ci subscriptions = nlk->subscriptions - old + new; 165662306a36Sopenharmony_ci __assign_bit(group - 1, nlk->groups, new); 165762306a36Sopenharmony_ci netlink_update_subscriptions(&nlk->sk, subscriptions); 165862306a36Sopenharmony_ci netlink_update_listeners(&nlk->sk); 165962306a36Sopenharmony_ci} 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_cistatic int netlink_setsockopt(struct socket *sock, int level, int optname, 166262306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci struct sock *sk = sock->sk; 166562306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 166662306a36Sopenharmony_ci unsigned int val = 0; 166762306a36Sopenharmony_ci int nr = -1; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci if (level != SOL_NETLINK) 167062306a36Sopenharmony_ci return -ENOPROTOOPT; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci if (optlen >= sizeof(int) && 167362306a36Sopenharmony_ci copy_from_sockptr(&val, optval, sizeof(val))) 167462306a36Sopenharmony_ci return -EFAULT; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci switch (optname) { 167762306a36Sopenharmony_ci case NETLINK_PKTINFO: 167862306a36Sopenharmony_ci nr = NETLINK_F_RECV_PKTINFO; 167962306a36Sopenharmony_ci break; 168062306a36Sopenharmony_ci case NETLINK_ADD_MEMBERSHIP: 168162306a36Sopenharmony_ci case NETLINK_DROP_MEMBERSHIP: { 168262306a36Sopenharmony_ci int err; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) 168562306a36Sopenharmony_ci return -EPERM; 168662306a36Sopenharmony_ci err = netlink_realloc_groups(sk); 168762306a36Sopenharmony_ci if (err) 168862306a36Sopenharmony_ci return err; 168962306a36Sopenharmony_ci if (!val || val - 1 >= nlk->ngroups) 169062306a36Sopenharmony_ci return -EINVAL; 169162306a36Sopenharmony_ci if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) { 169262306a36Sopenharmony_ci err = nlk->netlink_bind(sock_net(sk), val); 169362306a36Sopenharmony_ci if (err) 169462306a36Sopenharmony_ci return err; 169562306a36Sopenharmony_ci } 169662306a36Sopenharmony_ci netlink_table_grab(); 169762306a36Sopenharmony_ci netlink_update_socket_mc(nlk, val, 169862306a36Sopenharmony_ci optname == NETLINK_ADD_MEMBERSHIP); 169962306a36Sopenharmony_ci netlink_table_ungrab(); 170062306a36Sopenharmony_ci if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind) 170162306a36Sopenharmony_ci nlk->netlink_unbind(sock_net(sk), val); 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci break; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci case NETLINK_BROADCAST_ERROR: 170662306a36Sopenharmony_ci nr = NETLINK_F_BROADCAST_SEND_ERROR; 170762306a36Sopenharmony_ci break; 170862306a36Sopenharmony_ci case NETLINK_NO_ENOBUFS: 170962306a36Sopenharmony_ci assign_bit(NETLINK_F_RECV_NO_ENOBUFS, &nlk->flags, val); 171062306a36Sopenharmony_ci if (val) { 171162306a36Sopenharmony_ci clear_bit(NETLINK_S_CONGESTED, &nlk->state); 171262306a36Sopenharmony_ci wake_up_interruptible(&nlk->wait); 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci break; 171562306a36Sopenharmony_ci case NETLINK_LISTEN_ALL_NSID: 171662306a36Sopenharmony_ci if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_BROADCAST)) 171762306a36Sopenharmony_ci return -EPERM; 171862306a36Sopenharmony_ci nr = NETLINK_F_LISTEN_ALL_NSID; 171962306a36Sopenharmony_ci break; 172062306a36Sopenharmony_ci case NETLINK_CAP_ACK: 172162306a36Sopenharmony_ci nr = NETLINK_F_CAP_ACK; 172262306a36Sopenharmony_ci break; 172362306a36Sopenharmony_ci case NETLINK_EXT_ACK: 172462306a36Sopenharmony_ci nr = NETLINK_F_EXT_ACK; 172562306a36Sopenharmony_ci break; 172662306a36Sopenharmony_ci case NETLINK_GET_STRICT_CHK: 172762306a36Sopenharmony_ci nr = NETLINK_F_STRICT_CHK; 172862306a36Sopenharmony_ci break; 172962306a36Sopenharmony_ci default: 173062306a36Sopenharmony_ci return -ENOPROTOOPT; 173162306a36Sopenharmony_ci } 173262306a36Sopenharmony_ci if (nr >= 0) 173362306a36Sopenharmony_ci assign_bit(nr, &nlk->flags, val); 173462306a36Sopenharmony_ci return 0; 173562306a36Sopenharmony_ci} 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_cistatic int netlink_getsockopt(struct socket *sock, int level, int optname, 173862306a36Sopenharmony_ci char __user *optval, int __user *optlen) 173962306a36Sopenharmony_ci{ 174062306a36Sopenharmony_ci struct sock *sk = sock->sk; 174162306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 174262306a36Sopenharmony_ci unsigned int flag; 174362306a36Sopenharmony_ci int len, val; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci if (level != SOL_NETLINK) 174662306a36Sopenharmony_ci return -ENOPROTOOPT; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci if (get_user(len, optlen)) 174962306a36Sopenharmony_ci return -EFAULT; 175062306a36Sopenharmony_ci if (len < 0) 175162306a36Sopenharmony_ci return -EINVAL; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci switch (optname) { 175462306a36Sopenharmony_ci case NETLINK_PKTINFO: 175562306a36Sopenharmony_ci flag = NETLINK_F_RECV_PKTINFO; 175662306a36Sopenharmony_ci break; 175762306a36Sopenharmony_ci case NETLINK_BROADCAST_ERROR: 175862306a36Sopenharmony_ci flag = NETLINK_F_BROADCAST_SEND_ERROR; 175962306a36Sopenharmony_ci break; 176062306a36Sopenharmony_ci case NETLINK_NO_ENOBUFS: 176162306a36Sopenharmony_ci flag = NETLINK_F_RECV_NO_ENOBUFS; 176262306a36Sopenharmony_ci break; 176362306a36Sopenharmony_ci case NETLINK_LIST_MEMBERSHIPS: { 176462306a36Sopenharmony_ci int pos, idx, shift, err = 0; 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci netlink_lock_table(); 176762306a36Sopenharmony_ci for (pos = 0; pos * 8 < nlk->ngroups; pos += sizeof(u32)) { 176862306a36Sopenharmony_ci if (len - pos < sizeof(u32)) 176962306a36Sopenharmony_ci break; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci idx = pos / sizeof(unsigned long); 177262306a36Sopenharmony_ci shift = (pos % sizeof(unsigned long)) * 8; 177362306a36Sopenharmony_ci if (put_user((u32)(nlk->groups[idx] >> shift), 177462306a36Sopenharmony_ci (u32 __user *)(optval + pos))) { 177562306a36Sopenharmony_ci err = -EFAULT; 177662306a36Sopenharmony_ci break; 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci if (put_user(ALIGN(BITS_TO_BYTES(nlk->ngroups), sizeof(u32)), optlen)) 178062306a36Sopenharmony_ci err = -EFAULT; 178162306a36Sopenharmony_ci netlink_unlock_table(); 178262306a36Sopenharmony_ci return err; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci case NETLINK_CAP_ACK: 178562306a36Sopenharmony_ci flag = NETLINK_F_CAP_ACK; 178662306a36Sopenharmony_ci break; 178762306a36Sopenharmony_ci case NETLINK_EXT_ACK: 178862306a36Sopenharmony_ci flag = NETLINK_F_EXT_ACK; 178962306a36Sopenharmony_ci break; 179062306a36Sopenharmony_ci case NETLINK_GET_STRICT_CHK: 179162306a36Sopenharmony_ci flag = NETLINK_F_STRICT_CHK; 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci default: 179462306a36Sopenharmony_ci return -ENOPROTOOPT; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci if (len < sizeof(int)) 179862306a36Sopenharmony_ci return -EINVAL; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci len = sizeof(int); 180162306a36Sopenharmony_ci val = test_bit(flag, &nlk->flags); 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci if (put_user(len, optlen) || 180462306a36Sopenharmony_ci copy_to_user(optval, &val, len)) 180562306a36Sopenharmony_ci return -EFAULT; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci return 0; 180862306a36Sopenharmony_ci} 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_cistatic void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) 181162306a36Sopenharmony_ci{ 181262306a36Sopenharmony_ci struct nl_pktinfo info; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci info.group = NETLINK_CB(skb).dst_group; 181562306a36Sopenharmony_ci put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); 181662306a36Sopenharmony_ci} 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_cistatic void netlink_cmsg_listen_all_nsid(struct sock *sk, struct msghdr *msg, 181962306a36Sopenharmony_ci struct sk_buff *skb) 182062306a36Sopenharmony_ci{ 182162306a36Sopenharmony_ci if (!NETLINK_CB(skb).nsid_is_set) 182262306a36Sopenharmony_ci return; 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci put_cmsg(msg, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, sizeof(int), 182562306a36Sopenharmony_ci &NETLINK_CB(skb).nsid); 182662306a36Sopenharmony_ci} 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_cistatic int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci struct sock *sk = sock->sk; 183162306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 183262306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name); 183362306a36Sopenharmony_ci u32 dst_portid; 183462306a36Sopenharmony_ci u32 dst_group; 183562306a36Sopenharmony_ci struct sk_buff *skb; 183662306a36Sopenharmony_ci int err; 183762306a36Sopenharmony_ci struct scm_cookie scm; 183862306a36Sopenharmony_ci u32 netlink_skb_flags = 0; 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci if (msg->msg_flags & MSG_OOB) 184162306a36Sopenharmony_ci return -EOPNOTSUPP; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci if (len == 0) { 184462306a36Sopenharmony_ci pr_warn_once("Zero length message leads to an empty skb\n"); 184562306a36Sopenharmony_ci return -ENODATA; 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci err = scm_send(sock, msg, &scm, true); 184962306a36Sopenharmony_ci if (err < 0) 185062306a36Sopenharmony_ci return err; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci if (msg->msg_namelen) { 185362306a36Sopenharmony_ci err = -EINVAL; 185462306a36Sopenharmony_ci if (msg->msg_namelen < sizeof(struct sockaddr_nl)) 185562306a36Sopenharmony_ci goto out; 185662306a36Sopenharmony_ci if (addr->nl_family != AF_NETLINK) 185762306a36Sopenharmony_ci goto out; 185862306a36Sopenharmony_ci dst_portid = addr->nl_pid; 185962306a36Sopenharmony_ci dst_group = ffs(addr->nl_groups); 186062306a36Sopenharmony_ci err = -EPERM; 186162306a36Sopenharmony_ci if ((dst_group || dst_portid) && 186262306a36Sopenharmony_ci !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) 186362306a36Sopenharmony_ci goto out; 186462306a36Sopenharmony_ci netlink_skb_flags |= NETLINK_SKB_DST; 186562306a36Sopenharmony_ci } else { 186662306a36Sopenharmony_ci /* Paired with WRITE_ONCE() in netlink_connect() */ 186762306a36Sopenharmony_ci dst_portid = READ_ONCE(nlk->dst_portid); 186862306a36Sopenharmony_ci dst_group = READ_ONCE(nlk->dst_group); 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci /* Paired with WRITE_ONCE() in netlink_insert() */ 187262306a36Sopenharmony_ci if (!READ_ONCE(nlk->bound)) { 187362306a36Sopenharmony_ci err = netlink_autobind(sock); 187462306a36Sopenharmony_ci if (err) 187562306a36Sopenharmony_ci goto out; 187662306a36Sopenharmony_ci } else { 187762306a36Sopenharmony_ci /* Ensure nlk is hashed and visible. */ 187862306a36Sopenharmony_ci smp_rmb(); 187962306a36Sopenharmony_ci } 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci err = -EMSGSIZE; 188262306a36Sopenharmony_ci if (len > sk->sk_sndbuf - 32) 188362306a36Sopenharmony_ci goto out; 188462306a36Sopenharmony_ci err = -ENOBUFS; 188562306a36Sopenharmony_ci skb = netlink_alloc_large_skb(len, dst_group); 188662306a36Sopenharmony_ci if (skb == NULL) 188762306a36Sopenharmony_ci goto out; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci NETLINK_CB(skb).portid = nlk->portid; 189062306a36Sopenharmony_ci NETLINK_CB(skb).dst_group = dst_group; 189162306a36Sopenharmony_ci NETLINK_CB(skb).creds = scm.creds; 189262306a36Sopenharmony_ci NETLINK_CB(skb).flags = netlink_skb_flags; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci err = -EFAULT; 189562306a36Sopenharmony_ci if (memcpy_from_msg(skb_put(skb, len), msg, len)) { 189662306a36Sopenharmony_ci kfree_skb(skb); 189762306a36Sopenharmony_ci goto out; 189862306a36Sopenharmony_ci } 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci err = security_netlink_send(sk, skb); 190162306a36Sopenharmony_ci if (err) { 190262306a36Sopenharmony_ci kfree_skb(skb); 190362306a36Sopenharmony_ci goto out; 190462306a36Sopenharmony_ci } 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci if (dst_group) { 190762306a36Sopenharmony_ci refcount_inc(&skb->users); 190862306a36Sopenharmony_ci netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL); 190962306a36Sopenharmony_ci } 191062306a36Sopenharmony_ci err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags & MSG_DONTWAIT); 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ciout: 191362306a36Sopenharmony_ci scm_destroy(&scm); 191462306a36Sopenharmony_ci return err; 191562306a36Sopenharmony_ci} 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_cistatic int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, 191862306a36Sopenharmony_ci int flags) 191962306a36Sopenharmony_ci{ 192062306a36Sopenharmony_ci struct scm_cookie scm; 192162306a36Sopenharmony_ci struct sock *sk = sock->sk; 192262306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 192362306a36Sopenharmony_ci size_t copied, max_recvmsg_len; 192462306a36Sopenharmony_ci struct sk_buff *skb, *data_skb; 192562306a36Sopenharmony_ci int err, ret; 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci if (flags & MSG_OOB) 192862306a36Sopenharmony_ci return -EOPNOTSUPP; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci copied = 0; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci skb = skb_recv_datagram(sk, flags, &err); 193362306a36Sopenharmony_ci if (skb == NULL) 193462306a36Sopenharmony_ci goto out; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci data_skb = skb; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci#ifdef CONFIG_COMPAT_NETLINK_MESSAGES 193962306a36Sopenharmony_ci if (unlikely(skb_shinfo(skb)->frag_list)) { 194062306a36Sopenharmony_ci /* 194162306a36Sopenharmony_ci * If this skb has a frag_list, then here that means that we 194262306a36Sopenharmony_ci * will have to use the frag_list skb's data for compat tasks 194362306a36Sopenharmony_ci * and the regular skb's data for normal (non-compat) tasks. 194462306a36Sopenharmony_ci * 194562306a36Sopenharmony_ci * If we need to send the compat skb, assign it to the 194662306a36Sopenharmony_ci * 'data_skb' variable so that it will be used below for data 194762306a36Sopenharmony_ci * copying. We keep 'skb' for everything else, including 194862306a36Sopenharmony_ci * freeing both later. 194962306a36Sopenharmony_ci */ 195062306a36Sopenharmony_ci if (flags & MSG_CMSG_COMPAT) 195162306a36Sopenharmony_ci data_skb = skb_shinfo(skb)->frag_list; 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci#endif 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci /* Record the max length of recvmsg() calls for future allocations */ 195662306a36Sopenharmony_ci max_recvmsg_len = max(READ_ONCE(nlk->max_recvmsg_len), len); 195762306a36Sopenharmony_ci max_recvmsg_len = min_t(size_t, max_recvmsg_len, 195862306a36Sopenharmony_ci SKB_WITH_OVERHEAD(32768)); 195962306a36Sopenharmony_ci WRITE_ONCE(nlk->max_recvmsg_len, max_recvmsg_len); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci copied = data_skb->len; 196262306a36Sopenharmony_ci if (len < copied) { 196362306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 196462306a36Sopenharmony_ci copied = len; 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci err = skb_copy_datagram_msg(data_skb, 0, msg, copied); 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci if (msg->msg_name) { 197062306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name); 197162306a36Sopenharmony_ci addr->nl_family = AF_NETLINK; 197262306a36Sopenharmony_ci addr->nl_pad = 0; 197362306a36Sopenharmony_ci addr->nl_pid = NETLINK_CB(skb).portid; 197462306a36Sopenharmony_ci addr->nl_groups = netlink_group_mask(NETLINK_CB(skb).dst_group); 197562306a36Sopenharmony_ci msg->msg_namelen = sizeof(*addr); 197662306a36Sopenharmony_ci } 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci if (nlk_test_bit(RECV_PKTINFO, sk)) 197962306a36Sopenharmony_ci netlink_cmsg_recv_pktinfo(msg, skb); 198062306a36Sopenharmony_ci if (nlk_test_bit(LISTEN_ALL_NSID, sk)) 198162306a36Sopenharmony_ci netlink_cmsg_listen_all_nsid(sk, msg, skb); 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci memset(&scm, 0, sizeof(scm)); 198462306a36Sopenharmony_ci scm.creds = *NETLINK_CREDS(skb); 198562306a36Sopenharmony_ci if (flags & MSG_TRUNC) 198662306a36Sopenharmony_ci copied = data_skb->len; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci skb_free_datagram(sk, skb); 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci if (READ_ONCE(nlk->cb_running) && 199162306a36Sopenharmony_ci atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { 199262306a36Sopenharmony_ci ret = netlink_dump(sk); 199362306a36Sopenharmony_ci if (ret) { 199462306a36Sopenharmony_ci WRITE_ONCE(sk->sk_err, -ret); 199562306a36Sopenharmony_ci sk_error_report(sk); 199662306a36Sopenharmony_ci } 199762306a36Sopenharmony_ci } 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci scm_recv(sock, msg, &scm, flags); 200062306a36Sopenharmony_ciout: 200162306a36Sopenharmony_ci netlink_rcv_wake(sk); 200262306a36Sopenharmony_ci return err ? : copied; 200362306a36Sopenharmony_ci} 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_cistatic void netlink_data_ready(struct sock *sk) 200662306a36Sopenharmony_ci{ 200762306a36Sopenharmony_ci BUG(); 200862306a36Sopenharmony_ci} 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci/* 201162306a36Sopenharmony_ci * We export these functions to other modules. They provide a 201262306a36Sopenharmony_ci * complete set of kernel non-blocking support for message 201362306a36Sopenharmony_ci * queueing. 201462306a36Sopenharmony_ci */ 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_cistruct sock * 201762306a36Sopenharmony_ci__netlink_kernel_create(struct net *net, int unit, struct module *module, 201862306a36Sopenharmony_ci struct netlink_kernel_cfg *cfg) 201962306a36Sopenharmony_ci{ 202062306a36Sopenharmony_ci struct socket *sock; 202162306a36Sopenharmony_ci struct sock *sk; 202262306a36Sopenharmony_ci struct netlink_sock *nlk; 202362306a36Sopenharmony_ci struct listeners *listeners = NULL; 202462306a36Sopenharmony_ci struct mutex *cb_mutex = cfg ? cfg->cb_mutex : NULL; 202562306a36Sopenharmony_ci unsigned int groups; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci BUG_ON(!nl_table); 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci if (unit < 0 || unit >= MAX_LINKS) 203062306a36Sopenharmony_ci return NULL; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) 203362306a36Sopenharmony_ci return NULL; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci if (__netlink_create(net, sock, cb_mutex, unit, 1) < 0) 203662306a36Sopenharmony_ci goto out_sock_release_nosk; 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_ci sk = sock->sk; 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci if (!cfg || cfg->groups < 32) 204162306a36Sopenharmony_ci groups = 32; 204262306a36Sopenharmony_ci else 204362306a36Sopenharmony_ci groups = cfg->groups; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); 204662306a36Sopenharmony_ci if (!listeners) 204762306a36Sopenharmony_ci goto out_sock_release; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci sk->sk_data_ready = netlink_data_ready; 205062306a36Sopenharmony_ci if (cfg && cfg->input) 205162306a36Sopenharmony_ci nlk_sk(sk)->netlink_rcv = cfg->input; 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci if (netlink_insert(sk, 0)) 205462306a36Sopenharmony_ci goto out_sock_release; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci nlk = nlk_sk(sk); 205762306a36Sopenharmony_ci set_bit(NETLINK_F_KERNEL_SOCKET, &nlk->flags); 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci netlink_table_grab(); 206062306a36Sopenharmony_ci if (!nl_table[unit].registered) { 206162306a36Sopenharmony_ci nl_table[unit].groups = groups; 206262306a36Sopenharmony_ci rcu_assign_pointer(nl_table[unit].listeners, listeners); 206362306a36Sopenharmony_ci nl_table[unit].cb_mutex = cb_mutex; 206462306a36Sopenharmony_ci nl_table[unit].module = module; 206562306a36Sopenharmony_ci if (cfg) { 206662306a36Sopenharmony_ci nl_table[unit].bind = cfg->bind; 206762306a36Sopenharmony_ci nl_table[unit].unbind = cfg->unbind; 206862306a36Sopenharmony_ci nl_table[unit].release = cfg->release; 206962306a36Sopenharmony_ci nl_table[unit].flags = cfg->flags; 207062306a36Sopenharmony_ci } 207162306a36Sopenharmony_ci nl_table[unit].registered = 1; 207262306a36Sopenharmony_ci } else { 207362306a36Sopenharmony_ci kfree(listeners); 207462306a36Sopenharmony_ci nl_table[unit].registered++; 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci netlink_table_ungrab(); 207762306a36Sopenharmony_ci return sk; 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ciout_sock_release: 208062306a36Sopenharmony_ci kfree(listeners); 208162306a36Sopenharmony_ci netlink_kernel_release(sk); 208262306a36Sopenharmony_ci return NULL; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ciout_sock_release_nosk: 208562306a36Sopenharmony_ci sock_release(sock); 208662306a36Sopenharmony_ci return NULL; 208762306a36Sopenharmony_ci} 208862306a36Sopenharmony_ciEXPORT_SYMBOL(__netlink_kernel_create); 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_civoid 209162306a36Sopenharmony_cinetlink_kernel_release(struct sock *sk) 209262306a36Sopenharmony_ci{ 209362306a36Sopenharmony_ci if (sk == NULL || sk->sk_socket == NULL) 209462306a36Sopenharmony_ci return; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci sock_release(sk->sk_socket); 209762306a36Sopenharmony_ci} 209862306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_kernel_release); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ciint __netlink_change_ngroups(struct sock *sk, unsigned int groups) 210162306a36Sopenharmony_ci{ 210262306a36Sopenharmony_ci struct listeners *new, *old; 210362306a36Sopenharmony_ci struct netlink_table *tbl = &nl_table[sk->sk_protocol]; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci if (groups < 32) 210662306a36Sopenharmony_ci groups = 32; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { 210962306a36Sopenharmony_ci new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC); 211062306a36Sopenharmony_ci if (!new) 211162306a36Sopenharmony_ci return -ENOMEM; 211262306a36Sopenharmony_ci old = nl_deref_protected(tbl->listeners); 211362306a36Sopenharmony_ci memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups)); 211462306a36Sopenharmony_ci rcu_assign_pointer(tbl->listeners, new); 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci kfree_rcu(old, rcu); 211762306a36Sopenharmony_ci } 211862306a36Sopenharmony_ci tbl->groups = groups; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci return 0; 212162306a36Sopenharmony_ci} 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci/** 212462306a36Sopenharmony_ci * netlink_change_ngroups - change number of multicast groups 212562306a36Sopenharmony_ci * 212662306a36Sopenharmony_ci * This changes the number of multicast groups that are available 212762306a36Sopenharmony_ci * on a certain netlink family. Note that it is not possible to 212862306a36Sopenharmony_ci * change the number of groups to below 32. Also note that it does 212962306a36Sopenharmony_ci * not implicitly call netlink_clear_multicast_users() when the 213062306a36Sopenharmony_ci * number of groups is reduced. 213162306a36Sopenharmony_ci * 213262306a36Sopenharmony_ci * @sk: The kernel netlink socket, as returned by netlink_kernel_create(). 213362306a36Sopenharmony_ci * @groups: The new number of groups. 213462306a36Sopenharmony_ci */ 213562306a36Sopenharmony_ciint netlink_change_ngroups(struct sock *sk, unsigned int groups) 213662306a36Sopenharmony_ci{ 213762306a36Sopenharmony_ci int err; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci netlink_table_grab(); 214062306a36Sopenharmony_ci err = __netlink_change_ngroups(sk, groups); 214162306a36Sopenharmony_ci netlink_table_ungrab(); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci return err; 214462306a36Sopenharmony_ci} 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_civoid __netlink_clear_multicast_users(struct sock *ksk, unsigned int group) 214762306a36Sopenharmony_ci{ 214862306a36Sopenharmony_ci struct sock *sk; 214962306a36Sopenharmony_ci struct netlink_table *tbl = &nl_table[ksk->sk_protocol]; 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci sk_for_each_bound(sk, &tbl->mc_list) 215262306a36Sopenharmony_ci netlink_update_socket_mc(nlk_sk(sk), group, 0); 215362306a36Sopenharmony_ci} 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_cistruct nlmsghdr * 215662306a36Sopenharmony_ci__nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags) 215762306a36Sopenharmony_ci{ 215862306a36Sopenharmony_ci struct nlmsghdr *nlh; 215962306a36Sopenharmony_ci int size = nlmsg_msg_size(len); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci nlh = skb_put(skb, NLMSG_ALIGN(size)); 216262306a36Sopenharmony_ci nlh->nlmsg_type = type; 216362306a36Sopenharmony_ci nlh->nlmsg_len = size; 216462306a36Sopenharmony_ci nlh->nlmsg_flags = flags; 216562306a36Sopenharmony_ci nlh->nlmsg_pid = portid; 216662306a36Sopenharmony_ci nlh->nlmsg_seq = seq; 216762306a36Sopenharmony_ci if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0) 216862306a36Sopenharmony_ci memset(nlmsg_data(nlh) + len, 0, NLMSG_ALIGN(size) - size); 216962306a36Sopenharmony_ci return nlh; 217062306a36Sopenharmony_ci} 217162306a36Sopenharmony_ciEXPORT_SYMBOL(__nlmsg_put); 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci/* 217462306a36Sopenharmony_ci * It looks a bit ugly. 217562306a36Sopenharmony_ci * It would be better to create kernel thread. 217662306a36Sopenharmony_ci */ 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_cistatic int netlink_dump_done(struct netlink_sock *nlk, struct sk_buff *skb, 217962306a36Sopenharmony_ci struct netlink_callback *cb, 218062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 218162306a36Sopenharmony_ci{ 218262306a36Sopenharmony_ci struct nlmsghdr *nlh; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(nlk->dump_done_errno), 218562306a36Sopenharmony_ci NLM_F_MULTI | cb->answer_flags); 218662306a36Sopenharmony_ci if (WARN_ON(!nlh)) 218762306a36Sopenharmony_ci return -ENOBUFS; 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci nl_dump_check_consistent(cb, nlh); 219062306a36Sopenharmony_ci memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, sizeof(nlk->dump_done_errno)); 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci if (extack->_msg && test_bit(NETLINK_F_EXT_ACK, &nlk->flags)) { 219362306a36Sopenharmony_ci nlh->nlmsg_flags |= NLM_F_ACK_TLVS; 219462306a36Sopenharmony_ci if (!nla_put_string(skb, NLMSGERR_ATTR_MSG, extack->_msg)) 219562306a36Sopenharmony_ci nlmsg_end(skb, nlh); 219662306a36Sopenharmony_ci } 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci return 0; 219962306a36Sopenharmony_ci} 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_cistatic int netlink_dump(struct sock *sk) 220262306a36Sopenharmony_ci{ 220362306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(sk); 220462306a36Sopenharmony_ci struct netlink_ext_ack extack = {}; 220562306a36Sopenharmony_ci struct netlink_callback *cb; 220662306a36Sopenharmony_ci struct sk_buff *skb = NULL; 220762306a36Sopenharmony_ci size_t max_recvmsg_len; 220862306a36Sopenharmony_ci struct module *module; 220962306a36Sopenharmony_ci int err = -ENOBUFS; 221062306a36Sopenharmony_ci int alloc_min_size; 221162306a36Sopenharmony_ci int alloc_size; 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci mutex_lock(nlk->cb_mutex); 221462306a36Sopenharmony_ci if (!nlk->cb_running) { 221562306a36Sopenharmony_ci err = -EINVAL; 221662306a36Sopenharmony_ci goto errout_skb; 221762306a36Sopenharmony_ci } 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) 222062306a36Sopenharmony_ci goto errout_skb; 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci /* NLMSG_GOODSIZE is small to avoid high order allocations being 222362306a36Sopenharmony_ci * required, but it makes sense to _attempt_ a 16K bytes allocation 222462306a36Sopenharmony_ci * to reduce number of system calls on dump operations, if user 222562306a36Sopenharmony_ci * ever provided a big enough buffer. 222662306a36Sopenharmony_ci */ 222762306a36Sopenharmony_ci cb = &nlk->cb; 222862306a36Sopenharmony_ci alloc_min_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE); 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci max_recvmsg_len = READ_ONCE(nlk->max_recvmsg_len); 223162306a36Sopenharmony_ci if (alloc_min_size < max_recvmsg_len) { 223262306a36Sopenharmony_ci alloc_size = max_recvmsg_len; 223362306a36Sopenharmony_ci skb = alloc_skb(alloc_size, 223462306a36Sopenharmony_ci (GFP_KERNEL & ~__GFP_DIRECT_RECLAIM) | 223562306a36Sopenharmony_ci __GFP_NOWARN | __GFP_NORETRY); 223662306a36Sopenharmony_ci } 223762306a36Sopenharmony_ci if (!skb) { 223862306a36Sopenharmony_ci alloc_size = alloc_min_size; 223962306a36Sopenharmony_ci skb = alloc_skb(alloc_size, GFP_KERNEL); 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci if (!skb) 224262306a36Sopenharmony_ci goto errout_skb; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci /* Trim skb to allocated size. User is expected to provide buffer as 224562306a36Sopenharmony_ci * large as max(min_dump_alloc, 16KiB (mac_recvmsg_len capped at 224662306a36Sopenharmony_ci * netlink_recvmsg())). dump will pack as many smaller messages as 224762306a36Sopenharmony_ci * could fit within the allocated skb. skb is typically allocated 224862306a36Sopenharmony_ci * with larger space than required (could be as much as near 2x the 224962306a36Sopenharmony_ci * requested size with align to next power of 2 approach). Allowing 225062306a36Sopenharmony_ci * dump to use the excess space makes it difficult for a user to have a 225162306a36Sopenharmony_ci * reasonable static buffer based on the expected largest dump of a 225262306a36Sopenharmony_ci * single netdev. The outcome is MSG_TRUNC error. 225362306a36Sopenharmony_ci */ 225462306a36Sopenharmony_ci skb_reserve(skb, skb_tailroom(skb) - alloc_size); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci /* Make sure malicious BPF programs can not read unitialized memory 225762306a36Sopenharmony_ci * from skb->head -> skb->data 225862306a36Sopenharmony_ci */ 225962306a36Sopenharmony_ci skb_reset_network_header(skb); 226062306a36Sopenharmony_ci skb_reset_mac_header(skb); 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci netlink_skb_set_owner_r(skb, sk); 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci if (nlk->dump_done_errno > 0) { 226562306a36Sopenharmony_ci cb->extack = &extack; 226662306a36Sopenharmony_ci nlk->dump_done_errno = cb->dump(skb, cb); 226762306a36Sopenharmony_ci cb->extack = NULL; 226862306a36Sopenharmony_ci } 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci if (nlk->dump_done_errno > 0 || 227162306a36Sopenharmony_ci skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) { 227262306a36Sopenharmony_ci mutex_unlock(nlk->cb_mutex); 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci if (sk_filter(sk, skb)) 227562306a36Sopenharmony_ci kfree_skb(skb); 227662306a36Sopenharmony_ci else 227762306a36Sopenharmony_ci __netlink_sendskb(sk, skb); 227862306a36Sopenharmony_ci return 0; 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci if (netlink_dump_done(nlk, skb, cb, &extack)) 228262306a36Sopenharmony_ci goto errout_skb; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci#ifdef CONFIG_COMPAT_NETLINK_MESSAGES 228562306a36Sopenharmony_ci /* frag_list skb's data is used for compat tasks 228662306a36Sopenharmony_ci * and the regular skb's data for normal (non-compat) tasks. 228762306a36Sopenharmony_ci * See netlink_recvmsg(). 228862306a36Sopenharmony_ci */ 228962306a36Sopenharmony_ci if (unlikely(skb_shinfo(skb)->frag_list)) { 229062306a36Sopenharmony_ci if (netlink_dump_done(nlk, skb_shinfo(skb)->frag_list, cb, &extack)) 229162306a36Sopenharmony_ci goto errout_skb; 229262306a36Sopenharmony_ci } 229362306a36Sopenharmony_ci#endif 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci if (sk_filter(sk, skb)) 229662306a36Sopenharmony_ci kfree_skb(skb); 229762306a36Sopenharmony_ci else 229862306a36Sopenharmony_ci __netlink_sendskb(sk, skb); 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_ci if (cb->done) 230162306a36Sopenharmony_ci cb->done(cb); 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci WRITE_ONCE(nlk->cb_running, false); 230462306a36Sopenharmony_ci module = cb->module; 230562306a36Sopenharmony_ci skb = cb->skb; 230662306a36Sopenharmony_ci mutex_unlock(nlk->cb_mutex); 230762306a36Sopenharmony_ci module_put(module); 230862306a36Sopenharmony_ci consume_skb(skb); 230962306a36Sopenharmony_ci return 0; 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_cierrout_skb: 231262306a36Sopenharmony_ci mutex_unlock(nlk->cb_mutex); 231362306a36Sopenharmony_ci kfree_skb(skb); 231462306a36Sopenharmony_ci return err; 231562306a36Sopenharmony_ci} 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ciint __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, 231862306a36Sopenharmony_ci const struct nlmsghdr *nlh, 231962306a36Sopenharmony_ci struct netlink_dump_control *control) 232062306a36Sopenharmony_ci{ 232162306a36Sopenharmony_ci struct netlink_callback *cb; 232262306a36Sopenharmony_ci struct netlink_sock *nlk; 232362306a36Sopenharmony_ci struct sock *sk; 232462306a36Sopenharmony_ci int ret; 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_ci refcount_inc(&skb->users); 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid); 232962306a36Sopenharmony_ci if (sk == NULL) { 233062306a36Sopenharmony_ci ret = -ECONNREFUSED; 233162306a36Sopenharmony_ci goto error_free; 233262306a36Sopenharmony_ci } 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci nlk = nlk_sk(sk); 233562306a36Sopenharmony_ci mutex_lock(nlk->cb_mutex); 233662306a36Sopenharmony_ci /* A dump is in progress... */ 233762306a36Sopenharmony_ci if (nlk->cb_running) { 233862306a36Sopenharmony_ci ret = -EBUSY; 233962306a36Sopenharmony_ci goto error_unlock; 234062306a36Sopenharmony_ci } 234162306a36Sopenharmony_ci /* add reference of module which cb->dump belongs to */ 234262306a36Sopenharmony_ci if (!try_module_get(control->module)) { 234362306a36Sopenharmony_ci ret = -EPROTONOSUPPORT; 234462306a36Sopenharmony_ci goto error_unlock; 234562306a36Sopenharmony_ci } 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci cb = &nlk->cb; 234862306a36Sopenharmony_ci memset(cb, 0, sizeof(*cb)); 234962306a36Sopenharmony_ci cb->dump = control->dump; 235062306a36Sopenharmony_ci cb->done = control->done; 235162306a36Sopenharmony_ci cb->nlh = nlh; 235262306a36Sopenharmony_ci cb->data = control->data; 235362306a36Sopenharmony_ci cb->module = control->module; 235462306a36Sopenharmony_ci cb->min_dump_alloc = control->min_dump_alloc; 235562306a36Sopenharmony_ci cb->skb = skb; 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci cb->strict_check = nlk_test_bit(STRICT_CHK, NETLINK_CB(skb).sk); 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci if (control->start) { 236062306a36Sopenharmony_ci cb->extack = control->extack; 236162306a36Sopenharmony_ci ret = control->start(cb); 236262306a36Sopenharmony_ci cb->extack = NULL; 236362306a36Sopenharmony_ci if (ret) 236462306a36Sopenharmony_ci goto error_put; 236562306a36Sopenharmony_ci } 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci WRITE_ONCE(nlk->cb_running, true); 236862306a36Sopenharmony_ci nlk->dump_done_errno = INT_MAX; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci mutex_unlock(nlk->cb_mutex); 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci ret = netlink_dump(sk); 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci sock_put(sk); 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci if (ret) 237762306a36Sopenharmony_ci return ret; 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci /* We successfully started a dump, by returning -EINTR we 238062306a36Sopenharmony_ci * signal not to send ACK even if it was requested. 238162306a36Sopenharmony_ci */ 238262306a36Sopenharmony_ci return -EINTR; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_cierror_put: 238562306a36Sopenharmony_ci module_put(control->module); 238662306a36Sopenharmony_cierror_unlock: 238762306a36Sopenharmony_ci sock_put(sk); 238862306a36Sopenharmony_ci mutex_unlock(nlk->cb_mutex); 238962306a36Sopenharmony_cierror_free: 239062306a36Sopenharmony_ci kfree_skb(skb); 239162306a36Sopenharmony_ci return ret; 239262306a36Sopenharmony_ci} 239362306a36Sopenharmony_ciEXPORT_SYMBOL(__netlink_dump_start); 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_cistatic size_t 239662306a36Sopenharmony_cinetlink_ack_tlv_len(struct netlink_sock *nlk, int err, 239762306a36Sopenharmony_ci const struct netlink_ext_ack *extack) 239862306a36Sopenharmony_ci{ 239962306a36Sopenharmony_ci size_t tlvlen; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci if (!extack || !test_bit(NETLINK_F_EXT_ACK, &nlk->flags)) 240262306a36Sopenharmony_ci return 0; 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci tlvlen = 0; 240562306a36Sopenharmony_ci if (extack->_msg) 240662306a36Sopenharmony_ci tlvlen += nla_total_size(strlen(extack->_msg) + 1); 240762306a36Sopenharmony_ci if (extack->cookie_len) 240862306a36Sopenharmony_ci tlvlen += nla_total_size(extack->cookie_len); 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci /* Following attributes are only reported as error (not warning) */ 241162306a36Sopenharmony_ci if (!err) 241262306a36Sopenharmony_ci return tlvlen; 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci if (extack->bad_attr) 241562306a36Sopenharmony_ci tlvlen += nla_total_size(sizeof(u32)); 241662306a36Sopenharmony_ci if (extack->policy) 241762306a36Sopenharmony_ci tlvlen += netlink_policy_dump_attr_size_estimate(extack->policy); 241862306a36Sopenharmony_ci if (extack->miss_type) 241962306a36Sopenharmony_ci tlvlen += nla_total_size(sizeof(u32)); 242062306a36Sopenharmony_ci if (extack->miss_nest) 242162306a36Sopenharmony_ci tlvlen += nla_total_size(sizeof(u32)); 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci return tlvlen; 242462306a36Sopenharmony_ci} 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_cistatic void 242762306a36Sopenharmony_cinetlink_ack_tlv_fill(struct sk_buff *in_skb, struct sk_buff *skb, 242862306a36Sopenharmony_ci struct nlmsghdr *nlh, int err, 242962306a36Sopenharmony_ci const struct netlink_ext_ack *extack) 243062306a36Sopenharmony_ci{ 243162306a36Sopenharmony_ci if (extack->_msg) 243262306a36Sopenharmony_ci WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG, extack->_msg)); 243362306a36Sopenharmony_ci if (extack->cookie_len) 243462306a36Sopenharmony_ci WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE, 243562306a36Sopenharmony_ci extack->cookie_len, extack->cookie)); 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci if (!err) 243862306a36Sopenharmony_ci return; 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci if (extack->bad_attr && 244162306a36Sopenharmony_ci !WARN_ON((u8 *)extack->bad_attr < in_skb->data || 244262306a36Sopenharmony_ci (u8 *)extack->bad_attr >= in_skb->data + in_skb->len)) 244362306a36Sopenharmony_ci WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS, 244462306a36Sopenharmony_ci (u8 *)extack->bad_attr - (u8 *)nlh)); 244562306a36Sopenharmony_ci if (extack->policy) 244662306a36Sopenharmony_ci netlink_policy_dump_write_attr(skb, extack->policy, 244762306a36Sopenharmony_ci NLMSGERR_ATTR_POLICY); 244862306a36Sopenharmony_ci if (extack->miss_type) 244962306a36Sopenharmony_ci WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_TYPE, 245062306a36Sopenharmony_ci extack->miss_type)); 245162306a36Sopenharmony_ci if (extack->miss_nest && 245262306a36Sopenharmony_ci !WARN_ON((u8 *)extack->miss_nest < in_skb->data || 245362306a36Sopenharmony_ci (u8 *)extack->miss_nest > in_skb->data + in_skb->len)) 245462306a36Sopenharmony_ci WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_NEST, 245562306a36Sopenharmony_ci (u8 *)extack->miss_nest - (u8 *)nlh)); 245662306a36Sopenharmony_ci} 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_civoid netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err, 245962306a36Sopenharmony_ci const struct netlink_ext_ack *extack) 246062306a36Sopenharmony_ci{ 246162306a36Sopenharmony_ci struct sk_buff *skb; 246262306a36Sopenharmony_ci struct nlmsghdr *rep; 246362306a36Sopenharmony_ci struct nlmsgerr *errmsg; 246462306a36Sopenharmony_ci size_t payload = sizeof(*errmsg); 246562306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk); 246662306a36Sopenharmony_ci unsigned int flags = 0; 246762306a36Sopenharmony_ci size_t tlvlen; 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci /* Error messages get the original request appened, unless the user 247062306a36Sopenharmony_ci * requests to cap the error message, and get extra error data if 247162306a36Sopenharmony_ci * requested. 247262306a36Sopenharmony_ci */ 247362306a36Sopenharmony_ci if (err && !test_bit(NETLINK_F_CAP_ACK, &nlk->flags)) 247462306a36Sopenharmony_ci payload += nlmsg_len(nlh); 247562306a36Sopenharmony_ci else 247662306a36Sopenharmony_ci flags |= NLM_F_CAPPED; 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_ci tlvlen = netlink_ack_tlv_len(nlk, err, extack); 247962306a36Sopenharmony_ci if (tlvlen) 248062306a36Sopenharmony_ci flags |= NLM_F_ACK_TLVS; 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci skb = nlmsg_new(payload + tlvlen, GFP_KERNEL); 248362306a36Sopenharmony_ci if (!skb) 248462306a36Sopenharmony_ci goto err_skb; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci rep = nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, 248762306a36Sopenharmony_ci NLMSG_ERROR, sizeof(*errmsg), flags); 248862306a36Sopenharmony_ci if (!rep) 248962306a36Sopenharmony_ci goto err_bad_put; 249062306a36Sopenharmony_ci errmsg = nlmsg_data(rep); 249162306a36Sopenharmony_ci errmsg->error = err; 249262306a36Sopenharmony_ci errmsg->msg = *nlh; 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_ci if (!(flags & NLM_F_CAPPED)) { 249562306a36Sopenharmony_ci if (!nlmsg_append(skb, nlmsg_len(nlh))) 249662306a36Sopenharmony_ci goto err_bad_put; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci memcpy(nlmsg_data(&errmsg->msg), nlmsg_data(nlh), 249962306a36Sopenharmony_ci nlmsg_len(nlh)); 250062306a36Sopenharmony_ci } 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci if (tlvlen) 250362306a36Sopenharmony_ci netlink_ack_tlv_fill(in_skb, skb, nlh, err, extack); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci nlmsg_end(skb, rep); 250662306a36Sopenharmony_ci 250762306a36Sopenharmony_ci nlmsg_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid); 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci return; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_cierr_bad_put: 251262306a36Sopenharmony_ci nlmsg_free(skb); 251362306a36Sopenharmony_cierr_skb: 251462306a36Sopenharmony_ci WRITE_ONCE(NETLINK_CB(in_skb).sk->sk_err, ENOBUFS); 251562306a36Sopenharmony_ci sk_error_report(NETLINK_CB(in_skb).sk); 251662306a36Sopenharmony_ci} 251762306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_ack); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ciint netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, 252062306a36Sopenharmony_ci struct nlmsghdr *, 252162306a36Sopenharmony_ci struct netlink_ext_ack *)) 252262306a36Sopenharmony_ci{ 252362306a36Sopenharmony_ci struct netlink_ext_ack extack; 252462306a36Sopenharmony_ci struct nlmsghdr *nlh; 252562306a36Sopenharmony_ci int err; 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci while (skb->len >= nlmsg_total_size(0)) { 252862306a36Sopenharmony_ci int msglen; 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci memset(&extack, 0, sizeof(extack)); 253162306a36Sopenharmony_ci nlh = nlmsg_hdr(skb); 253262306a36Sopenharmony_ci err = 0; 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) 253562306a36Sopenharmony_ci return 0; 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci /* Only requests are handled by the kernel */ 253862306a36Sopenharmony_ci if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) 253962306a36Sopenharmony_ci goto ack; 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci /* Skip control messages */ 254262306a36Sopenharmony_ci if (nlh->nlmsg_type < NLMSG_MIN_TYPE) 254362306a36Sopenharmony_ci goto ack; 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci err = cb(skb, nlh, &extack); 254662306a36Sopenharmony_ci if (err == -EINTR) 254762306a36Sopenharmony_ci goto skip; 254862306a36Sopenharmony_ci 254962306a36Sopenharmony_ciack: 255062306a36Sopenharmony_ci if (nlh->nlmsg_flags & NLM_F_ACK || err) 255162306a36Sopenharmony_ci netlink_ack(skb, nlh, err, &extack); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ciskip: 255462306a36Sopenharmony_ci msglen = NLMSG_ALIGN(nlh->nlmsg_len); 255562306a36Sopenharmony_ci if (msglen > skb->len) 255662306a36Sopenharmony_ci msglen = skb->len; 255762306a36Sopenharmony_ci skb_pull(skb, msglen); 255862306a36Sopenharmony_ci } 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci return 0; 256162306a36Sopenharmony_ci} 256262306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_rcv_skb); 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci/** 256562306a36Sopenharmony_ci * nlmsg_notify - send a notification netlink message 256662306a36Sopenharmony_ci * @sk: netlink socket to use 256762306a36Sopenharmony_ci * @skb: notification message 256862306a36Sopenharmony_ci * @portid: destination netlink portid for reports or 0 256962306a36Sopenharmony_ci * @group: destination multicast group or 0 257062306a36Sopenharmony_ci * @report: 1 to report back, 0 to disable 257162306a36Sopenharmony_ci * @flags: allocation flags 257262306a36Sopenharmony_ci */ 257362306a36Sopenharmony_ciint nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid, 257462306a36Sopenharmony_ci unsigned int group, int report, gfp_t flags) 257562306a36Sopenharmony_ci{ 257662306a36Sopenharmony_ci int err = 0; 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci if (group) { 257962306a36Sopenharmony_ci int exclude_portid = 0; 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci if (report) { 258262306a36Sopenharmony_ci refcount_inc(&skb->users); 258362306a36Sopenharmony_ci exclude_portid = portid; 258462306a36Sopenharmony_ci } 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci /* errors reported via destination sk->sk_err, but propagate 258762306a36Sopenharmony_ci * delivery errors if NETLINK_BROADCAST_ERROR flag is set */ 258862306a36Sopenharmony_ci err = nlmsg_multicast(sk, skb, exclude_portid, group, flags); 258962306a36Sopenharmony_ci if (err == -ESRCH) 259062306a36Sopenharmony_ci err = 0; 259162306a36Sopenharmony_ci } 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci if (report) { 259462306a36Sopenharmony_ci int err2; 259562306a36Sopenharmony_ci 259662306a36Sopenharmony_ci err2 = nlmsg_unicast(sk, skb, portid); 259762306a36Sopenharmony_ci if (!err) 259862306a36Sopenharmony_ci err = err2; 259962306a36Sopenharmony_ci } 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci return err; 260262306a36Sopenharmony_ci} 260362306a36Sopenharmony_ciEXPORT_SYMBOL(nlmsg_notify); 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 260662306a36Sopenharmony_cistruct nl_seq_iter { 260762306a36Sopenharmony_ci struct seq_net_private p; 260862306a36Sopenharmony_ci struct rhashtable_iter hti; 260962306a36Sopenharmony_ci int link; 261062306a36Sopenharmony_ci}; 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_cistatic void netlink_walk_start(struct nl_seq_iter *iter) 261362306a36Sopenharmony_ci{ 261462306a36Sopenharmony_ci rhashtable_walk_enter(&nl_table[iter->link].hash, &iter->hti); 261562306a36Sopenharmony_ci rhashtable_walk_start(&iter->hti); 261662306a36Sopenharmony_ci} 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_cistatic void netlink_walk_stop(struct nl_seq_iter *iter) 261962306a36Sopenharmony_ci{ 262062306a36Sopenharmony_ci rhashtable_walk_stop(&iter->hti); 262162306a36Sopenharmony_ci rhashtable_walk_exit(&iter->hti); 262262306a36Sopenharmony_ci} 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_cistatic void *__netlink_seq_next(struct seq_file *seq) 262562306a36Sopenharmony_ci{ 262662306a36Sopenharmony_ci struct nl_seq_iter *iter = seq->private; 262762306a36Sopenharmony_ci struct netlink_sock *nlk; 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci do { 263062306a36Sopenharmony_ci for (;;) { 263162306a36Sopenharmony_ci nlk = rhashtable_walk_next(&iter->hti); 263262306a36Sopenharmony_ci 263362306a36Sopenharmony_ci if (IS_ERR(nlk)) { 263462306a36Sopenharmony_ci if (PTR_ERR(nlk) == -EAGAIN) 263562306a36Sopenharmony_ci continue; 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ci return nlk; 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci if (nlk) 264162306a36Sopenharmony_ci break; 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci netlink_walk_stop(iter); 264462306a36Sopenharmony_ci if (++iter->link >= MAX_LINKS) 264562306a36Sopenharmony_ci return NULL; 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci netlink_walk_start(iter); 264862306a36Sopenharmony_ci } 264962306a36Sopenharmony_ci } while (sock_net(&nlk->sk) != seq_file_net(seq)); 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci return nlk; 265262306a36Sopenharmony_ci} 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_cistatic void *netlink_seq_start(struct seq_file *seq, loff_t *posp) 265562306a36Sopenharmony_ci __acquires(RCU) 265662306a36Sopenharmony_ci{ 265762306a36Sopenharmony_ci struct nl_seq_iter *iter = seq->private; 265862306a36Sopenharmony_ci void *obj = SEQ_START_TOKEN; 265962306a36Sopenharmony_ci loff_t pos; 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci iter->link = 0; 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci netlink_walk_start(iter); 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci for (pos = *posp; pos && obj && !IS_ERR(obj); pos--) 266662306a36Sopenharmony_ci obj = __netlink_seq_next(seq); 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_ci return obj; 266962306a36Sopenharmony_ci} 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_cistatic void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) 267262306a36Sopenharmony_ci{ 267362306a36Sopenharmony_ci ++*pos; 267462306a36Sopenharmony_ci return __netlink_seq_next(seq); 267562306a36Sopenharmony_ci} 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_cistatic void netlink_native_seq_stop(struct seq_file *seq, void *v) 267862306a36Sopenharmony_ci{ 267962306a36Sopenharmony_ci struct nl_seq_iter *iter = seq->private; 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci if (iter->link >= MAX_LINKS) 268262306a36Sopenharmony_ci return; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci netlink_walk_stop(iter); 268562306a36Sopenharmony_ci} 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci 268862306a36Sopenharmony_cistatic int netlink_native_seq_show(struct seq_file *seq, void *v) 268962306a36Sopenharmony_ci{ 269062306a36Sopenharmony_ci if (v == SEQ_START_TOKEN) { 269162306a36Sopenharmony_ci seq_puts(seq, 269262306a36Sopenharmony_ci "sk Eth Pid Groups " 269362306a36Sopenharmony_ci "Rmem Wmem Dump Locks Drops Inode\n"); 269462306a36Sopenharmony_ci } else { 269562306a36Sopenharmony_ci struct sock *s = v; 269662306a36Sopenharmony_ci struct netlink_sock *nlk = nlk_sk(s); 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8u %-8lu\n", 269962306a36Sopenharmony_ci s, 270062306a36Sopenharmony_ci s->sk_protocol, 270162306a36Sopenharmony_ci nlk->portid, 270262306a36Sopenharmony_ci nlk->groups ? (u32)nlk->groups[0] : 0, 270362306a36Sopenharmony_ci sk_rmem_alloc_get(s), 270462306a36Sopenharmony_ci sk_wmem_alloc_get(s), 270562306a36Sopenharmony_ci READ_ONCE(nlk->cb_running), 270662306a36Sopenharmony_ci refcount_read(&s->sk_refcnt), 270762306a36Sopenharmony_ci atomic_read(&s->sk_drops), 270862306a36Sopenharmony_ci sock_i_ino(s) 270962306a36Sopenharmony_ci ); 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci } 271262306a36Sopenharmony_ci return 0; 271362306a36Sopenharmony_ci} 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 271662306a36Sopenharmony_cistruct bpf_iter__netlink { 271762306a36Sopenharmony_ci __bpf_md_ptr(struct bpf_iter_meta *, meta); 271862306a36Sopenharmony_ci __bpf_md_ptr(struct netlink_sock *, sk); 271962306a36Sopenharmony_ci}; 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ciDEFINE_BPF_ITER_FUNC(netlink, struct bpf_iter_meta *meta, struct netlink_sock *sk) 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_cistatic int netlink_prog_seq_show(struct bpf_prog *prog, 272462306a36Sopenharmony_ci struct bpf_iter_meta *meta, 272562306a36Sopenharmony_ci void *v) 272662306a36Sopenharmony_ci{ 272762306a36Sopenharmony_ci struct bpf_iter__netlink ctx; 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci meta->seq_num--; /* skip SEQ_START_TOKEN */ 273062306a36Sopenharmony_ci ctx.meta = meta; 273162306a36Sopenharmony_ci ctx.sk = nlk_sk((struct sock *)v); 273262306a36Sopenharmony_ci return bpf_iter_run_prog(prog, &ctx); 273362306a36Sopenharmony_ci} 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_cistatic int netlink_seq_show(struct seq_file *seq, void *v) 273662306a36Sopenharmony_ci{ 273762306a36Sopenharmony_ci struct bpf_iter_meta meta; 273862306a36Sopenharmony_ci struct bpf_prog *prog; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci meta.seq = seq; 274162306a36Sopenharmony_ci prog = bpf_iter_get_info(&meta, false); 274262306a36Sopenharmony_ci if (!prog) 274362306a36Sopenharmony_ci return netlink_native_seq_show(seq, v); 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci if (v != SEQ_START_TOKEN) 274662306a36Sopenharmony_ci return netlink_prog_seq_show(prog, &meta, v); 274762306a36Sopenharmony_ci 274862306a36Sopenharmony_ci return 0; 274962306a36Sopenharmony_ci} 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_cistatic void netlink_seq_stop(struct seq_file *seq, void *v) 275262306a36Sopenharmony_ci{ 275362306a36Sopenharmony_ci struct bpf_iter_meta meta; 275462306a36Sopenharmony_ci struct bpf_prog *prog; 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_ci if (!v) { 275762306a36Sopenharmony_ci meta.seq = seq; 275862306a36Sopenharmony_ci prog = bpf_iter_get_info(&meta, true); 275962306a36Sopenharmony_ci if (prog) 276062306a36Sopenharmony_ci (void)netlink_prog_seq_show(prog, &meta, v); 276162306a36Sopenharmony_ci } 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci netlink_native_seq_stop(seq, v); 276462306a36Sopenharmony_ci} 276562306a36Sopenharmony_ci#else 276662306a36Sopenharmony_cistatic int netlink_seq_show(struct seq_file *seq, void *v) 276762306a36Sopenharmony_ci{ 276862306a36Sopenharmony_ci return netlink_native_seq_show(seq, v); 276962306a36Sopenharmony_ci} 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_cistatic void netlink_seq_stop(struct seq_file *seq, void *v) 277262306a36Sopenharmony_ci{ 277362306a36Sopenharmony_ci netlink_native_seq_stop(seq, v); 277462306a36Sopenharmony_ci} 277562306a36Sopenharmony_ci#endif 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_cistatic const struct seq_operations netlink_seq_ops = { 277862306a36Sopenharmony_ci .start = netlink_seq_start, 277962306a36Sopenharmony_ci .next = netlink_seq_next, 278062306a36Sopenharmony_ci .stop = netlink_seq_stop, 278162306a36Sopenharmony_ci .show = netlink_seq_show, 278262306a36Sopenharmony_ci}; 278362306a36Sopenharmony_ci#endif 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ciint netlink_register_notifier(struct notifier_block *nb) 278662306a36Sopenharmony_ci{ 278762306a36Sopenharmony_ci return blocking_notifier_chain_register(&netlink_chain, nb); 278862306a36Sopenharmony_ci} 278962306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_register_notifier); 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ciint netlink_unregister_notifier(struct notifier_block *nb) 279262306a36Sopenharmony_ci{ 279362306a36Sopenharmony_ci return blocking_notifier_chain_unregister(&netlink_chain, nb); 279462306a36Sopenharmony_ci} 279562306a36Sopenharmony_ciEXPORT_SYMBOL(netlink_unregister_notifier); 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_cistatic const struct proto_ops netlink_ops = { 279862306a36Sopenharmony_ci .family = PF_NETLINK, 279962306a36Sopenharmony_ci .owner = THIS_MODULE, 280062306a36Sopenharmony_ci .release = netlink_release, 280162306a36Sopenharmony_ci .bind = netlink_bind, 280262306a36Sopenharmony_ci .connect = netlink_connect, 280362306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 280462306a36Sopenharmony_ci .accept = sock_no_accept, 280562306a36Sopenharmony_ci .getname = netlink_getname, 280662306a36Sopenharmony_ci .poll = datagram_poll, 280762306a36Sopenharmony_ci .ioctl = netlink_ioctl, 280862306a36Sopenharmony_ci .listen = sock_no_listen, 280962306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 281062306a36Sopenharmony_ci .setsockopt = netlink_setsockopt, 281162306a36Sopenharmony_ci .getsockopt = netlink_getsockopt, 281262306a36Sopenharmony_ci .sendmsg = netlink_sendmsg, 281362306a36Sopenharmony_ci .recvmsg = netlink_recvmsg, 281462306a36Sopenharmony_ci .mmap = sock_no_mmap, 281562306a36Sopenharmony_ci}; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_cistatic const struct net_proto_family netlink_family_ops = { 281862306a36Sopenharmony_ci .family = PF_NETLINK, 281962306a36Sopenharmony_ci .create = netlink_create, 282062306a36Sopenharmony_ci .owner = THIS_MODULE, /* for consistency 8) */ 282162306a36Sopenharmony_ci}; 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_cistatic int __net_init netlink_net_init(struct net *net) 282462306a36Sopenharmony_ci{ 282562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 282662306a36Sopenharmony_ci if (!proc_create_net("netlink", 0, net->proc_net, &netlink_seq_ops, 282762306a36Sopenharmony_ci sizeof(struct nl_seq_iter))) 282862306a36Sopenharmony_ci return -ENOMEM; 282962306a36Sopenharmony_ci#endif 283062306a36Sopenharmony_ci return 0; 283162306a36Sopenharmony_ci} 283262306a36Sopenharmony_ci 283362306a36Sopenharmony_cistatic void __net_exit netlink_net_exit(struct net *net) 283462306a36Sopenharmony_ci{ 283562306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 283662306a36Sopenharmony_ci remove_proc_entry("netlink", net->proc_net); 283762306a36Sopenharmony_ci#endif 283862306a36Sopenharmony_ci} 283962306a36Sopenharmony_ci 284062306a36Sopenharmony_cistatic void __init netlink_add_usersock_entry(void) 284162306a36Sopenharmony_ci{ 284262306a36Sopenharmony_ci struct listeners *listeners; 284362306a36Sopenharmony_ci int groups = 32; 284462306a36Sopenharmony_ci 284562306a36Sopenharmony_ci listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); 284662306a36Sopenharmony_ci if (!listeners) 284762306a36Sopenharmony_ci panic("netlink_add_usersock_entry: Cannot allocate listeners\n"); 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_ci netlink_table_grab(); 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci nl_table[NETLINK_USERSOCK].groups = groups; 285262306a36Sopenharmony_ci rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners); 285362306a36Sopenharmony_ci nl_table[NETLINK_USERSOCK].module = THIS_MODULE; 285462306a36Sopenharmony_ci nl_table[NETLINK_USERSOCK].registered = 1; 285562306a36Sopenharmony_ci nl_table[NETLINK_USERSOCK].flags = NL_CFG_F_NONROOT_SEND; 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci netlink_table_ungrab(); 285862306a36Sopenharmony_ci} 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_cistatic struct pernet_operations __net_initdata netlink_net_ops = { 286162306a36Sopenharmony_ci .init = netlink_net_init, 286262306a36Sopenharmony_ci .exit = netlink_net_exit, 286362306a36Sopenharmony_ci}; 286462306a36Sopenharmony_ci 286562306a36Sopenharmony_cistatic inline u32 netlink_hash(const void *data, u32 len, u32 seed) 286662306a36Sopenharmony_ci{ 286762306a36Sopenharmony_ci const struct netlink_sock *nlk = data; 286862306a36Sopenharmony_ci struct netlink_compare_arg arg; 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci netlink_compare_arg_init(&arg, sock_net(&nlk->sk), nlk->portid); 287162306a36Sopenharmony_ci return jhash2((u32 *)&arg, netlink_compare_arg_len / sizeof(u32), seed); 287262306a36Sopenharmony_ci} 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_cistatic const struct rhashtable_params netlink_rhashtable_params = { 287562306a36Sopenharmony_ci .head_offset = offsetof(struct netlink_sock, node), 287662306a36Sopenharmony_ci .key_len = netlink_compare_arg_len, 287762306a36Sopenharmony_ci .obj_hashfn = netlink_hash, 287862306a36Sopenharmony_ci .obj_cmpfn = netlink_compare, 287962306a36Sopenharmony_ci .automatic_shrinking = true, 288062306a36Sopenharmony_ci}; 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) 288362306a36Sopenharmony_ciBTF_ID_LIST(btf_netlink_sock_id) 288462306a36Sopenharmony_ciBTF_ID(struct, netlink_sock) 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_cistatic const struct bpf_iter_seq_info netlink_seq_info = { 288762306a36Sopenharmony_ci .seq_ops = &netlink_seq_ops, 288862306a36Sopenharmony_ci .init_seq_private = bpf_iter_init_seq_net, 288962306a36Sopenharmony_ci .fini_seq_private = bpf_iter_fini_seq_net, 289062306a36Sopenharmony_ci .seq_priv_size = sizeof(struct nl_seq_iter), 289162306a36Sopenharmony_ci}; 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_cistatic struct bpf_iter_reg netlink_reg_info = { 289462306a36Sopenharmony_ci .target = "netlink", 289562306a36Sopenharmony_ci .ctx_arg_info_size = 1, 289662306a36Sopenharmony_ci .ctx_arg_info = { 289762306a36Sopenharmony_ci { offsetof(struct bpf_iter__netlink, sk), 289862306a36Sopenharmony_ci PTR_TO_BTF_ID_OR_NULL }, 289962306a36Sopenharmony_ci }, 290062306a36Sopenharmony_ci .seq_info = &netlink_seq_info, 290162306a36Sopenharmony_ci}; 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_cistatic int __init bpf_iter_register(void) 290462306a36Sopenharmony_ci{ 290562306a36Sopenharmony_ci netlink_reg_info.ctx_arg_info[0].btf_id = *btf_netlink_sock_id; 290662306a36Sopenharmony_ci return bpf_iter_reg_target(&netlink_reg_info); 290762306a36Sopenharmony_ci} 290862306a36Sopenharmony_ci#endif 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_cistatic int __init netlink_proto_init(void) 291162306a36Sopenharmony_ci{ 291262306a36Sopenharmony_ci int i; 291362306a36Sopenharmony_ci int err = proto_register(&netlink_proto, 0); 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci if (err != 0) 291662306a36Sopenharmony_ci goto out; 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci#if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS) 291962306a36Sopenharmony_ci err = bpf_iter_register(); 292062306a36Sopenharmony_ci if (err) 292162306a36Sopenharmony_ci goto out; 292262306a36Sopenharmony_ci#endif 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof_field(struct sk_buff, cb)); 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); 292762306a36Sopenharmony_ci if (!nl_table) 292862306a36Sopenharmony_ci goto panic; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci for (i = 0; i < MAX_LINKS; i++) { 293162306a36Sopenharmony_ci if (rhashtable_init(&nl_table[i].hash, 293262306a36Sopenharmony_ci &netlink_rhashtable_params) < 0) { 293362306a36Sopenharmony_ci while (--i > 0) 293462306a36Sopenharmony_ci rhashtable_destroy(&nl_table[i].hash); 293562306a36Sopenharmony_ci kfree(nl_table); 293662306a36Sopenharmony_ci goto panic; 293762306a36Sopenharmony_ci } 293862306a36Sopenharmony_ci } 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci netlink_add_usersock_entry(); 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci sock_register(&netlink_family_ops); 294362306a36Sopenharmony_ci register_pernet_subsys(&netlink_net_ops); 294462306a36Sopenharmony_ci register_pernet_subsys(&netlink_tap_net_ops); 294562306a36Sopenharmony_ci /* The netlink device handler may be needed early. */ 294662306a36Sopenharmony_ci rtnetlink_init(); 294762306a36Sopenharmony_ciout: 294862306a36Sopenharmony_ci return err; 294962306a36Sopenharmony_cipanic: 295062306a36Sopenharmony_ci panic("netlink_init: Cannot allocate nl_table\n"); 295162306a36Sopenharmony_ci} 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_cicore_initcall(netlink_proto_init); 2954