12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * NETLINK Kernel-user communication protocol.
41da177e4SLinus Torvalds *
5113aa838SAlan Cox * Authors: Alan Cox <alan@lxorguk.ukuu.org.uk>
61da177e4SLinus Torvalds * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
7cd1df525SPatrick McHardy * Patrick McHardy <kaber@trash.net>
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith
101da177e4SLinus Torvalds * added netlink_proto_exit
111da177e4SLinus Torvalds * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br>
121da177e4SLinus Torvalds * use nlk_sk, as sk->protinfo is on a diet 8)
134fdb3bb7SHarald Welte * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org>
144fdb3bb7SHarald Welte * - inc module use count of module that owns
154fdb3bb7SHarald Welte * the kernel socket in case userspace opens
164fdb3bb7SHarald Welte * socket of same protocol
174fdb3bb7SHarald Welte * - remove all module support, since netlink is
184fdb3bb7SHarald Welte * mandatory if CONFIG_NET=y these days
191da177e4SLinus Torvalds */
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds #include <linux/module.h>
221da177e4SLinus Torvalds
23b6459415SJakub Kicinski #include <linux/bpf.h>
244fc268d2SRandy Dunlap #include <linux/capability.h>
251da177e4SLinus Torvalds #include <linux/kernel.h>
26b6459415SJakub Kicinski #include <linux/filter.h>
271da177e4SLinus Torvalds #include <linux/init.h>
281da177e4SLinus Torvalds #include <linux/signal.h>
291da177e4SLinus Torvalds #include <linux/sched.h>
301da177e4SLinus Torvalds #include <linux/errno.h>
311da177e4SLinus Torvalds #include <linux/string.h>
321da177e4SLinus Torvalds #include <linux/stat.h>
331da177e4SLinus Torvalds #include <linux/socket.h>
341da177e4SLinus Torvalds #include <linux/un.h>
351da177e4SLinus Torvalds #include <linux/fcntl.h>
361da177e4SLinus Torvalds #include <linux/termios.h>
371da177e4SLinus Torvalds #include <linux/sockios.h>
381da177e4SLinus Torvalds #include <linux/net.h>
391da177e4SLinus Torvalds #include <linux/fs.h>
401da177e4SLinus Torvalds #include <linux/slab.h>
417c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
421da177e4SLinus Torvalds #include <linux/skbuff.h>
431da177e4SLinus Torvalds #include <linux/netdevice.h>
441da177e4SLinus Torvalds #include <linux/rtnetlink.h>
451da177e4SLinus Torvalds #include <linux/proc_fs.h>
461da177e4SLinus Torvalds #include <linux/seq_file.h>
471da177e4SLinus Torvalds #include <linux/notifier.h>
481da177e4SLinus Torvalds #include <linux/security.h>
491da177e4SLinus Torvalds #include <linux/jhash.h>
501da177e4SLinus Torvalds #include <linux/jiffies.h>
511da177e4SLinus Torvalds #include <linux/random.h>
521da177e4SLinus Torvalds #include <linux/bitops.h>
531da177e4SLinus Torvalds #include <linux/mm.h>
541da177e4SLinus Torvalds #include <linux/types.h>
5554e0f520SAndrew Morton #include <linux/audit.h>
56af65bdfcSPatrick McHardy #include <linux/mutex.h>
57ccdfcc39SPatrick McHardy #include <linux/vmalloc.h>
58bcbde0d4SDaniel Borkmann #include <linux/if_arp.h>
59e341694eSThomas Graf #include <linux/rhashtable.h>
609652e931SPatrick McHardy #include <asm/cacheflush.h>
61e341694eSThomas Graf #include <linux/hash.h>
62ee1c2442SJohannes Berg #include <linux/genetlink.h>
637212462fSNicolas Dichtel #include <linux/net_namespace.h>
64bc5b6c0bSJeremy Cline #include <linux/nospec.h>
65951cf368SYonghong Song #include <linux/btf_ids.h>
6654e0f520SAndrew Morton
67457c4cbcSEric W. Biederman #include <net/net_namespace.h>
6825e3f70fSCong Wang #include <net/netns/generic.h>
691da177e4SLinus Torvalds #include <net/sock.h>
701da177e4SLinus Torvalds #include <net/scm.h>
7182ace47aSThomas Graf #include <net/netlink.h>
727e3ce05eSMarcelo Ricardo Leitner #define CREATE_TRACE_POINTS
737e3ce05eSMarcelo Ricardo Leitner #include <trace/events/netlink.h>
741da177e4SLinus Torvalds
750f29c768SAndrey Vagin #include "af_netlink.h"
761da177e4SLinus Torvalds
775c398dc8SEric Dumazet struct listeners {
785c398dc8SEric Dumazet struct rcu_head rcu;
792b738124SGustavo A. R. Silva unsigned long masks[];
806c04bb18SJohannes Berg };
816c04bb18SJohannes Berg
82cd967e05SPatrick McHardy /* state bits */
83cc3a572fSNicolas Dichtel #define NETLINK_S_CONGESTED 0x0
84cd967e05SPatrick McHardy
netlink_is_kernel(struct sock * sk)85035c4c16SDavid S. Miller static inline int netlink_is_kernel(struct sock *sk)
86aed81560SDenis V. Lunev {
878fe08d70SEric Dumazet return nlk_test_bit(KERNEL_SOCKET, sk);
88aed81560SDenis V. Lunev }
89aed81560SDenis V. Lunev
9091dd93f9SEric Dumazet struct netlink_table *nl_table __read_mostly;
910f29c768SAndrey Vagin EXPORT_SYMBOL_GPL(nl_table);
921da177e4SLinus Torvalds
931da177e4SLinus Torvalds static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
941da177e4SLinus Torvalds
958a0f5ccfSHerbert Xu static struct lock_class_key nlk_cb_mutex_keys[MAX_LINKS];
968a0f5ccfSHerbert Xu
978a0f5ccfSHerbert Xu static const char *const nlk_cb_mutex_key_strings[MAX_LINKS + 1] = {
988a0f5ccfSHerbert Xu "nlk_cb_mutex-ROUTE",
998a0f5ccfSHerbert Xu "nlk_cb_mutex-1",
1008a0f5ccfSHerbert Xu "nlk_cb_mutex-USERSOCK",
1018a0f5ccfSHerbert Xu "nlk_cb_mutex-FIREWALL",
1028a0f5ccfSHerbert Xu "nlk_cb_mutex-SOCK_DIAG",
1038a0f5ccfSHerbert Xu "nlk_cb_mutex-NFLOG",
1048a0f5ccfSHerbert Xu "nlk_cb_mutex-XFRM",
1058a0f5ccfSHerbert Xu "nlk_cb_mutex-SELINUX",
1068a0f5ccfSHerbert Xu "nlk_cb_mutex-ISCSI",
1078a0f5ccfSHerbert Xu "nlk_cb_mutex-AUDIT",
1088a0f5ccfSHerbert Xu "nlk_cb_mutex-FIB_LOOKUP",
1098a0f5ccfSHerbert Xu "nlk_cb_mutex-CONNECTOR",
1108a0f5ccfSHerbert Xu "nlk_cb_mutex-NETFILTER",
1118a0f5ccfSHerbert Xu "nlk_cb_mutex-IP6_FW",
1128a0f5ccfSHerbert Xu "nlk_cb_mutex-DNRTMSG",
1138a0f5ccfSHerbert Xu "nlk_cb_mutex-KOBJECT_UEVENT",
1148a0f5ccfSHerbert Xu "nlk_cb_mutex-GENERIC",
1158a0f5ccfSHerbert Xu "nlk_cb_mutex-17",
1168a0f5ccfSHerbert Xu "nlk_cb_mutex-SCSITRANSPORT",
1178a0f5ccfSHerbert Xu "nlk_cb_mutex-ECRYPTFS",
1188a0f5ccfSHerbert Xu "nlk_cb_mutex-RDMA",
1198a0f5ccfSHerbert Xu "nlk_cb_mutex-CRYPTO",
1208a0f5ccfSHerbert Xu "nlk_cb_mutex-SMC",
1218a0f5ccfSHerbert Xu "nlk_cb_mutex-23",
1228a0f5ccfSHerbert Xu "nlk_cb_mutex-24",
1238a0f5ccfSHerbert Xu "nlk_cb_mutex-25",
1248a0f5ccfSHerbert Xu "nlk_cb_mutex-26",
1258a0f5ccfSHerbert Xu "nlk_cb_mutex-27",
1268a0f5ccfSHerbert Xu "nlk_cb_mutex-28",
1278a0f5ccfSHerbert Xu "nlk_cb_mutex-29",
1288a0f5ccfSHerbert Xu "nlk_cb_mutex-30",
1298a0f5ccfSHerbert Xu "nlk_cb_mutex-31",
1308a0f5ccfSHerbert Xu "nlk_cb_mutex-MAX_LINKS"
1318a0f5ccfSHerbert Xu };
1328a0f5ccfSHerbert Xu
1339cf3b89bSEric Dumazet static int netlink_dump(struct sock *sk, bool lock_taken);
1341da177e4SLinus Torvalds
13578fd1d0aSThomas Graf /* nl_table locking explained:
13621e4902aSThomas Graf * Lookup and traversal are protected with an RCU read-side lock. Insertion
137c5adde94SYing Xue * and removal are protected with per bucket lock while using RCU list
13821e4902aSThomas Graf * modification primitives and may run in parallel to RCU protected lookups.
13921e4902aSThomas Graf * Destruction of the Netlink socket may only occur *after* nl_table_lock has
14021e4902aSThomas Graf * been acquired * either during or after the socket has been removed from
14121e4902aSThomas Graf * the list and after an RCU grace period.
14278fd1d0aSThomas Graf */
1430f29c768SAndrey Vagin DEFINE_RWLOCK(nl_table_lock);
1440f29c768SAndrey Vagin EXPORT_SYMBOL_GPL(nl_table_lock);
1451da177e4SLinus Torvalds static atomic_t nl_table_users = ATOMIC_INIT(0);
1461da177e4SLinus Torvalds
1476d772ac5SEric Dumazet #define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock));
1486d772ac5SEric Dumazet
149efa172f4SWANG Cong static BLOCKING_NOTIFIER_HEAD(netlink_chain);
1501da177e4SLinus Torvalds
151bcbde0d4SDaniel Borkmann
152c428ecd1SHerbert Xu static const struct rhashtable_params netlink_rhashtable_params;
153c428ecd1SHerbert Xu
do_trace_netlink_extack(const char * msg)1547e3ce05eSMarcelo Ricardo Leitner void do_trace_netlink_extack(const char *msg)
1557e3ce05eSMarcelo Ricardo Leitner {
1567e3ce05eSMarcelo Ricardo Leitner trace_netlink_extack(msg);
1577e3ce05eSMarcelo Ricardo Leitner }
1587e3ce05eSMarcelo Ricardo Leitner EXPORT_SYMBOL(do_trace_netlink_extack);
1597e3ce05eSMarcelo Ricardo Leitner
netlink_group_mask(u32 group)160b57ef81fSstephen hemminger static inline u32 netlink_group_mask(u32 group)
161d629b836SPatrick McHardy {
1620caf6d99SPetr Machata if (group > 32)
1630caf6d99SPetr Machata return 0;
164d629b836SPatrick McHardy return group ? 1 << (group - 1) : 0;
165d629b836SPatrick McHardy }
166d629b836SPatrick McHardy
netlink_to_full_skb(const struct sk_buff * skb,gfp_t gfp_mask)1671853c949SDaniel Borkmann static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb,
1681853c949SDaniel Borkmann gfp_t gfp_mask)
1691853c949SDaniel Borkmann {
170d3ada42eSRyosuke Yasuoka unsigned int len = skb->len;
1711853c949SDaniel Borkmann struct sk_buff *new;
1721853c949SDaniel Borkmann
1731853c949SDaniel Borkmann new = alloc_skb(len, gfp_mask);
1741853c949SDaniel Borkmann if (new == NULL)
1751853c949SDaniel Borkmann return NULL;
1761853c949SDaniel Borkmann
1771853c949SDaniel Borkmann NETLINK_CB(new).portid = NETLINK_CB(skb).portid;
1781853c949SDaniel Borkmann NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group;
1791853c949SDaniel Borkmann NETLINK_CB(new).creds = NETLINK_CB(skb).creds;
1801853c949SDaniel Borkmann
18159ae1d12SJohannes Berg skb_put_data(new, skb->data, len);
1821853c949SDaniel Borkmann return new;
1831853c949SDaniel Borkmann }
1841853c949SDaniel Borkmann
18525e3f70fSCong Wang static unsigned int netlink_tap_net_id;
18625e3f70fSCong Wang
18725e3f70fSCong Wang struct netlink_tap_net {
18825e3f70fSCong Wang struct list_head netlink_tap_all;
189b1042d35SCong Wang struct mutex netlink_tap_lock;
19025e3f70fSCong Wang };
19125e3f70fSCong Wang
netlink_add_tap(struct netlink_tap * nt)192bcbde0d4SDaniel Borkmann int netlink_add_tap(struct netlink_tap *nt)
193bcbde0d4SDaniel Borkmann {
19425e3f70fSCong Wang struct net *net = dev_net(nt->dev);
19525e3f70fSCong Wang struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id);
19625e3f70fSCong Wang
197bcbde0d4SDaniel Borkmann if (unlikely(nt->dev->type != ARPHRD_NETLINK))
198bcbde0d4SDaniel Borkmann return -EINVAL;
199bcbde0d4SDaniel Borkmann
200b1042d35SCong Wang mutex_lock(&nn->netlink_tap_lock);
20125e3f70fSCong Wang list_add_rcu(&nt->list, &nn->netlink_tap_all);
202b1042d35SCong Wang mutex_unlock(&nn->netlink_tap_lock);
203bcbde0d4SDaniel Borkmann
204bcbde0d4SDaniel Borkmann __module_get(nt->module);
205bcbde0d4SDaniel Borkmann
206bcbde0d4SDaniel Borkmann return 0;
207bcbde0d4SDaniel Borkmann }
208bcbde0d4SDaniel Borkmann EXPORT_SYMBOL_GPL(netlink_add_tap);
209bcbde0d4SDaniel Borkmann
__netlink_remove_tap(struct netlink_tap * nt)2102173f8d9Sstephen hemminger static int __netlink_remove_tap(struct netlink_tap *nt)
211bcbde0d4SDaniel Borkmann {
21225e3f70fSCong Wang struct net *net = dev_net(nt->dev);
21325e3f70fSCong Wang struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id);
214bcbde0d4SDaniel Borkmann bool found = false;
215bcbde0d4SDaniel Borkmann struct netlink_tap *tmp;
216bcbde0d4SDaniel Borkmann
217b1042d35SCong Wang mutex_lock(&nn->netlink_tap_lock);
218bcbde0d4SDaniel Borkmann
21925e3f70fSCong Wang list_for_each_entry(tmp, &nn->netlink_tap_all, list) {
220bcbde0d4SDaniel Borkmann if (nt == tmp) {
221bcbde0d4SDaniel Borkmann list_del_rcu(&nt->list);
222bcbde0d4SDaniel Borkmann found = true;
223bcbde0d4SDaniel Borkmann goto out;
224bcbde0d4SDaniel Borkmann }
225bcbde0d4SDaniel Borkmann }
226bcbde0d4SDaniel Borkmann
227bcbde0d4SDaniel Borkmann pr_warn("__netlink_remove_tap: %p not found\n", nt);
228bcbde0d4SDaniel Borkmann out:
229b1042d35SCong Wang mutex_unlock(&nn->netlink_tap_lock);
230bcbde0d4SDaniel Borkmann
23192b80eb3SMarkus Elfring if (found)
232bcbde0d4SDaniel Borkmann module_put(nt->module);
233bcbde0d4SDaniel Borkmann
234bcbde0d4SDaniel Borkmann return found ? 0 : -ENODEV;
235bcbde0d4SDaniel Borkmann }
236bcbde0d4SDaniel Borkmann
netlink_remove_tap(struct netlink_tap * nt)237bcbde0d4SDaniel Borkmann int netlink_remove_tap(struct netlink_tap *nt)
238bcbde0d4SDaniel Borkmann {
239bcbde0d4SDaniel Borkmann int ret;
240bcbde0d4SDaniel Borkmann
241bcbde0d4SDaniel Borkmann ret = __netlink_remove_tap(nt);
242bcbde0d4SDaniel Borkmann synchronize_net();
243bcbde0d4SDaniel Borkmann
244bcbde0d4SDaniel Borkmann return ret;
245bcbde0d4SDaniel Borkmann }
246bcbde0d4SDaniel Borkmann EXPORT_SYMBOL_GPL(netlink_remove_tap);
247bcbde0d4SDaniel Borkmann
netlink_tap_init_net(struct net * net)24825e3f70fSCong Wang static __net_init int netlink_tap_init_net(struct net *net)
24925e3f70fSCong Wang {
25025e3f70fSCong Wang struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id);
25125e3f70fSCong Wang
25225e3f70fSCong Wang INIT_LIST_HEAD(&nn->netlink_tap_all);
253b1042d35SCong Wang mutex_init(&nn->netlink_tap_lock);
25425e3f70fSCong Wang return 0;
25525e3f70fSCong Wang }
25625e3f70fSCong Wang
25725e3f70fSCong Wang static struct pernet_operations netlink_tap_net_ops = {
25825e3f70fSCong Wang .init = netlink_tap_init_net,
25925e3f70fSCong Wang .id = &netlink_tap_net_id,
26025e3f70fSCong Wang .size = sizeof(struct netlink_tap_net),
26125e3f70fSCong Wang };
26225e3f70fSCong Wang
netlink_filter_tap(const struct sk_buff * skb)2635ffd5cddSDaniel Borkmann static bool netlink_filter_tap(const struct sk_buff *skb)
2645ffd5cddSDaniel Borkmann {
2655ffd5cddSDaniel Borkmann struct sock *sk = skb->sk;
2665ffd5cddSDaniel Borkmann
2675ffd5cddSDaniel Borkmann /* We take the more conservative approach and
2685ffd5cddSDaniel Borkmann * whitelist socket protocols that may pass.
2695ffd5cddSDaniel Borkmann */
2705ffd5cddSDaniel Borkmann switch (sk->sk_protocol) {
2715ffd5cddSDaniel Borkmann case NETLINK_ROUTE:
2725ffd5cddSDaniel Borkmann case NETLINK_USERSOCK:
2735ffd5cddSDaniel Borkmann case NETLINK_SOCK_DIAG:
2745ffd5cddSDaniel Borkmann case NETLINK_NFLOG:
2755ffd5cddSDaniel Borkmann case NETLINK_XFRM:
2765ffd5cddSDaniel Borkmann case NETLINK_FIB_LOOKUP:
2775ffd5cddSDaniel Borkmann case NETLINK_NETFILTER:
2785ffd5cddSDaniel Borkmann case NETLINK_GENERIC:
279498044bbSVarka Bhadram return true;
2805ffd5cddSDaniel Borkmann }
2815ffd5cddSDaniel Borkmann
282498044bbSVarka Bhadram return false;
2835ffd5cddSDaniel Borkmann }
2845ffd5cddSDaniel Borkmann
__netlink_deliver_tap_skb(struct sk_buff * skb,struct net_device * dev)285bcbde0d4SDaniel Borkmann static int __netlink_deliver_tap_skb(struct sk_buff *skb,
286bcbde0d4SDaniel Borkmann struct net_device *dev)
287bcbde0d4SDaniel Borkmann {
288bcbde0d4SDaniel Borkmann struct sk_buff *nskb;
2895ffd5cddSDaniel Borkmann struct sock *sk = skb->sk;
290bcbde0d4SDaniel Borkmann int ret = -ENOMEM;
291bcbde0d4SDaniel Borkmann
29293c64764SKevin Cernekee if (!net_eq(dev_net(dev), sock_net(sk)))
29393c64764SKevin Cernekee return 0;
29493c64764SKevin Cernekee
295bcbde0d4SDaniel Borkmann dev_hold(dev);
2961853c949SDaniel Borkmann
297d1b4c689SFlorian Westphal if (is_vmalloc_addr(skb->head))
2981853c949SDaniel Borkmann nskb = netlink_to_full_skb(skb, GFP_ATOMIC);
2991853c949SDaniel Borkmann else
300bcbde0d4SDaniel Borkmann nskb = skb_clone(skb, GFP_ATOMIC);
301bcbde0d4SDaniel Borkmann if (nskb) {
302bcbde0d4SDaniel Borkmann nskb->dev = dev;
3035ffd5cddSDaniel Borkmann nskb->protocol = htons((u16) sk->sk_protocol);
304604d13c9SDaniel Borkmann nskb->pkt_type = netlink_is_kernel(sk) ?
305604d13c9SDaniel Borkmann PACKET_KERNEL : PACKET_USER;
3064e48ed88SDaniel Borkmann skb_reset_network_header(nskb);
307bcbde0d4SDaniel Borkmann ret = dev_queue_xmit(nskb);
308bcbde0d4SDaniel Borkmann if (unlikely(ret > 0))
309bcbde0d4SDaniel Borkmann ret = net_xmit_errno(ret);
310bcbde0d4SDaniel Borkmann }
311bcbde0d4SDaniel Borkmann
312bcbde0d4SDaniel Borkmann dev_put(dev);
313bcbde0d4SDaniel Borkmann return ret;
314bcbde0d4SDaniel Borkmann }
315bcbde0d4SDaniel Borkmann
__netlink_deliver_tap(struct sk_buff * skb,struct netlink_tap_net * nn)31625e3f70fSCong Wang static void __netlink_deliver_tap(struct sk_buff *skb, struct netlink_tap_net *nn)
317bcbde0d4SDaniel Borkmann {
318bcbde0d4SDaniel Borkmann int ret;
319bcbde0d4SDaniel Borkmann struct netlink_tap *tmp;
320bcbde0d4SDaniel Borkmann
3215ffd5cddSDaniel Borkmann if (!netlink_filter_tap(skb))
3225ffd5cddSDaniel Borkmann return;
3235ffd5cddSDaniel Borkmann
32425e3f70fSCong Wang list_for_each_entry_rcu(tmp, &nn->netlink_tap_all, list) {
325bcbde0d4SDaniel Borkmann ret = __netlink_deliver_tap_skb(skb, tmp->dev);
326bcbde0d4SDaniel Borkmann if (unlikely(ret))
327bcbde0d4SDaniel Borkmann break;
328bcbde0d4SDaniel Borkmann }
329bcbde0d4SDaniel Borkmann }
330bcbde0d4SDaniel Borkmann
netlink_deliver_tap(struct net * net,struct sk_buff * skb)33125e3f70fSCong Wang static void netlink_deliver_tap(struct net *net, struct sk_buff *skb)
332bcbde0d4SDaniel Borkmann {
33325e3f70fSCong Wang struct netlink_tap_net *nn = net_generic(net, netlink_tap_net_id);
33425e3f70fSCong Wang
335bcbde0d4SDaniel Borkmann rcu_read_lock();
336bcbde0d4SDaniel Borkmann
33725e3f70fSCong Wang if (unlikely(!list_empty(&nn->netlink_tap_all)))
33825e3f70fSCong Wang __netlink_deliver_tap(skb, nn);
339bcbde0d4SDaniel Borkmann
340bcbde0d4SDaniel Borkmann rcu_read_unlock();
341bcbde0d4SDaniel Borkmann }
342bcbde0d4SDaniel Borkmann
netlink_deliver_tap_kernel(struct sock * dst,struct sock * src,struct sk_buff * skb)34373bfd370SDaniel Borkmann static void netlink_deliver_tap_kernel(struct sock *dst, struct sock *src,
34473bfd370SDaniel Borkmann struct sk_buff *skb)
34573bfd370SDaniel Borkmann {
34673bfd370SDaniel Borkmann if (!(netlink_is_kernel(dst) && netlink_is_kernel(src)))
34725e3f70fSCong Wang netlink_deliver_tap(sock_net(dst), skb);
34873bfd370SDaniel Borkmann }
34973bfd370SDaniel Borkmann
netlink_overrun(struct sock * sk)350cd1df525SPatrick McHardy static void netlink_overrun(struct sock *sk)
351cd1df525SPatrick McHardy {
3528fe08d70SEric Dumazet if (!nlk_test_bit(RECV_NO_ENOBUFS, sk)) {
353cc3a572fSNicolas Dichtel if (!test_and_set_bit(NETLINK_S_CONGESTED,
354cc3a572fSNicolas Dichtel &nlk_sk(sk)->state)) {
355d0f95894SEric Dumazet WRITE_ONCE(sk->sk_err, ENOBUFS);
356e3ae2365SAlexander Aring sk_error_report(sk);
357cd1df525SPatrick McHardy }
358cd1df525SPatrick McHardy }
359cd1df525SPatrick McHardy atomic_inc(&sk->sk_drops);
360cd1df525SPatrick McHardy }
361cd1df525SPatrick McHardy
netlink_rcv_wake(struct sock * sk)362cd1df525SPatrick McHardy static void netlink_rcv_wake(struct sock *sk)
363cd1df525SPatrick McHardy {
364cd1df525SPatrick McHardy struct netlink_sock *nlk = nlk_sk(sk);
365cd1df525SPatrick McHardy
366174bce38Szhudi if (skb_queue_empty_lockless(&sk->sk_receive_queue))
367cc3a572fSNicolas Dichtel clear_bit(NETLINK_S_CONGESTED, &nlk->state);
368cc3a572fSNicolas Dichtel if (!test_bit(NETLINK_S_CONGESTED, &nlk->state))
369cd1df525SPatrick McHardy wake_up_interruptible(&nlk->wait);
370cd1df525SPatrick McHardy }
371cd1df525SPatrick McHardy
netlink_skb_destructor(struct sk_buff * skb)372cf0a018aSPatrick McHardy static void netlink_skb_destructor(struct sk_buff *skb)
373cf0a018aSPatrick McHardy {
374c05cdb1bSPablo Neira Ayuso if (is_vmalloc_addr(skb->head)) {
3753a36515fSPablo Neira if (!skb->cloned ||
3763a36515fSPablo Neira !atomic_dec_return(&(skb_shinfo(skb)->dataref)))
377b17ca9a4SZhengchao Shao vfree_atomic(skb->head);
3783a36515fSPablo Neira
379c05cdb1bSPablo Neira Ayuso skb->head = NULL;
380c05cdb1bSPablo Neira Ayuso }
3819652e931SPatrick McHardy if (skb->sk != NULL)
382cf0a018aSPatrick McHardy sock_rfree(skb);
383cf0a018aSPatrick McHardy }
384cf0a018aSPatrick McHardy
netlink_skb_set_owner_r(struct sk_buff * skb,struct sock * sk)385cf0a018aSPatrick McHardy static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
386cf0a018aSPatrick McHardy {
387cf0a018aSPatrick McHardy WARN_ON(skb->sk != NULL);
388cf0a018aSPatrick McHardy skb->sk = sk;
389cf0a018aSPatrick McHardy skb->destructor = netlink_skb_destructor;
390cf0a018aSPatrick McHardy atomic_add(skb->truesize, &sk->sk_rmem_alloc);
391cf0a018aSPatrick McHardy sk_mem_charge(sk, skb->truesize);
392cf0a018aSPatrick McHardy }
393cf0a018aSPatrick McHardy
netlink_sock_destruct(struct sock * sk)394ed5d7788SHerbert Xu static void netlink_sock_destruct(struct sock *sk)
3951da177e4SLinus Torvalds {
3961da177e4SLinus Torvalds skb_queue_purge(&sk->sk_receive_queue);
3971da177e4SLinus Torvalds
3981da177e4SLinus Torvalds if (!sock_flag(sk, SOCK_DEAD)) {
3996ac552fdSPatrick McHardy printk(KERN_ERR "Freeing alive netlink socket %p\n", sk);
4001da177e4SLinus Torvalds return;
4011da177e4SLinus Torvalds }
402547b792cSIlpo Järvinen
403547b792cSIlpo Järvinen WARN_ON(atomic_read(&sk->sk_rmem_alloc));
40414afee4bSReshetova, Elena WARN_ON(refcount_read(&sk->sk_wmem_alloc));
405547b792cSIlpo Järvinen WARN_ON(nlk_sk(sk)->groups);
4061da177e4SLinus Torvalds }
4071da177e4SLinus Torvalds
4086ac552fdSPatrick McHardy /* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on
4096ac552fdSPatrick McHardy * SMP. Look, when several writers sleep and reader wakes them up, all but one
4101da177e4SLinus Torvalds * immediately hit write lock and grab all the cpus. Exclusive sleep solves
4111da177e4SLinus Torvalds * this, _but_ remember, it adds useless work on UP machines.
4121da177e4SLinus Torvalds */
4131da177e4SLinus Torvalds
netlink_table_grab(void)414d136f1bdSJohannes Berg void netlink_table_grab(void)
4159a429c49SEric Dumazet __acquires(nl_table_lock)
4161da177e4SLinus Torvalds {
417d136f1bdSJohannes Berg might_sleep();
418d136f1bdSJohannes Berg
4196abd219cSArjan van de Ven write_lock_irq(&nl_table_lock);
4201da177e4SLinus Torvalds
4211da177e4SLinus Torvalds if (atomic_read(&nl_table_users)) {
4221da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current);
4231da177e4SLinus Torvalds
4241da177e4SLinus Torvalds add_wait_queue_exclusive(&nl_table_wait, &wait);
4251da177e4SLinus Torvalds for (;;) {
4261da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE);
4271da177e4SLinus Torvalds if (atomic_read(&nl_table_users) == 0)
4281da177e4SLinus Torvalds break;
4296abd219cSArjan van de Ven write_unlock_irq(&nl_table_lock);
4301da177e4SLinus Torvalds schedule();
4316abd219cSArjan van de Ven write_lock_irq(&nl_table_lock);
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds
4341da177e4SLinus Torvalds __set_current_state(TASK_RUNNING);
4351da177e4SLinus Torvalds remove_wait_queue(&nl_table_wait, &wait);
4361da177e4SLinus Torvalds }
4371da177e4SLinus Torvalds }
4381da177e4SLinus Torvalds
netlink_table_ungrab(void)439d136f1bdSJohannes Berg void netlink_table_ungrab(void)
4409a429c49SEric Dumazet __releases(nl_table_lock)
4411da177e4SLinus Torvalds {
4426abd219cSArjan van de Ven write_unlock_irq(&nl_table_lock);
4431da177e4SLinus Torvalds wake_up(&nl_table_wait);
4441da177e4SLinus Torvalds }
4451da177e4SLinus Torvalds
4466ac552fdSPatrick McHardy static inline void
netlink_lock_table(void)4471da177e4SLinus Torvalds netlink_lock_table(void)
4481da177e4SLinus Torvalds {
4491d482e66SJohannes Berg unsigned long flags;
4501d482e66SJohannes Berg
4511da177e4SLinus Torvalds /* read_lock() synchronizes us to netlink_table_grab */
4521da177e4SLinus Torvalds
4531d482e66SJohannes Berg read_lock_irqsave(&nl_table_lock, flags);
4541da177e4SLinus Torvalds atomic_inc(&nl_table_users);
4551d482e66SJohannes Berg read_unlock_irqrestore(&nl_table_lock, flags);
4561da177e4SLinus Torvalds }
4571da177e4SLinus Torvalds
4586ac552fdSPatrick McHardy static inline void
netlink_unlock_table(void)4591da177e4SLinus Torvalds netlink_unlock_table(void)
4601da177e4SLinus Torvalds {
4611da177e4SLinus Torvalds if (atomic_dec_and_test(&nl_table_users))
4621da177e4SLinus Torvalds wake_up(&nl_table_wait);
4631da177e4SLinus Torvalds }
4641da177e4SLinus Torvalds
465e341694eSThomas Graf struct netlink_compare_arg
466da12c90eSGao feng {
467c428ecd1SHerbert Xu possible_net_t pnet;
468e341694eSThomas Graf u32 portid;
469e341694eSThomas Graf };
470e341694eSThomas Graf
4718f2ddaacSHerbert Xu /* Doing sizeof directly may yield 4 extra bytes on 64-bit. */
4728f2ddaacSHerbert Xu #define netlink_compare_arg_len \
4738f2ddaacSHerbert Xu (offsetof(struct netlink_compare_arg, portid) + sizeof(u32))
474e341694eSThomas Graf
netlink_compare(struct rhashtable_compare_arg * arg,const void * ptr)475c428ecd1SHerbert Xu static inline int netlink_compare(struct rhashtable_compare_arg *arg,
476c428ecd1SHerbert Xu const void *ptr)
477c428ecd1SHerbert Xu {
478c428ecd1SHerbert Xu const struct netlink_compare_arg *x = arg->key;
479c428ecd1SHerbert Xu const struct netlink_sock *nlk = ptr;
480c428ecd1SHerbert Xu
481da314c99SHerbert Xu return nlk->portid != x->portid ||
482c428ecd1SHerbert Xu !net_eq(sock_net(&nlk->sk), read_pnet(&x->pnet));
483c428ecd1SHerbert Xu }
484c428ecd1SHerbert Xu
netlink_compare_arg_init(struct netlink_compare_arg * arg,struct net * net,u32 portid)485c428ecd1SHerbert Xu static void netlink_compare_arg_init(struct netlink_compare_arg *arg,
486c428ecd1SHerbert Xu struct net *net, u32 portid)
487c428ecd1SHerbert Xu {
488c428ecd1SHerbert Xu memset(arg, 0, sizeof(*arg));
489c428ecd1SHerbert Xu write_pnet(&arg->pnet, net);
490c428ecd1SHerbert Xu arg->portid = portid;
491e341694eSThomas Graf }
492e341694eSThomas Graf
__netlink_lookup(struct netlink_table * table,u32 portid,struct net * net)493e341694eSThomas Graf static struct sock *__netlink_lookup(struct netlink_table *table, u32 portid,
494e341694eSThomas Graf struct net *net)
495e341694eSThomas Graf {
496c428ecd1SHerbert Xu struct netlink_compare_arg arg;
497e341694eSThomas Graf
498c428ecd1SHerbert Xu netlink_compare_arg_init(&arg, net, portid);
499c428ecd1SHerbert Xu return rhashtable_lookup_fast(&table->hash, &arg,
500c428ecd1SHerbert Xu netlink_rhashtable_params);
501da12c90eSGao feng }
502da12c90eSGao feng
__netlink_insert(struct netlink_table * table,struct sock * sk)503c428ecd1SHerbert Xu static int __netlink_insert(struct netlink_table *table, struct sock *sk)
504c5adde94SYing Xue {
505c428ecd1SHerbert Xu struct netlink_compare_arg arg;
506c5adde94SYing Xue
507da314c99SHerbert Xu netlink_compare_arg_init(&arg, sock_net(sk), nlk_sk(sk)->portid);
508c428ecd1SHerbert Xu return rhashtable_lookup_insert_key(&table->hash, &arg,
509c5adde94SYing Xue &nlk_sk(sk)->node,
510c428ecd1SHerbert Xu netlink_rhashtable_params);
511c5adde94SYing Xue }
512c5adde94SYing Xue
netlink_lookup(struct net * net,int protocol,u32 portid)51315e47304SEric W. Biederman static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid)
5141da177e4SLinus Torvalds {
515da12c90eSGao feng struct netlink_table *table = &nl_table[protocol];
5161da177e4SLinus Torvalds struct sock *sk;
5171da177e4SLinus Torvalds
518e341694eSThomas Graf rcu_read_lock();
519e341694eSThomas Graf sk = __netlink_lookup(table, portid, net);
520e341694eSThomas Graf if (sk)
5211da177e4SLinus Torvalds sock_hold(sk);
522e341694eSThomas Graf rcu_read_unlock();
523e341694eSThomas Graf
5241da177e4SLinus Torvalds return sk;
5251da177e4SLinus Torvalds }
5261da177e4SLinus Torvalds
52790ddc4f0SEric Dumazet static const struct proto_ops netlink_ops;
5281da177e4SLinus Torvalds
5294277a083SPatrick McHardy static void
netlink_update_listeners(struct sock * sk)5304277a083SPatrick McHardy netlink_update_listeners(struct sock *sk)
5314277a083SPatrick McHardy {
5324277a083SPatrick McHardy struct netlink_table *tbl = &nl_table[sk->sk_protocol];
5334277a083SPatrick McHardy unsigned long mask;
5344277a083SPatrick McHardy unsigned int i;
5356d772ac5SEric Dumazet struct listeners *listeners;
5366d772ac5SEric Dumazet
5376d772ac5SEric Dumazet listeners = nl_deref_protected(tbl->listeners);
5386d772ac5SEric Dumazet if (!listeners)
5396d772ac5SEric Dumazet return;
5404277a083SPatrick McHardy
541b4ff4f04SJohannes Berg for (i = 0; i < NLGRPLONGS(tbl->groups); i++) {
5424277a083SPatrick McHardy mask = 0;
543b67bfe0dSSasha Levin sk_for_each_bound(sk, &tbl->mc_list) {
544b4ff4f04SJohannes Berg if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
5454277a083SPatrick McHardy mask |= nlk_sk(sk)->groups[i];
546b4ff4f04SJohannes Berg }
5476d772ac5SEric Dumazet listeners->masks[i] = mask;
5484277a083SPatrick McHardy }
5494277a083SPatrick McHardy /* this function is only called with the netlink table "grabbed", which
5504277a083SPatrick McHardy * makes sure updates are visible before bind or setsockopt return. */
5514277a083SPatrick McHardy }
5524277a083SPatrick McHardy
netlink_insert(struct sock * sk,u32 portid)5538ea65f4aSHerbert Xu static int netlink_insert(struct sock *sk, u32 portid)
5541da177e4SLinus Torvalds {
555da12c90eSGao feng struct netlink_table *table = &nl_table[sk->sk_protocol];
556919d9db9SHerbert Xu int err;
5571da177e4SLinus Torvalds
558c5adde94SYing Xue lock_sock(sk);
5591da177e4SLinus Torvalds
560da314c99SHerbert Xu err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY;
561da314c99SHerbert Xu if (nlk_sk(sk)->bound)
5621da177e4SLinus Torvalds goto err;
5631da177e4SLinus Torvalds
564c1bb9484SEric Dumazet /* portid can be read locklessly from netlink_getname(). */
565c1bb9484SEric Dumazet WRITE_ONCE(nlk_sk(sk)->portid, portid);
566c1bb9484SEric Dumazet
567e341694eSThomas Graf sock_hold(sk);
568919d9db9SHerbert Xu
569c428ecd1SHerbert Xu err = __netlink_insert(table, sk);
570c428ecd1SHerbert Xu if (err) {
5714e7c1330SDaniel Borkmann /* In case the hashtable backend returns with -EBUSY
5724e7c1330SDaniel Borkmann * from here, it must not escape to the caller.
5734e7c1330SDaniel Borkmann */
5744e7c1330SDaniel Borkmann if (unlikely(err == -EBUSY))
5754e7c1330SDaniel Borkmann err = -EOVERFLOW;
576c428ecd1SHerbert Xu if (err == -EEXIST)
577919d9db9SHerbert Xu err = -EADDRINUSE;
578c5adde94SYing Xue sock_put(sk);
5791f770c0aSHerbert Xu goto err;
580919d9db9SHerbert Xu }
581919d9db9SHerbert Xu
582da314c99SHerbert Xu /* We need to ensure that the socket is hashed and visible. */
583da314c99SHerbert Xu smp_wmb();
5847707a4d0SEric Dumazet /* Paired with lockless reads from netlink_bind(),
5857707a4d0SEric Dumazet * netlink_connect() and netlink_sendmsg().
5867707a4d0SEric Dumazet */
5877707a4d0SEric Dumazet WRITE_ONCE(nlk_sk(sk)->bound, portid);
5881f770c0aSHerbert Xu
5891da177e4SLinus Torvalds err:
590c5adde94SYing Xue release_sock(sk);
5911da177e4SLinus Torvalds return err;
5921da177e4SLinus Torvalds }
5931da177e4SLinus Torvalds
netlink_remove(struct sock * sk)5941da177e4SLinus Torvalds static void netlink_remove(struct sock *sk)
5951da177e4SLinus Torvalds {
596e341694eSThomas Graf struct netlink_table *table;
597e341694eSThomas Graf
598e341694eSThomas Graf table = &nl_table[sk->sk_protocol];
599c428ecd1SHerbert Xu if (!rhashtable_remove_fast(&table->hash, &nlk_sk(sk)->node,
600c428ecd1SHerbert Xu netlink_rhashtable_params)) {
60141c6d650SReshetova, Elena WARN_ON(refcount_read(&sk->sk_refcnt) == 1);
602e341694eSThomas Graf __sock_put(sk);
603e341694eSThomas Graf }
604e341694eSThomas Graf
6051da177e4SLinus Torvalds netlink_table_grab();
606b10dcb3bSJohannes Berg if (nlk_sk(sk)->subscriptions) {
6071da177e4SLinus Torvalds __sk_del_bind_node(sk);
608b10dcb3bSJohannes Berg netlink_update_listeners(sk);
609b10dcb3bSJohannes Berg }
610ee1c2442SJohannes Berg if (sk->sk_protocol == NETLINK_GENERIC)
611ee1c2442SJohannes Berg atomic_inc(&genl_sk_destructing_cnt);
6121da177e4SLinus Torvalds netlink_table_ungrab();
6131da177e4SLinus Torvalds }
6141da177e4SLinus Torvalds
6151da177e4SLinus Torvalds static struct proto netlink_proto = {
6161da177e4SLinus Torvalds .name = "NETLINK",
6171da177e4SLinus Torvalds .owner = THIS_MODULE,
6181da177e4SLinus Torvalds .obj_size = sizeof(struct netlink_sock),
6191da177e4SLinus Torvalds };
6201da177e4SLinus Torvalds
__netlink_create(struct net * net,struct socket * sock,struct mutex * dump_cb_mutex,int protocol,int kern)6211b8d7ae4SEric W. Biederman static int __netlink_create(struct net *net, struct socket *sock,
622c8c76f15SEric Dumazet struct mutex *dump_cb_mutex, int protocol,
62311aa9c28SEric W. Biederman int kern)
6241da177e4SLinus Torvalds {
6251da177e4SLinus Torvalds struct sock *sk;
6261da177e4SLinus Torvalds struct netlink_sock *nlk;
627ab33a171SPatrick McHardy
628ab33a171SPatrick McHardy sock->ops = &netlink_ops;
629ab33a171SPatrick McHardy
63011aa9c28SEric W. Biederman sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto, kern);
631ab33a171SPatrick McHardy if (!sk)
632ab33a171SPatrick McHardy return -ENOMEM;
633ab33a171SPatrick McHardy
634ab33a171SPatrick McHardy sock_init_data(sock, sk);
635ab33a171SPatrick McHardy
636ab33a171SPatrick McHardy nlk = nlk_sk(sk);
637c8c76f15SEric Dumazet mutex_init(&nlk->nl_cb_mutex);
638c8c76f15SEric Dumazet lockdep_set_class_and_name(&nlk->nl_cb_mutex,
6398a0f5ccfSHerbert Xu nlk_cb_mutex_keys + protocol,
6408a0f5ccfSHerbert Xu nlk_cb_mutex_key_strings[protocol]);
641c8c76f15SEric Dumazet nlk->dump_cb_mutex = dump_cb_mutex;
642ab33a171SPatrick McHardy init_waitqueue_head(&nlk->wait);
643ab33a171SPatrick McHardy
644ab33a171SPatrick McHardy sk->sk_destruct = netlink_sock_destruct;
645ab33a171SPatrick McHardy sk->sk_protocol = protocol;
646ab33a171SPatrick McHardy return 0;
647ab33a171SPatrick McHardy }
648ab33a171SPatrick McHardy
netlink_create(struct net * net,struct socket * sock,int protocol,int kern)6493f378b68SEric Paris static int netlink_create(struct net *net, struct socket *sock, int protocol,
6503f378b68SEric Paris int kern)
651ab33a171SPatrick McHardy {
652ab33a171SPatrick McHardy struct module *module = NULL;
653af65bdfcSPatrick McHardy struct mutex *cb_mutex;
654f7fa9b10SPatrick McHardy struct netlink_sock *nlk;
655023e2cfaSJohannes Berg int (*bind)(struct net *net, int group);
656023e2cfaSJohannes Berg void (*unbind)(struct net *net, int group);
657a4c9a56eSAnjali Kulkarni void (*release)(struct sock *sock, unsigned long *groups);
658ab33a171SPatrick McHardy int err = 0;
6591da177e4SLinus Torvalds
6601da177e4SLinus Torvalds sock->state = SS_UNCONNECTED;
6611da177e4SLinus Torvalds
6621da177e4SLinus Torvalds if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM)
6631da177e4SLinus Torvalds return -ESOCKTNOSUPPORT;
6641da177e4SLinus Torvalds
6651da177e4SLinus Torvalds if (protocol < 0 || protocol >= MAX_LINKS)
6661da177e4SLinus Torvalds return -EPROTONOSUPPORT;
667bc5b6c0bSJeremy Cline protocol = array_index_nospec(protocol, MAX_LINKS);
6681da177e4SLinus Torvalds
66977247bbbSPatrick McHardy netlink_lock_table();
67095a5afcaSJohannes Berg #ifdef CONFIG_MODULES
671ab33a171SPatrick McHardy if (!nl_table[protocol].registered) {
67277247bbbSPatrick McHardy netlink_unlock_table();
6734fdb3bb7SHarald Welte request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol);
67477247bbbSPatrick McHardy netlink_lock_table();
6754fdb3bb7SHarald Welte }
676ab33a171SPatrick McHardy #endif
677ab33a171SPatrick McHardy if (nl_table[protocol].registered &&
678ab33a171SPatrick McHardy try_module_get(nl_table[protocol].module))
67977247bbbSPatrick McHardy module = nl_table[protocol].module;
680974c37e9SAlexey Dobriyan else
681974c37e9SAlexey Dobriyan err = -EPROTONOSUPPORT;
682af65bdfcSPatrick McHardy cb_mutex = nl_table[protocol].cb_mutex;
68303292745SPablo Neira Ayuso bind = nl_table[protocol].bind;
6844f520900SRichard Guy Briggs unbind = nl_table[protocol].unbind;
685a4c9a56eSAnjali Kulkarni release = nl_table[protocol].release;
68677247bbbSPatrick McHardy netlink_unlock_table();
6874fdb3bb7SHarald Welte
688974c37e9SAlexey Dobriyan if (err < 0)
689974c37e9SAlexey Dobriyan goto out;
690974c37e9SAlexey Dobriyan
69111aa9c28SEric W. Biederman err = __netlink_create(net, sock, cb_mutex, protocol, kern);
6926ac552fdSPatrick McHardy if (err < 0)
693ab33a171SPatrick McHardy goto out_module;
694ab33a171SPatrick McHardy
695c1fd3b94SEric Dumazet sock_prot_inuse_add(net, &netlink_proto, 1);
6966f756a8cSDavid S. Miller
697f7fa9b10SPatrick McHardy nlk = nlk_sk(sock->sk);
698f7fa9b10SPatrick McHardy nlk->module = module;
69903292745SPablo Neira Ayuso nlk->netlink_bind = bind;
7004f520900SRichard Guy Briggs nlk->netlink_unbind = unbind;
701a4c9a56eSAnjali Kulkarni nlk->netlink_release = release;
702ab33a171SPatrick McHardy out:
703ab33a171SPatrick McHardy return err;
704ab33a171SPatrick McHardy
705ab33a171SPatrick McHardy out_module:
70677247bbbSPatrick McHardy module_put(module);
707ab33a171SPatrick McHardy goto out;
7081da177e4SLinus Torvalds }
7091da177e4SLinus Torvalds
deferred_put_nlk_sk(struct rcu_head * head)71021e4902aSThomas Graf static void deferred_put_nlk_sk(struct rcu_head *head)
71121e4902aSThomas Graf {
71221e4902aSThomas Graf struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu);
713ed5d7788SHerbert Xu struct sock *sk = &nlk->sk;
71421e4902aSThomas Graf
715be82485fSXin Long kfree(nlk->groups);
716be82485fSXin Long nlk->groups = NULL;
717be82485fSXin Long
71841c6d650SReshetova, Elena if (!refcount_dec_and_test(&sk->sk_refcnt))
719ed5d7788SHerbert Xu return;
720ed5d7788SHerbert Xu
721ed5d7788SHerbert Xu sk_free(sk);
72221e4902aSThomas Graf }
72321e4902aSThomas Graf
netlink_release(struct socket * sock)7241da177e4SLinus Torvalds static int netlink_release(struct socket *sock)
7251da177e4SLinus Torvalds {
7261da177e4SLinus Torvalds struct sock *sk = sock->sk;
7271da177e4SLinus Torvalds struct netlink_sock *nlk;
7281da177e4SLinus Torvalds
7291da177e4SLinus Torvalds if (!sk)
7301da177e4SLinus Torvalds return 0;
7311da177e4SLinus Torvalds
7321da177e4SLinus Torvalds netlink_remove(sk);
733ac57b3a9SDenis Lunev sock_orphan(sk);
7341da177e4SLinus Torvalds nlk = nlk_sk(sk);
7351da177e4SLinus Torvalds
7363f660d66SHerbert Xu /*
7373f660d66SHerbert Xu * OK. Socket is unlinked, any packets that arrive now
7383f660d66SHerbert Xu * will be purged.
7393f660d66SHerbert Xu */
740a4c9a56eSAnjali Kulkarni if (nlk->netlink_release)
741a4c9a56eSAnjali Kulkarni nlk->netlink_release(sk, nlk->groups);
7421da177e4SLinus Torvalds
743ee1c2442SJohannes Berg /* must not acquire netlink_table_lock in any way again before unbind
744ee1c2442SJohannes Berg * and notifying genetlink is done as otherwise it might deadlock
745ee1c2442SJohannes Berg */
746ee1c2442SJohannes Berg if (nlk->netlink_unbind) {
747ee1c2442SJohannes Berg int i;
748ee1c2442SJohannes Berg
749ee1c2442SJohannes Berg for (i = 0; i < nlk->ngroups; i++)
750ee1c2442SJohannes Berg if (test_bit(i, nlk->groups))
751ee1c2442SJohannes Berg nlk->netlink_unbind(sock_net(sk), i + 1);
752ee1c2442SJohannes Berg }
753ee1c2442SJohannes Berg if (sk->sk_protocol == NETLINK_GENERIC &&
754ee1c2442SJohannes Berg atomic_dec_return(&genl_sk_destructing_cnt) == 0)
755ee1c2442SJohannes Berg wake_up(&genl_sk_destructing_waitq);
756ee1c2442SJohannes Berg
7571da177e4SLinus Torvalds sock->sk = NULL;
7581da177e4SLinus Torvalds wake_up_interruptible_all(&nlk->wait);
7591da177e4SLinus Torvalds
7601da177e4SLinus Torvalds skb_queue_purge(&sk->sk_write_queue);
7611da177e4SLinus Torvalds
762e2726020SDmitry Ivanov if (nlk->portid && nlk->bound) {
7631da177e4SLinus Torvalds struct netlink_notify n = {
7643b1e0a65SYOSHIFUJI Hideaki .net = sock_net(sk),
7651da177e4SLinus Torvalds .protocol = sk->sk_protocol,
76615e47304SEric W. Biederman .portid = nlk->portid,
7671da177e4SLinus Torvalds };
768efa172f4SWANG Cong blocking_notifier_call_chain(&netlink_chain,
769e041c683SAlan Stern NETLINK_URELEASE, &n);
7701da177e4SLinus Torvalds }
7711da177e4SLinus Torvalds
772*bbc769d2SJakub Kicinski /* Terminate any outstanding dump */
773*bbc769d2SJakub Kicinski if (nlk->cb_running) {
774*bbc769d2SJakub Kicinski if (nlk->cb.done)
775*bbc769d2SJakub Kicinski nlk->cb.done(&nlk->cb);
776*bbc769d2SJakub Kicinski module_put(nlk->cb.module);
777*bbc769d2SJakub Kicinski kfree_skb(nlk->cb.skb);
778*bbc769d2SJakub Kicinski }
779*bbc769d2SJakub Kicinski
78077247bbbSPatrick McHardy module_put(nlk->module);
7814fdb3bb7SHarald Welte
782aed81560SDenis V. Lunev if (netlink_is_kernel(sk)) {
783b10dcb3bSJohannes Berg netlink_table_grab();
784869e58f8SDenis V. Lunev BUG_ON(nl_table[sk->sk_protocol].registered == 0);
785869e58f8SDenis V. Lunev if (--nl_table[sk->sk_protocol].registered == 0) {
7866d772ac5SEric Dumazet struct listeners *old;
7876d772ac5SEric Dumazet
7886d772ac5SEric Dumazet old = nl_deref_protected(nl_table[sk->sk_protocol].listeners);
7896d772ac5SEric Dumazet RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL);
7906d772ac5SEric Dumazet kfree_rcu(old, rcu);
79177247bbbSPatrick McHardy nl_table[sk->sk_protocol].module = NULL;
7929785e10aSPablo Neira Ayuso nl_table[sk->sk_protocol].bind = NULL;
7934f520900SRichard Guy Briggs nl_table[sk->sk_protocol].unbind = NULL;
7949785e10aSPablo Neira Ayuso nl_table[sk->sk_protocol].flags = 0;
795ab33a171SPatrick McHardy nl_table[sk->sk_protocol].registered = 0;
796869e58f8SDenis V. Lunev }
7974fdb3bb7SHarald Welte netlink_table_ungrab();
798b10dcb3bSJohannes Berg }
7994fdb3bb7SHarald Welte
800c1fd3b94SEric Dumazet sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1);
8010cafd77dSEric Dumazet
8020cafd77dSEric Dumazet /* Because struct net might disappear soon, do not keep a pointer. */
8030cafd77dSEric Dumazet if (!sk->sk_net_refcnt && sock_net(sk) != &init_net) {
8040cafd77dSEric Dumazet __netns_tracker_free(sock_net(sk), &sk->ns_tracker, false);
8050cafd77dSEric Dumazet /* Because of deferred_put_nlk_sk and use of work queue,
8060cafd77dSEric Dumazet * it is possible netns will be freed before this socket.
8070cafd77dSEric Dumazet */
8080cafd77dSEric Dumazet sock_net_set(sk, &init_net);
8090cafd77dSEric Dumazet __netns_tracker_alloc(&init_net, &sk->ns_tracker,
8100cafd77dSEric Dumazet false, GFP_KERNEL);
8110cafd77dSEric Dumazet }
81221e4902aSThomas Graf call_rcu(&nlk->rcu, deferred_put_nlk_sk);
8131da177e4SLinus Torvalds return 0;
8141da177e4SLinus Torvalds }
8151da177e4SLinus Torvalds
netlink_autobind(struct socket * sock)8161da177e4SLinus Torvalds static int netlink_autobind(struct socket *sock)
8171da177e4SLinus Torvalds {
8181da177e4SLinus Torvalds struct sock *sk = sock->sk;
8193b1e0a65SYOSHIFUJI Hideaki struct net *net = sock_net(sk);
820da12c90eSGao feng struct netlink_table *table = &nl_table[sk->sk_protocol];
82115e47304SEric W. Biederman s32 portid = task_tgid_vnr(current);
8221da177e4SLinus Torvalds int err;
823b9fbe709SHerbert Xu s32 rover = -4096;
824b9fbe709SHerbert Xu bool ok;
8251da177e4SLinus Torvalds
8261da177e4SLinus Torvalds retry:
8271da177e4SLinus Torvalds cond_resched();
828e341694eSThomas Graf rcu_read_lock();
829b9fbe709SHerbert Xu ok = !__netlink_lookup(table, portid, net);
830e341694eSThomas Graf rcu_read_unlock();
831b9fbe709SHerbert Xu if (!ok) {
832b9fbe709SHerbert Xu /* Bind collision, search negative portid values. */
833b9fbe709SHerbert Xu if (rover == -4096)
834b9fbe709SHerbert Xu /* rover will be in range [S32_MIN, -4097] */
8358032bf12SJason A. Donenfeld rover = S32_MIN + get_random_u32_below(-4096 - S32_MIN);
836b9fbe709SHerbert Xu else if (rover >= -4096)
837b9fbe709SHerbert Xu rover = -4097;
838b9fbe709SHerbert Xu portid = rover--;
8391da177e4SLinus Torvalds goto retry;
8401da177e4SLinus Torvalds }
8411da177e4SLinus Torvalds
8428ea65f4aSHerbert Xu err = netlink_insert(sk, portid);
8431da177e4SLinus Torvalds if (err == -EADDRINUSE)
8441da177e4SLinus Torvalds goto retry;
845d470e3b4SDavid S. Miller
846d470e3b4SDavid S. Miller /* If 2 threads race to autobind, that is fine. */
847d470e3b4SDavid S. Miller if (err == -EBUSY)
848d470e3b4SDavid S. Miller err = 0;
849d470e3b4SDavid S. Miller
850d470e3b4SDavid S. Miller return err;
8511da177e4SLinus Torvalds }
8521da177e4SLinus Torvalds
853aa4cf945SEric W. Biederman /**
854aa4cf945SEric W. Biederman * __netlink_ns_capable - General netlink message capability test
855aa4cf945SEric W. Biederman * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace.
856aa4cf945SEric W. Biederman * @user_ns: The user namespace of the capability to use
857aa4cf945SEric W. Biederman * @cap: The capability to use
858aa4cf945SEric W. Biederman *
859aa4cf945SEric W. Biederman * Test to see if the opener of the socket we received the message
860aa4cf945SEric W. Biederman * from had when the netlink socket was created and the sender of the
86185405918SRandy Dunlap * message has the capability @cap in the user namespace @user_ns.
862aa4cf945SEric W. Biederman */
__netlink_ns_capable(const struct netlink_skb_parms * nsp,struct user_namespace * user_ns,int cap)863aa4cf945SEric W. Biederman bool __netlink_ns_capable(const struct netlink_skb_parms *nsp,
864aa4cf945SEric W. Biederman struct user_namespace *user_ns, int cap)
865aa4cf945SEric W. Biederman {
8662d7a85f4SEric W. Biederman return ((nsp->flags & NETLINK_SKB_DST) ||
8672d7a85f4SEric W. Biederman file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) &&
8682d7a85f4SEric W. Biederman ns_capable(user_ns, cap);
869aa4cf945SEric W. Biederman }
870aa4cf945SEric W. Biederman EXPORT_SYMBOL(__netlink_ns_capable);
871aa4cf945SEric W. Biederman
872aa4cf945SEric W. Biederman /**
873aa4cf945SEric W. Biederman * netlink_ns_capable - General netlink message capability test
874aa4cf945SEric W. Biederman * @skb: socket buffer holding a netlink command from userspace
875aa4cf945SEric W. Biederman * @user_ns: The user namespace of the capability to use
876aa4cf945SEric W. Biederman * @cap: The capability to use
877aa4cf945SEric W. Biederman *
878aa4cf945SEric W. Biederman * Test to see if the opener of the socket we received the message
879aa4cf945SEric W. Biederman * from had when the netlink socket was created and the sender of the
88085405918SRandy Dunlap * message has the capability @cap in the user namespace @user_ns.
881aa4cf945SEric W. Biederman */
netlink_ns_capable(const struct sk_buff * skb,struct user_namespace * user_ns,int cap)882aa4cf945SEric W. Biederman bool netlink_ns_capable(const struct sk_buff *skb,
883aa4cf945SEric W. Biederman struct user_namespace *user_ns, int cap)
884aa4cf945SEric W. Biederman {
885aa4cf945SEric W. Biederman return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap);
886aa4cf945SEric W. Biederman }
887aa4cf945SEric W. Biederman EXPORT_SYMBOL(netlink_ns_capable);
888aa4cf945SEric W. Biederman
889aa4cf945SEric W. Biederman /**
890aa4cf945SEric W. Biederman * netlink_capable - Netlink global message capability test
891aa4cf945SEric W. Biederman * @skb: socket buffer holding a netlink command from userspace
892aa4cf945SEric W. Biederman * @cap: The capability to use
893aa4cf945SEric W. Biederman *
894aa4cf945SEric W. Biederman * Test to see if the opener of the socket we received the message
895aa4cf945SEric W. Biederman * from had when the netlink socket was created and the sender of the
89685405918SRandy Dunlap * message has the capability @cap in all user namespaces.
897aa4cf945SEric W. Biederman */
netlink_capable(const struct sk_buff * skb,int cap)898aa4cf945SEric W. Biederman bool netlink_capable(const struct sk_buff *skb, int cap)
899aa4cf945SEric W. Biederman {
900aa4cf945SEric W. Biederman return netlink_ns_capable(skb, &init_user_ns, cap);
901aa4cf945SEric W. Biederman }
902aa4cf945SEric W. Biederman EXPORT_SYMBOL(netlink_capable);
903aa4cf945SEric W. Biederman
904aa4cf945SEric W. Biederman /**
905aa4cf945SEric W. Biederman * netlink_net_capable - Netlink network namespace message capability test
906aa4cf945SEric W. Biederman * @skb: socket buffer holding a netlink command from userspace
907aa4cf945SEric W. Biederman * @cap: The capability to use
908aa4cf945SEric W. Biederman *
909aa4cf945SEric W. Biederman * Test to see if the opener of the socket we received the message
910aa4cf945SEric W. Biederman * from had when the netlink socket was created and the sender of the
91185405918SRandy Dunlap * message has the capability @cap over the network namespace of
912aa4cf945SEric W. Biederman * the socket we received the message from.
913aa4cf945SEric W. Biederman */
netlink_net_capable(const struct sk_buff * skb,int cap)914aa4cf945SEric W. Biederman bool netlink_net_capable(const struct sk_buff *skb, int cap)
915aa4cf945SEric W. Biederman {
916aa4cf945SEric W. Biederman return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap);
917aa4cf945SEric W. Biederman }
918aa4cf945SEric W. Biederman EXPORT_SYMBOL(netlink_net_capable);
919aa4cf945SEric W. Biederman
netlink_allowed(const struct socket * sock,unsigned int flag)9205187cd05SEric W. Biederman static inline int netlink_allowed(const struct socket *sock, unsigned int flag)
9211da177e4SLinus Torvalds {
9229785e10aSPablo Neira Ayuso return (nl_table[sock->sk->sk_protocol].flags & flag) ||
923df008c91SEric W. Biederman ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN);
9241da177e4SLinus Torvalds }
9251da177e4SLinus Torvalds
926f7fa9b10SPatrick McHardy static void
netlink_update_subscriptions(struct sock * sk,unsigned int subscriptions)927f7fa9b10SPatrick McHardy netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions)
928f7fa9b10SPatrick McHardy {
929f7fa9b10SPatrick McHardy struct netlink_sock *nlk = nlk_sk(sk);
930f7fa9b10SPatrick McHardy
931f7fa9b10SPatrick McHardy if (nlk->subscriptions && !subscriptions)
932f7fa9b10SPatrick McHardy __sk_del_bind_node(sk);
933f7fa9b10SPatrick McHardy else if (!nlk->subscriptions && subscriptions)
934f7fa9b10SPatrick McHardy sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list);
935f7fa9b10SPatrick McHardy nlk->subscriptions = subscriptions;
936f7fa9b10SPatrick McHardy }
937f7fa9b10SPatrick McHardy
netlink_realloc_groups(struct sock * sk)938b4ff4f04SJohannes Berg static int netlink_realloc_groups(struct sock *sk)
939513c2500SPatrick McHardy {
940513c2500SPatrick McHardy struct netlink_sock *nlk = nlk_sk(sk);
941513c2500SPatrick McHardy unsigned int groups;
942b4ff4f04SJohannes Berg unsigned long *new_groups;
943513c2500SPatrick McHardy int err = 0;
944513c2500SPatrick McHardy
945b4ff4f04SJohannes Berg netlink_table_grab();
946b4ff4f04SJohannes Berg
947513c2500SPatrick McHardy groups = nl_table[sk->sk_protocol].groups;
948b4ff4f04SJohannes Berg if (!nl_table[sk->sk_protocol].registered) {
949513c2500SPatrick McHardy err = -ENOENT;
950b4ff4f04SJohannes Berg goto out_unlock;
951b4ff4f04SJohannes Berg }
952513c2500SPatrick McHardy
953b4ff4f04SJohannes Berg if (nlk->ngroups >= groups)
954b4ff4f04SJohannes Berg goto out_unlock;
955513c2500SPatrick McHardy
956b4ff4f04SJohannes Berg new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC);
957b4ff4f04SJohannes Berg if (new_groups == NULL) {
958b4ff4f04SJohannes Berg err = -ENOMEM;
959b4ff4f04SJohannes Berg goto out_unlock;
960b4ff4f04SJohannes Berg }
961b4ff4f04SJohannes Berg memset((char *)new_groups + NLGRPSZ(nlk->ngroups), 0,
962b4ff4f04SJohannes Berg NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups));
963b4ff4f04SJohannes Berg
964b4ff4f04SJohannes Berg nlk->groups = new_groups;
965513c2500SPatrick McHardy nlk->ngroups = groups;
966b4ff4f04SJohannes Berg out_unlock:
967b4ff4f04SJohannes Berg netlink_table_ungrab();
968b4ff4f04SJohannes Berg return err;
969513c2500SPatrick McHardy }
970513c2500SPatrick McHardy
netlink_undo_bind(int group,long unsigned int groups,struct sock * sk)97102c81ab9SJohannes Berg static void netlink_undo_bind(int group, long unsigned int groups,
972023e2cfaSJohannes Berg struct sock *sk)
9734f520900SRichard Guy Briggs {
974023e2cfaSJohannes Berg struct netlink_sock *nlk = nlk_sk(sk);
9754f520900SRichard Guy Briggs int undo;
9764f520900SRichard Guy Briggs
9774f520900SRichard Guy Briggs if (!nlk->netlink_unbind)
9784f520900SRichard Guy Briggs return;
9794f520900SRichard Guy Briggs
9804f520900SRichard Guy Briggs for (undo = 0; undo < group; undo++)
9816251edd9SHiroaki SHIMODA if (test_bit(undo, &groups))
9828b7c36d8SPablo Neira nlk->netlink_unbind(sock_net(sk), undo + 1);
9834f520900SRichard Guy Briggs }
9844f520900SRichard Guy Briggs
netlink_bind(struct socket * sock,struct sockaddr * addr,int addr_len)9856ac552fdSPatrick McHardy static int netlink_bind(struct socket *sock, struct sockaddr *addr,
9866ac552fdSPatrick McHardy int addr_len)
9871da177e4SLinus Torvalds {
9881da177e4SLinus Torvalds struct sock *sk = sock->sk;
9893b1e0a65SYOSHIFUJI Hideaki struct net *net = sock_net(sk);
9901da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(sk);
9911da177e4SLinus Torvalds struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
992f7736080SXin Long int err = 0;
993d852be84STetsuo Handa unsigned long groups;
994da314c99SHerbert Xu bool bound;
9951da177e4SLinus Torvalds
9964e4b5376SHannes Frederic Sowa if (addr_len < sizeof(struct sockaddr_nl))
9974e4b5376SHannes Frederic Sowa return -EINVAL;
9984e4b5376SHannes Frederic Sowa
9991da177e4SLinus Torvalds if (nladdr->nl_family != AF_NETLINK)
10001da177e4SLinus Torvalds return -EINVAL;
1001d852be84STetsuo Handa groups = nladdr->nl_groups;
10021da177e4SLinus Torvalds
10031da177e4SLinus Torvalds /* Only superuser is allowed to listen multicasts */
10044f520900SRichard Guy Briggs if (groups) {
10055187cd05SEric W. Biederman if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
10061da177e4SLinus Torvalds return -EPERM;
1007b4ff4f04SJohannes Berg err = netlink_realloc_groups(sk);
1008513c2500SPatrick McHardy if (err)
1009513c2500SPatrick McHardy return err;
1010513c2500SPatrick McHardy }
10111da177e4SLinus Torvalds
1012428f944bSDmitry Safonov if (nlk->ngroups < BITS_PER_LONG)
101391874ecfSDmitry Safonov groups &= (1UL << nlk->ngroups) - 1;
10141da177e4SLinus Torvalds
10157707a4d0SEric Dumazet /* Paired with WRITE_ONCE() in netlink_insert() */
10167707a4d0SEric Dumazet bound = READ_ONCE(nlk->bound);
1017da314c99SHerbert Xu if (bound) {
1018da314c99SHerbert Xu /* Ensure nlk->portid is up-to-date. */
1019da314c99SHerbert Xu smp_rmb();
1020da314c99SHerbert Xu
102115e47304SEric W. Biederman if (nladdr->nl_pid != nlk->portid)
10221da177e4SLinus Torvalds return -EINVAL;
1023da314c99SHerbert Xu }
10244f520900SRichard Guy Briggs
10254f520900SRichard Guy Briggs if (nlk->netlink_bind && groups) {
10264f520900SRichard Guy Briggs int group;
10274f520900SRichard Guy Briggs
10283a20773bSNikolay Aleksandrov /* nl_groups is a u32, so cap the maximum groups we can bind */
10293a20773bSNikolay Aleksandrov for (group = 0; group < BITS_PER_TYPE(u32); group++) {
10304f520900SRichard Guy Briggs if (!test_bit(group, &groups))
10314f520900SRichard Guy Briggs continue;
10328b7c36d8SPablo Neira err = nlk->netlink_bind(net, group + 1);
10334f520900SRichard Guy Briggs if (!err)
10344f520900SRichard Guy Briggs continue;
1035023e2cfaSJohannes Berg netlink_undo_bind(group, groups, sk);
1036f2764bd4SFlorian Westphal return err;
10374f520900SRichard Guy Briggs }
10384f520900SRichard Guy Briggs }
10394f520900SRichard Guy Briggs
1040da314c99SHerbert Xu /* No need for barriers here as we return to user-space without
1041da314c99SHerbert Xu * using any of the bound attributes.
1042da314c99SHerbert Xu */
1043f2764bd4SFlorian Westphal netlink_lock_table();
1044da314c99SHerbert Xu if (!bound) {
10451da177e4SLinus Torvalds err = nladdr->nl_pid ?
10468ea65f4aSHerbert Xu netlink_insert(sk, nladdr->nl_pid) :
10471da177e4SLinus Torvalds netlink_autobind(sock);
10484f520900SRichard Guy Briggs if (err) {
10493a20773bSNikolay Aleksandrov netlink_undo_bind(BITS_PER_TYPE(u32), groups, sk);
1050f7736080SXin Long goto unlock;
10511da177e4SLinus Torvalds }
10524f520900SRichard Guy Briggs }
10531da177e4SLinus Torvalds
10544f520900SRichard Guy Briggs if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0]))
1055f7736080SXin Long goto unlock;
1056f7736080SXin Long netlink_unlock_table();
10571da177e4SLinus Torvalds
10581da177e4SLinus Torvalds netlink_table_grab();
1059f7fa9b10SPatrick McHardy netlink_update_subscriptions(sk, nlk->subscriptions +
10604f520900SRichard Guy Briggs hweight32(groups) -
1061f7fa9b10SPatrick McHardy hweight32(nlk->groups[0]));
10624f520900SRichard Guy Briggs nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | groups;
10634277a083SPatrick McHardy netlink_update_listeners(sk);
10641da177e4SLinus Torvalds netlink_table_ungrab();
10651da177e4SLinus Torvalds
10661da177e4SLinus Torvalds return 0;
1067f7736080SXin Long
1068f7736080SXin Long unlock:
1069f7736080SXin Long netlink_unlock_table();
1070f7736080SXin Long return err;
10711da177e4SLinus Torvalds }
10721da177e4SLinus Torvalds
netlink_connect(struct socket * sock,struct sockaddr * addr,int alen,int flags)10731da177e4SLinus Torvalds static int netlink_connect(struct socket *sock, struct sockaddr *addr,
10741da177e4SLinus Torvalds int alen, int flags)
10751da177e4SLinus Torvalds {
10761da177e4SLinus Torvalds int err = 0;
10771da177e4SLinus Torvalds struct sock *sk = sock->sk;
10781da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(sk);
10791da177e4SLinus Torvalds struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr;
10801da177e4SLinus Torvalds
10816503d961SChangli Gao if (alen < sizeof(addr->sa_family))
10826503d961SChangli Gao return -EINVAL;
10836503d961SChangli Gao
10841da177e4SLinus Torvalds if (addr->sa_family == AF_UNSPEC) {
10859b663b5cSEric Dumazet /* paired with READ_ONCE() in netlink_getsockbyportid() */
10869b663b5cSEric Dumazet WRITE_ONCE(sk->sk_state, NETLINK_UNCONNECTED);
1087004db64dSEric Dumazet /* dst_portid and dst_group can be read locklessly */
1088004db64dSEric Dumazet WRITE_ONCE(nlk->dst_portid, 0);
1089004db64dSEric Dumazet WRITE_ONCE(nlk->dst_group, 0);
10901da177e4SLinus Torvalds return 0;
10911da177e4SLinus Torvalds }
10921da177e4SLinus Torvalds if (addr->sa_family != AF_NETLINK)
10931da177e4SLinus Torvalds return -EINVAL;
10941da177e4SLinus Torvalds
109578802879SAlexander Potapenko if (alen < sizeof(struct sockaddr_nl))
109678802879SAlexander Potapenko return -EINVAL;
109778802879SAlexander Potapenko
109846833a86SMike Pecovnik if ((nladdr->nl_groups || nladdr->nl_pid) &&
10995187cd05SEric W. Biederman !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
11001da177e4SLinus Torvalds return -EPERM;
11011da177e4SLinus Torvalds
1102da314c99SHerbert Xu /* No need for barriers here as we return to user-space without
1103da314c99SHerbert Xu * using any of the bound attributes.
11047707a4d0SEric Dumazet * Paired with WRITE_ONCE() in netlink_insert().
1105da314c99SHerbert Xu */
11067707a4d0SEric Dumazet if (!READ_ONCE(nlk->bound))
11071da177e4SLinus Torvalds err = netlink_autobind(sock);
11081da177e4SLinus Torvalds
11091da177e4SLinus Torvalds if (err == 0) {
11109b663b5cSEric Dumazet /* paired with READ_ONCE() in netlink_getsockbyportid() */
11119b663b5cSEric Dumazet WRITE_ONCE(sk->sk_state, NETLINK_CONNECTED);
1112004db64dSEric Dumazet /* dst_portid and dst_group can be read locklessly */
1113004db64dSEric Dumazet WRITE_ONCE(nlk->dst_portid, nladdr->nl_pid);
1114004db64dSEric Dumazet WRITE_ONCE(nlk->dst_group, ffs(nladdr->nl_groups));
11151da177e4SLinus Torvalds }
11161da177e4SLinus Torvalds
11171da177e4SLinus Torvalds return err;
11181da177e4SLinus Torvalds }
11191da177e4SLinus Torvalds
netlink_getname(struct socket * sock,struct sockaddr * addr,int peer)11206ac552fdSPatrick McHardy static int netlink_getname(struct socket *sock, struct sockaddr *addr,
11219b2c45d4SDenys Vlasenko int peer)
11221da177e4SLinus Torvalds {
11231da177e4SLinus Torvalds struct sock *sk = sock->sk;
11241da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(sk);
112513cfa97bSCyrill Gorcunov DECLARE_SOCKADDR(struct sockaddr_nl *, nladdr, addr);
11261da177e4SLinus Torvalds
11271da177e4SLinus Torvalds nladdr->nl_family = AF_NETLINK;
11281da177e4SLinus Torvalds nladdr->nl_pad = 0;
11291da177e4SLinus Torvalds
11301da177e4SLinus Torvalds if (peer) {
1131004db64dSEric Dumazet /* Paired with WRITE_ONCE() in netlink_connect() */
1132004db64dSEric Dumazet nladdr->nl_pid = READ_ONCE(nlk->dst_portid);
1133004db64dSEric Dumazet nladdr->nl_groups = netlink_group_mask(READ_ONCE(nlk->dst_group));
11341da177e4SLinus Torvalds } else {
1135c1bb9484SEric Dumazet /* Paired with WRITE_ONCE() in netlink_insert() */
1136c1bb9484SEric Dumazet nladdr->nl_pid = READ_ONCE(nlk->portid);
1137f7736080SXin Long netlink_lock_table();
1138513c2500SPatrick McHardy nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0;
1139f7736080SXin Long netlink_unlock_table();
11401da177e4SLinus Torvalds }
11419b2c45d4SDenys Vlasenko return sizeof(*nladdr);
11421da177e4SLinus Torvalds }
11431da177e4SLinus Torvalds
netlink_ioctl(struct socket * sock,unsigned int cmd,unsigned long arg)1144025c6818SDavid Decotigny static int netlink_ioctl(struct socket *sock, unsigned int cmd,
1145025c6818SDavid Decotigny unsigned long arg)
1146025c6818SDavid Decotigny {
1147025c6818SDavid Decotigny /* try to hand this ioctl down to the NIC drivers.
1148025c6818SDavid Decotigny */
1149025c6818SDavid Decotigny return -ENOIOCTLCMD;
1150025c6818SDavid Decotigny }
1151025c6818SDavid Decotigny
netlink_getsockbyportid(struct sock * ssk,u32 portid)115215e47304SEric W. Biederman static struct sock *netlink_getsockbyportid(struct sock *ssk, u32 portid)
11531da177e4SLinus Torvalds {
11541da177e4SLinus Torvalds struct sock *sock;
11551da177e4SLinus Torvalds struct netlink_sock *nlk;
11561da177e4SLinus Torvalds
115715e47304SEric W. Biederman sock = netlink_lookup(sock_net(ssk), ssk->sk_protocol, portid);
11581da177e4SLinus Torvalds if (!sock)
11591da177e4SLinus Torvalds return ERR_PTR(-ECONNREFUSED);
11601da177e4SLinus Torvalds
11611da177e4SLinus Torvalds /* Don't bother queuing skb if kernel socket has no input function */
11621da177e4SLinus Torvalds nlk = nlk_sk(sock);
11639b663b5cSEric Dumazet /* dst_portid and sk_state can be changed in netlink_connect() */
11649b663b5cSEric Dumazet if (READ_ONCE(sock->sk_state) == NETLINK_CONNECTED &&
1165004db64dSEric Dumazet READ_ONCE(nlk->dst_portid) != nlk_sk(ssk)->portid) {
11661da177e4SLinus Torvalds sock_put(sock);
11671da177e4SLinus Torvalds return ERR_PTR(-ECONNREFUSED);
11681da177e4SLinus Torvalds }
11691da177e4SLinus Torvalds return sock;
11701da177e4SLinus Torvalds }
11711da177e4SLinus Torvalds
netlink_getsockbyfilp(struct file * filp)11721da177e4SLinus Torvalds struct sock *netlink_getsockbyfilp(struct file *filp)
11731da177e4SLinus Torvalds {
1174496ad9aaSAl Viro struct inode *inode = file_inode(filp);
11751da177e4SLinus Torvalds struct sock *sock;
11761da177e4SLinus Torvalds
11771da177e4SLinus Torvalds if (!S_ISSOCK(inode->i_mode))
11781da177e4SLinus Torvalds return ERR_PTR(-ENOTSOCK);
11791da177e4SLinus Torvalds
11801da177e4SLinus Torvalds sock = SOCKET_I(inode)->sk;
11811da177e4SLinus Torvalds if (sock->sk_family != AF_NETLINK)
11821da177e4SLinus Torvalds return ERR_PTR(-EINVAL);
11831da177e4SLinus Torvalds
11841da177e4SLinus Torvalds sock_hold(sock);
11851da177e4SLinus Torvalds return sock;
11861da177e4SLinus Torvalds }
11871da177e4SLinus Torvalds
netlink_alloc_large_skb(unsigned int size,int broadcast)11883a36515fSPablo Neira static struct sk_buff *netlink_alloc_large_skb(unsigned int size,
11893a36515fSPablo Neira int broadcast)
1190c05cdb1bSPablo Neira Ayuso {
1191c05cdb1bSPablo Neira Ayuso struct sk_buff *skb;
1192c05cdb1bSPablo Neira Ayuso void *data;
1193c05cdb1bSPablo Neira Ayuso
11943a36515fSPablo Neira if (size <= NLMSG_GOODSIZE || broadcast)
1195c05cdb1bSPablo Neira Ayuso return alloc_skb(size, GFP_KERNEL);
1196c05cdb1bSPablo Neira Ayuso
11973a36515fSPablo Neira size = SKB_DATA_ALIGN(size) +
11983a36515fSPablo Neira SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
1199c05cdb1bSPablo Neira Ayuso
1200c05cdb1bSPablo Neira Ayuso data = vmalloc(size);
1201c05cdb1bSPablo Neira Ayuso if (data == NULL)
12023a36515fSPablo Neira return NULL;
1203c05cdb1bSPablo Neira Ayuso
12042ea2f62cSEric Dumazet skb = __build_skb(data, size);
12053a36515fSPablo Neira if (skb == NULL)
12063a36515fSPablo Neira vfree(data);
12072ea2f62cSEric Dumazet else
1208c05cdb1bSPablo Neira Ayuso skb->destructor = netlink_skb_destructor;
1209c05cdb1bSPablo Neira Ayuso
1210c05cdb1bSPablo Neira Ayuso return skb;
1211c05cdb1bSPablo Neira Ayuso }
1212c05cdb1bSPablo Neira Ayuso
12131da177e4SLinus Torvalds /*
12141da177e4SLinus Torvalds * Attach a skb to a netlink socket.
12151da177e4SLinus Torvalds * The caller must hold a reference to the destination socket. On error, the
12161da177e4SLinus Torvalds * reference is dropped. The skb is not send to the destination, just all
12171da177e4SLinus Torvalds * all error checks are performed and memory in the queue is reserved.
12181da177e4SLinus Torvalds * Return values:
12191da177e4SLinus Torvalds * < 0: error. skb freed, reference to sock dropped.
12201da177e4SLinus Torvalds * 0: continue
12211da177e4SLinus Torvalds * 1: repeat lookup - reference dropped while waiting for socket memory.
12221da177e4SLinus Torvalds */
netlink_attachskb(struct sock * sk,struct sk_buff * skb,long * timeo,struct sock * ssk)12239457afeeSDenis V. Lunev int netlink_attachskb(struct sock *sk, struct sk_buff *skb,
1224c3d8d1e3SPatrick McHardy long *timeo, struct sock *ssk)
12251da177e4SLinus Torvalds {
12261da177e4SLinus Torvalds struct netlink_sock *nlk;
12271da177e4SLinus Torvalds
12281da177e4SLinus Torvalds nlk = nlk_sk(sk);
12291da177e4SLinus Torvalds
12305fd96123SPatrick McHardy if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
1231d1b4c689SFlorian Westphal test_bit(NETLINK_S_CONGESTED, &nlk->state))) {
12321da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current);
1233c3d8d1e3SPatrick McHardy if (!*timeo) {
1234aed81560SDenis V. Lunev if (!ssk || netlink_is_kernel(ssk))
12351da177e4SLinus Torvalds netlink_overrun(sk);
12361da177e4SLinus Torvalds sock_put(sk);
12371da177e4SLinus Torvalds kfree_skb(skb);
12381da177e4SLinus Torvalds return -EAGAIN;
12391da177e4SLinus Torvalds }
12401da177e4SLinus Torvalds
12411da177e4SLinus Torvalds __set_current_state(TASK_INTERRUPTIBLE);
12421da177e4SLinus Torvalds add_wait_queue(&nlk->wait, &wait);
12431da177e4SLinus Torvalds
12441da177e4SLinus Torvalds if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf ||
1245cc3a572fSNicolas Dichtel test_bit(NETLINK_S_CONGESTED, &nlk->state)) &&
12461da177e4SLinus Torvalds !sock_flag(sk, SOCK_DEAD))
1247c3d8d1e3SPatrick McHardy *timeo = schedule_timeout(*timeo);
12481da177e4SLinus Torvalds
12491da177e4SLinus Torvalds __set_current_state(TASK_RUNNING);
12501da177e4SLinus Torvalds remove_wait_queue(&nlk->wait, &wait);
12511da177e4SLinus Torvalds sock_put(sk);
12521da177e4SLinus Torvalds
12531da177e4SLinus Torvalds if (signal_pending(current)) {
12541da177e4SLinus Torvalds kfree_skb(skb);
1255c3d8d1e3SPatrick McHardy return sock_intr_errno(*timeo);
12561da177e4SLinus Torvalds }
12571da177e4SLinus Torvalds return 1;
12581da177e4SLinus Torvalds }
1259cf0a018aSPatrick McHardy netlink_skb_set_owner_r(skb, sk);
12601da177e4SLinus Torvalds return 0;
12611da177e4SLinus Torvalds }
12621da177e4SLinus Torvalds
__netlink_sendskb(struct sock * sk,struct sk_buff * skb)12634a7e7c2aSEric Dumazet static int __netlink_sendskb(struct sock *sk, struct sk_buff *skb)
12641da177e4SLinus Torvalds {
12651da177e4SLinus Torvalds int len = skb->len;
12661da177e4SLinus Torvalds
126725e3f70fSCong Wang netlink_deliver_tap(sock_net(sk), skb);
1268bcbde0d4SDaniel Borkmann
12691da177e4SLinus Torvalds skb_queue_tail(&sk->sk_receive_queue, skb);
1270676d2369SDavid S. Miller sk->sk_data_ready(sk);
12714a7e7c2aSEric Dumazet return len;
12724a7e7c2aSEric Dumazet }
12734a7e7c2aSEric Dumazet
netlink_sendskb(struct sock * sk,struct sk_buff * skb)12744a7e7c2aSEric Dumazet int netlink_sendskb(struct sock *sk, struct sk_buff *skb)
12754a7e7c2aSEric Dumazet {
12764a7e7c2aSEric Dumazet int len = __netlink_sendskb(sk, skb);
12774a7e7c2aSEric Dumazet
12781da177e4SLinus Torvalds sock_put(sk);
12791da177e4SLinus Torvalds return len;
12801da177e4SLinus Torvalds }
12811da177e4SLinus Torvalds
netlink_detachskb(struct sock * sk,struct sk_buff * skb)12821da177e4SLinus Torvalds void netlink_detachskb(struct sock *sk, struct sk_buff *skb)
12831da177e4SLinus Torvalds {
12841da177e4SLinus Torvalds kfree_skb(skb);
12851da177e4SLinus Torvalds sock_put(sk);
12861da177e4SLinus Torvalds }
12871da177e4SLinus Torvalds
netlink_trim(struct sk_buff * skb,gfp_t allocation)1288b57ef81fSstephen hemminger static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
12891da177e4SLinus Torvalds {
12901da177e4SLinus Torvalds int delta;
12911da177e4SLinus Torvalds
12921298ca46SPatrick McHardy WARN_ON(skb->sk != NULL);
12934305b541SArnaldo Carvalho de Melo delta = skb->end - skb->tail;
1294c05cdb1bSPablo Neira Ayuso if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize)
12951da177e4SLinus Torvalds return skb;
12961da177e4SLinus Torvalds
12971da177e4SLinus Torvalds if (skb_shared(skb)) {
12981da177e4SLinus Torvalds struct sk_buff *nskb = skb_clone(skb, allocation);
12991da177e4SLinus Torvalds if (!nskb)
13001da177e4SLinus Torvalds return skb;
13018460c00fSEric Dumazet consume_skb(skb);
13021da177e4SLinus Torvalds skb = nskb;
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds
1305158f323bSEric Dumazet pskb_expand_head(skb, 0, -delta,
1306e89df813SEric Dumazet (allocation & ~__GFP_DIRECT_RECLAIM) |
1307158f323bSEric Dumazet __GFP_NOWARN | __GFP_NORETRY);
13081da177e4SLinus Torvalds return skb;
13091da177e4SLinus Torvalds }
13101da177e4SLinus Torvalds
netlink_unicast_kernel(struct sock * sk,struct sk_buff * skb,struct sock * ssk)13113fbc2905SEric W. Biederman static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb,
13123fbc2905SEric W. Biederman struct sock *ssk)
1313cd40b7d3SDenis V. Lunev {
1314cd40b7d3SDenis V. Lunev int ret;
1315cd40b7d3SDenis V. Lunev struct netlink_sock *nlk = nlk_sk(sk);
1316cd40b7d3SDenis V. Lunev
1317cd40b7d3SDenis V. Lunev ret = -ECONNREFUSED;
1318cd40b7d3SDenis V. Lunev if (nlk->netlink_rcv != NULL) {
1319cd40b7d3SDenis V. Lunev ret = skb->len;
1320cf0a018aSPatrick McHardy netlink_skb_set_owner_r(skb, sk);
1321e32123e5SPatrick McHardy NETLINK_CB(skb).sk = ssk;
132273bfd370SDaniel Borkmann netlink_deliver_tap_kernel(sk, ssk, skb);
1323cd40b7d3SDenis V. Lunev nlk->netlink_rcv(skb);
1324bfb253c9SEric Dumazet consume_skb(skb);
1325bfb253c9SEric Dumazet } else {
1326cd40b7d3SDenis V. Lunev kfree_skb(skb);
1327bfb253c9SEric Dumazet }
1328cd40b7d3SDenis V. Lunev sock_put(sk);
1329cd40b7d3SDenis V. Lunev return ret;
1330cd40b7d3SDenis V. Lunev }
1331cd40b7d3SDenis V. Lunev
netlink_unicast(struct sock * ssk,struct sk_buff * skb,u32 portid,int nonblock)1332cd40b7d3SDenis V. Lunev int netlink_unicast(struct sock *ssk, struct sk_buff *skb,
133315e47304SEric W. Biederman u32 portid, int nonblock)
13341da177e4SLinus Torvalds {
13351da177e4SLinus Torvalds struct sock *sk;
13361da177e4SLinus Torvalds int err;
13371da177e4SLinus Torvalds long timeo;
13381da177e4SLinus Torvalds
13391da177e4SLinus Torvalds skb = netlink_trim(skb, gfp_any());
13401da177e4SLinus Torvalds
13411da177e4SLinus Torvalds timeo = sock_sndtimeo(ssk, nonblock);
13421da177e4SLinus Torvalds retry:
134315e47304SEric W. Biederman sk = netlink_getsockbyportid(ssk, portid);
13441da177e4SLinus Torvalds if (IS_ERR(sk)) {
13451da177e4SLinus Torvalds kfree_skb(skb);
13461da177e4SLinus Torvalds return PTR_ERR(sk);
13471da177e4SLinus Torvalds }
1348cd40b7d3SDenis V. Lunev if (netlink_is_kernel(sk))
13493fbc2905SEric W. Biederman return netlink_unicast_kernel(sk, skb, ssk);
1350cd40b7d3SDenis V. Lunev
1351b1153f29SStephen Hemminger if (sk_filter(sk, skb)) {
135284874607SWang Chen err = skb->len;
1353b1153f29SStephen Hemminger kfree_skb(skb);
1354b1153f29SStephen Hemminger sock_put(sk);
1355b1153f29SStephen Hemminger return err;
1356b1153f29SStephen Hemminger }
1357b1153f29SStephen Hemminger
13589457afeeSDenis V. Lunev err = netlink_attachskb(sk, skb, &timeo, ssk);
13591da177e4SLinus Torvalds if (err == 1)
13601da177e4SLinus Torvalds goto retry;
13611da177e4SLinus Torvalds if (err)
13621da177e4SLinus Torvalds return err;
13631da177e4SLinus Torvalds
13647ee015e0SDenis V. Lunev return netlink_sendskb(sk, skb);
13651da177e4SLinus Torvalds }
13666ac552fdSPatrick McHardy EXPORT_SYMBOL(netlink_unicast);
13671da177e4SLinus Torvalds
netlink_has_listeners(struct sock * sk,unsigned int group)13684277a083SPatrick McHardy int netlink_has_listeners(struct sock *sk, unsigned int group)
13694277a083SPatrick McHardy {
13704277a083SPatrick McHardy int res = 0;
13715c398dc8SEric Dumazet struct listeners *listeners;
13724277a083SPatrick McHardy
1373aed81560SDenis V. Lunev BUG_ON(!netlink_is_kernel(sk));
1374b4ff4f04SJohannes Berg
1375b4ff4f04SJohannes Berg rcu_read_lock();
1376b4ff4f04SJohannes Berg listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
1377b4ff4f04SJohannes Berg
13786d772ac5SEric Dumazet if (listeners && group - 1 < nl_table[sk->sk_protocol].groups)
13795c398dc8SEric Dumazet res = test_bit(group - 1, listeners->masks);
1380b4ff4f04SJohannes Berg
1381b4ff4f04SJohannes Berg rcu_read_unlock();
1382b4ff4f04SJohannes Berg
13834277a083SPatrick McHardy return res;
13844277a083SPatrick McHardy }
13854277a083SPatrick McHardy EXPORT_SYMBOL_GPL(netlink_has_listeners);
13864277a083SPatrick McHardy
netlink_strict_get_check(struct sk_buff * skb)138759c28058SJakub Kicinski bool netlink_strict_get_check(struct sk_buff *skb)
138859c28058SJakub Kicinski {
13898fe08d70SEric Dumazet return nlk_test_bit(STRICT_CHK, NETLINK_CB(skb).sk);
139059c28058SJakub Kicinski }
139159c28058SJakub Kicinski EXPORT_SYMBOL_GPL(netlink_strict_get_check);
139259c28058SJakub Kicinski
netlink_broadcast_deliver(struct sock * sk,struct sk_buff * skb)1393b57ef81fSstephen hemminger static int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb)
13941da177e4SLinus Torvalds {
13951da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(sk);
13961da177e4SLinus Torvalds
13971da177e4SLinus Torvalds if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
1398cc3a572fSNicolas Dichtel !test_bit(NETLINK_S_CONGESTED, &nlk->state)) {
1399cf0a018aSPatrick McHardy netlink_skb_set_owner_r(skb, sk);
14004a7e7c2aSEric Dumazet __netlink_sendskb(sk, skb);
14012c645800Sstephen hemminger return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1);
14021da177e4SLinus Torvalds }
14031da177e4SLinus Torvalds return -1;
14041da177e4SLinus Torvalds }
14051da177e4SLinus Torvalds
14061da177e4SLinus Torvalds struct netlink_broadcast_data {
14071da177e4SLinus Torvalds struct sock *exclude_sk;
1408b4b51029SEric W. Biederman struct net *net;
140915e47304SEric W. Biederman u32 portid;
14101da177e4SLinus Torvalds u32 group;
14111da177e4SLinus Torvalds int failure;
1412ff491a73SPablo Neira Ayuso int delivery_failure;
14131da177e4SLinus Torvalds int congested;
14141da177e4SLinus Torvalds int delivered;
14157d877f3bSAl Viro gfp_t allocation;
14161da177e4SLinus Torvalds struct sk_buff *skb, *skb2;
1417a3377386SAnjali Kulkarni int (*tx_filter)(struct sock *dsk, struct sk_buff *skb, void *data);
1418a3377386SAnjali Kulkarni void *tx_data;
14191da177e4SLinus Torvalds };
14201da177e4SLinus Torvalds
do_one_broadcast(struct sock * sk,struct netlink_broadcast_data * p)142146c9521fSRami Rosen static void do_one_broadcast(struct sock *sk,
14221da177e4SLinus Torvalds struct netlink_broadcast_data *p)
14231da177e4SLinus Torvalds {
14241da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(sk);
14251da177e4SLinus Torvalds int val;
14261da177e4SLinus Torvalds
14271da177e4SLinus Torvalds if (p->exclude_sk == sk)
142846c9521fSRami Rosen return;
14291da177e4SLinus Torvalds
143015e47304SEric W. Biederman if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups ||
1431f7fa9b10SPatrick McHardy !test_bit(p->group - 1, nlk->groups))
143246c9521fSRami Rosen return;
14331da177e4SLinus Torvalds
143459324cf3SNicolas Dichtel if (!net_eq(sock_net(sk), p->net)) {
14358fe08d70SEric Dumazet if (!nlk_test_bit(LISTEN_ALL_NSID, sk))
143646c9521fSRami Rosen return;
1437b4b51029SEric W. Biederman
143859324cf3SNicolas Dichtel if (!peernet_has_id(sock_net(sk), p->net))
143959324cf3SNicolas Dichtel return;
144059324cf3SNicolas Dichtel
144159324cf3SNicolas Dichtel if (!file_ns_capable(sk->sk_socket->file, p->net->user_ns,
144259324cf3SNicolas Dichtel CAP_NET_BROADCAST))
144359324cf3SNicolas Dichtel return;
144459324cf3SNicolas Dichtel }
144559324cf3SNicolas Dichtel
14461da177e4SLinus Torvalds if (p->failure) {
14471da177e4SLinus Torvalds netlink_overrun(sk);
144846c9521fSRami Rosen return;
14491da177e4SLinus Torvalds }
14501da177e4SLinus Torvalds
14511da177e4SLinus Torvalds sock_hold(sk);
14521da177e4SLinus Torvalds if (p->skb2 == NULL) {
145368acc024STommy S. Christensen if (skb_shared(p->skb)) {
14541da177e4SLinus Torvalds p->skb2 = skb_clone(p->skb, p->allocation);
14551da177e4SLinus Torvalds } else {
145668acc024STommy S. Christensen p->skb2 = skb_get(p->skb);
145768acc024STommy S. Christensen /*
145868acc024STommy S. Christensen * skb ownership may have been set when
145968acc024STommy S. Christensen * delivered to a previous socket.
146068acc024STommy S. Christensen */
146168acc024STommy S. Christensen skb_orphan(p->skb2);
14621da177e4SLinus Torvalds }
14631da177e4SLinus Torvalds }
14641da177e4SLinus Torvalds if (p->skb2 == NULL) {
14651da177e4SLinus Torvalds netlink_overrun(sk);
14661da177e4SLinus Torvalds /* Clone failed. Notify ALL listeners. */
14671da177e4SLinus Torvalds p->failure = 1;
14688fe08d70SEric Dumazet if (nlk_test_bit(BROADCAST_SEND_ERROR, sk))
1469be0c22a4SPablo Neira Ayuso p->delivery_failure = 1;
147059324cf3SNicolas Dichtel goto out;
147159324cf3SNicolas Dichtel }
1472a3377386SAnjali Kulkarni
1473a3377386SAnjali Kulkarni if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) {
1474a3377386SAnjali Kulkarni kfree_skb(p->skb2);
1475a3377386SAnjali Kulkarni p->skb2 = NULL;
1476a3377386SAnjali Kulkarni goto out;
1477a3377386SAnjali Kulkarni }
1478a3377386SAnjali Kulkarni
147959324cf3SNicolas Dichtel if (sk_filter(sk, p->skb2)) {
1480b1153f29SStephen Hemminger kfree_skb(p->skb2);
1481b1153f29SStephen Hemminger p->skb2 = NULL;
148259324cf3SNicolas Dichtel goto out;
148359324cf3SNicolas Dichtel }
148459324cf3SNicolas Dichtel NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net);
14857212462fSNicolas Dichtel if (NETLINK_CB(p->skb2).nsid != NETNSA_NSID_NOT_ASSIGNED)
148659324cf3SNicolas Dichtel NETLINK_CB(p->skb2).nsid_is_set = true;
148759324cf3SNicolas Dichtel val = netlink_broadcast_deliver(sk, p->skb2);
148859324cf3SNicolas Dichtel if (val < 0) {
14891da177e4SLinus Torvalds netlink_overrun(sk);
14908fe08d70SEric Dumazet if (nlk_test_bit(BROADCAST_SEND_ERROR, sk))
1491ff491a73SPablo Neira Ayuso p->delivery_failure = 1;
14921da177e4SLinus Torvalds } else {
14931da177e4SLinus Torvalds p->congested |= val;
14941da177e4SLinus Torvalds p->delivered = 1;
14951da177e4SLinus Torvalds p->skb2 = NULL;
14961da177e4SLinus Torvalds }
149759324cf3SNicolas Dichtel out:
14981da177e4SLinus Torvalds sock_put(sk);
14991da177e4SLinus Torvalds }
15001da177e4SLinus Torvalds
netlink_broadcast_filtered(struct sock * ssk,struct sk_buff * skb,u32 portid,u32 group,gfp_t allocation,int (* filter)(struct sock * dsk,struct sk_buff * skb,void * data),void * filter_data)1501a3377386SAnjali Kulkarni int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb,
1502a3377386SAnjali Kulkarni u32 portid,
1503a3377386SAnjali Kulkarni u32 group, gfp_t allocation,
1504a3377386SAnjali Kulkarni int (*filter)(struct sock *dsk,
1505a3377386SAnjali Kulkarni struct sk_buff *skb, void *data),
1506a3377386SAnjali Kulkarni void *filter_data)
15071da177e4SLinus Torvalds {
15083b1e0a65SYOSHIFUJI Hideaki struct net *net = sock_net(ssk);
15091da177e4SLinus Torvalds struct netlink_broadcast_data info;
15101da177e4SLinus Torvalds struct sock *sk;
15111da177e4SLinus Torvalds
15121da177e4SLinus Torvalds skb = netlink_trim(skb, allocation);
15131da177e4SLinus Torvalds
15141da177e4SLinus Torvalds info.exclude_sk = ssk;
1515b4b51029SEric W. Biederman info.net = net;
151615e47304SEric W. Biederman info.portid = portid;
15171da177e4SLinus Torvalds info.group = group;
15181da177e4SLinus Torvalds info.failure = 0;
1519ff491a73SPablo Neira Ayuso info.delivery_failure = 0;
15201da177e4SLinus Torvalds info.congested = 0;
15211da177e4SLinus Torvalds info.delivered = 0;
15221da177e4SLinus Torvalds info.allocation = allocation;
15231da177e4SLinus Torvalds info.skb = skb;
15241da177e4SLinus Torvalds info.skb2 = NULL;
1525a3377386SAnjali Kulkarni info.tx_filter = filter;
1526a3377386SAnjali Kulkarni info.tx_data = filter_data;
15271da177e4SLinus Torvalds
15281da177e4SLinus Torvalds /* While we sleep in clone, do not allow to change socket list */
15291da177e4SLinus Torvalds
15301da177e4SLinus Torvalds netlink_lock_table();
15311da177e4SLinus Torvalds
1532b67bfe0dSSasha Levin sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list)
15331da177e4SLinus Torvalds do_one_broadcast(sk, &info);
15341da177e4SLinus Torvalds
153570d4bf6dSNeil Horman consume_skb(skb);
1536aa1c6a6fSTommy S. Christensen
15371da177e4SLinus Torvalds netlink_unlock_table();
15381da177e4SLinus Torvalds
153970d4bf6dSNeil Horman if (info.delivery_failure) {
15401da177e4SLinus Torvalds kfree_skb(info.skb2);
1541ff491a73SPablo Neira Ayuso return -ENOBUFS;
1542658cb354SEric Dumazet }
154370d4bf6dSNeil Horman consume_skb(info.skb2);
1544ff491a73SPablo Neira Ayuso
15451da177e4SLinus Torvalds if (info.delivered) {
1546d0164adcSMel Gorman if (info.congested && gfpflags_allow_blocking(allocation))
15471da177e4SLinus Torvalds yield();
15481da177e4SLinus Torvalds return 0;
15491da177e4SLinus Torvalds }
15501da177e4SLinus Torvalds return -ESRCH;
15511da177e4SLinus Torvalds }
1552a3377386SAnjali Kulkarni EXPORT_SYMBOL(netlink_broadcast_filtered);
1553a3377386SAnjali Kulkarni
netlink_broadcast(struct sock * ssk,struct sk_buff * skb,u32 portid,u32 group,gfp_t allocation)1554a3377386SAnjali Kulkarni int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 portid,
1555a3377386SAnjali Kulkarni u32 group, gfp_t allocation)
1556a3377386SAnjali Kulkarni {
1557a3377386SAnjali Kulkarni return netlink_broadcast_filtered(ssk, skb, portid, group, allocation,
1558a3377386SAnjali Kulkarni NULL, NULL);
1559a3377386SAnjali Kulkarni }
15606ac552fdSPatrick McHardy EXPORT_SYMBOL(netlink_broadcast);
15611da177e4SLinus Torvalds
15621da177e4SLinus Torvalds struct netlink_set_err_data {
15631da177e4SLinus Torvalds struct sock *exclude_sk;
156415e47304SEric W. Biederman u32 portid;
15651da177e4SLinus Torvalds u32 group;
15661da177e4SLinus Torvalds int code;
15671da177e4SLinus Torvalds };
15681da177e4SLinus Torvalds
do_one_set_err(struct sock * sk,struct netlink_set_err_data * p)1569b57ef81fSstephen hemminger static int do_one_set_err(struct sock *sk, struct netlink_set_err_data *p)
15701da177e4SLinus Torvalds {
15711da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(sk);
15721a50307bSPablo Neira Ayuso int ret = 0;
15731da177e4SLinus Torvalds
15741da177e4SLinus Torvalds if (sk == p->exclude_sk)
15751da177e4SLinus Torvalds goto out;
15761da177e4SLinus Torvalds
157709ad9bc7SOctavian Purdila if (!net_eq(sock_net(sk), sock_net(p->exclude_sk)))
1578b4b51029SEric W. Biederman goto out;
1579b4b51029SEric W. Biederman
158015e47304SEric W. Biederman if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups ||
1581f7fa9b10SPatrick McHardy !test_bit(p->group - 1, nlk->groups))
15821da177e4SLinus Torvalds goto out;
15831da177e4SLinus Torvalds
15848fe08d70SEric Dumazet if (p->code == ENOBUFS && nlk_test_bit(RECV_NO_ENOBUFS, sk)) {
15851a50307bSPablo Neira Ayuso ret = 1;
15861a50307bSPablo Neira Ayuso goto out;
15871a50307bSPablo Neira Ayuso }
15881a50307bSPablo Neira Ayuso
1589d0f95894SEric Dumazet WRITE_ONCE(sk->sk_err, p->code);
1590e3ae2365SAlexander Aring sk_error_report(sk);
15911da177e4SLinus Torvalds out:
15921a50307bSPablo Neira Ayuso return ret;
15931da177e4SLinus Torvalds }
15941da177e4SLinus Torvalds
15954843b93cSPablo Neira Ayuso /**
15964843b93cSPablo Neira Ayuso * netlink_set_err - report error to broadcast listeners
15974843b93cSPablo Neira Ayuso * @ssk: the kernel netlink socket, as returned by netlink_kernel_create()
159815e47304SEric W. Biederman * @portid: the PORTID of a process that we want to skip (if any)
1599840e93f2SJohannes Berg * @group: the broadcast group that will notice the error
16004843b93cSPablo Neira Ayuso * @code: error code, must be negative (as usual in kernelspace)
16011a50307bSPablo Neira Ayuso *
16021a50307bSPablo Neira Ayuso * This function returns the number of broadcast listeners that have set the
1603cc3a572fSNicolas Dichtel * NETLINK_NO_ENOBUFS socket option.
16044843b93cSPablo Neira Ayuso */
netlink_set_err(struct sock * ssk,u32 portid,u32 group,int code)160515e47304SEric W. Biederman int netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code)
16061da177e4SLinus Torvalds {
16071da177e4SLinus Torvalds struct netlink_set_err_data info;
16088d61f926SEric Dumazet unsigned long flags;
16091da177e4SLinus Torvalds struct sock *sk;
16101a50307bSPablo Neira Ayuso int ret = 0;
16111da177e4SLinus Torvalds
16121da177e4SLinus Torvalds info.exclude_sk = ssk;
161315e47304SEric W. Biederman info.portid = portid;
16141da177e4SLinus Torvalds info.group = group;
16154843b93cSPablo Neira Ayuso /* sk->sk_err wants a positive error value */
16164843b93cSPablo Neira Ayuso info.code = -code;
16171da177e4SLinus Torvalds
16188d61f926SEric Dumazet read_lock_irqsave(&nl_table_lock, flags);
16191da177e4SLinus Torvalds
1620b67bfe0dSSasha Levin sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list)
16211a50307bSPablo Neira Ayuso ret += do_one_set_err(sk, &info);
16221da177e4SLinus Torvalds
16238d61f926SEric Dumazet read_unlock_irqrestore(&nl_table_lock, flags);
16241a50307bSPablo Neira Ayuso return ret;
16251da177e4SLinus Torvalds }
1626dd5b6ce6SPablo Neira Ayuso EXPORT_SYMBOL(netlink_set_err);
16271da177e4SLinus Torvalds
162884659eb5SJohannes Berg /* must be called with netlink table grabbed */
netlink_update_socket_mc(struct netlink_sock * nlk,unsigned int group,int is_new)162984659eb5SJohannes Berg static void netlink_update_socket_mc(struct netlink_sock *nlk,
163084659eb5SJohannes Berg unsigned int group,
163184659eb5SJohannes Berg int is_new)
163284659eb5SJohannes Berg {
163384659eb5SJohannes Berg int old, new = !!is_new, subscriptions;
163484659eb5SJohannes Berg
163584659eb5SJohannes Berg old = test_bit(group - 1, nlk->groups);
163684659eb5SJohannes Berg subscriptions = nlk->subscriptions - old + new;
1637b8e39b38SAndy Shevchenko __assign_bit(group - 1, nlk->groups, new);
163884659eb5SJohannes Berg netlink_update_subscriptions(&nlk->sk, subscriptions);
163984659eb5SJohannes Berg netlink_update_listeners(&nlk->sk);
164084659eb5SJohannes Berg }
164184659eb5SJohannes Berg
netlink_setsockopt(struct socket * sock,int level,int optname,sockptr_t optval,unsigned int optlen)16429a4595bcSPatrick McHardy static int netlink_setsockopt(struct socket *sock, int level, int optname,
1643a7b75c5aSChristoph Hellwig sockptr_t optval, unsigned int optlen)
16449a4595bcSPatrick McHardy {
16459a4595bcSPatrick McHardy struct sock *sk = sock->sk;
16469a4595bcSPatrick McHardy struct netlink_sock *nlk = nlk_sk(sk);
1647eb496534SJohannes Berg unsigned int val = 0;
16488fe08d70SEric Dumazet int nr = -1;
16499a4595bcSPatrick McHardy
16509a4595bcSPatrick McHardy if (level != SOL_NETLINK)
16519a4595bcSPatrick McHardy return -ENOPROTOOPT;
16529a4595bcSPatrick McHardy
1653d1b4c689SFlorian Westphal if (optlen >= sizeof(int) &&
1654a7b75c5aSChristoph Hellwig copy_from_sockptr(&val, optval, sizeof(val)))
16559a4595bcSPatrick McHardy return -EFAULT;
16569a4595bcSPatrick McHardy
16579a4595bcSPatrick McHardy switch (optname) {
16589a4595bcSPatrick McHardy case NETLINK_PKTINFO:
16598fe08d70SEric Dumazet nr = NETLINK_F_RECV_PKTINFO;
16609a4595bcSPatrick McHardy break;
16619a4595bcSPatrick McHardy case NETLINK_ADD_MEMBERSHIP:
16629a4595bcSPatrick McHardy case NETLINK_DROP_MEMBERSHIP: {
16638fe08d70SEric Dumazet int err;
16648fe08d70SEric Dumazet
16655187cd05SEric W. Biederman if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV))
16669a4595bcSPatrick McHardy return -EPERM;
1667b4ff4f04SJohannes Berg err = netlink_realloc_groups(sk);
1668513c2500SPatrick McHardy if (err)
1669513c2500SPatrick McHardy return err;
16709a4595bcSPatrick McHardy if (!val || val - 1 >= nlk->ngroups)
16719a4595bcSPatrick McHardy return -EINVAL;
16727774d5e0SRichard Guy Briggs if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) {
1673023e2cfaSJohannes Berg err = nlk->netlink_bind(sock_net(sk), val);
16744f520900SRichard Guy Briggs if (err)
16754f520900SRichard Guy Briggs return err;
16764f520900SRichard Guy Briggs }
16779a4595bcSPatrick McHardy netlink_table_grab();
167884659eb5SJohannes Berg netlink_update_socket_mc(nlk, val,
167984659eb5SJohannes Berg optname == NETLINK_ADD_MEMBERSHIP);
16809a4595bcSPatrick McHardy netlink_table_ungrab();
16817774d5e0SRichard Guy Briggs if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind)
1682023e2cfaSJohannes Berg nlk->netlink_unbind(sock_net(sk), val);
168303292745SPablo Neira Ayuso
16849a4595bcSPatrick McHardy break;
16859a4595bcSPatrick McHardy }
1686be0c22a4SPablo Neira Ayuso case NETLINK_BROADCAST_ERROR:
16878fe08d70SEric Dumazet nr = NETLINK_F_BROADCAST_SEND_ERROR;
1688be0c22a4SPablo Neira Ayuso break;
168938938bfeSPablo Neira Ayuso case NETLINK_NO_ENOBUFS:
16908fe08d70SEric Dumazet assign_bit(NETLINK_F_RECV_NO_ENOBUFS, &nlk->flags, val);
169138938bfeSPablo Neira Ayuso if (val) {
1692cc3a572fSNicolas Dichtel clear_bit(NETLINK_S_CONGESTED, &nlk->state);
169338938bfeSPablo Neira Ayuso wake_up_interruptible(&nlk->wait);
1694658cb354SEric Dumazet }
169538938bfeSPablo Neira Ayuso break;
169659324cf3SNicolas Dichtel case NETLINK_LISTEN_ALL_NSID:
169759324cf3SNicolas Dichtel if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_BROADCAST))
169859324cf3SNicolas Dichtel return -EPERM;
16998fe08d70SEric Dumazet nr = NETLINK_F_LISTEN_ALL_NSID;
170059324cf3SNicolas Dichtel break;
17010a6a3a23SChristophe Ricard case NETLINK_CAP_ACK:
17028fe08d70SEric Dumazet nr = NETLINK_F_CAP_ACK;
17030a6a3a23SChristophe Ricard break;
17042d4bc933SJohannes Berg case NETLINK_EXT_ACK:
17058fe08d70SEric Dumazet nr = NETLINK_F_EXT_ACK;
17062d4bc933SJohannes Berg break;
1707d3e8869eSJakub Kicinski case NETLINK_GET_STRICT_CHK:
17088fe08d70SEric Dumazet nr = NETLINK_F_STRICT_CHK;
170989d35528SDavid Ahern break;
17109a4595bcSPatrick McHardy default:
17118fe08d70SEric Dumazet return -ENOPROTOOPT;
17129a4595bcSPatrick McHardy }
17138fe08d70SEric Dumazet if (nr >= 0)
17148fe08d70SEric Dumazet assign_bit(nr, &nlk->flags, val);
17158fe08d70SEric Dumazet return 0;
17169a4595bcSPatrick McHardy }
17179a4595bcSPatrick McHardy
netlink_getsockopt(struct socket * sock,int level,int optname,char __user * optval,int __user * optlen)17189a4595bcSPatrick McHardy static int netlink_getsockopt(struct socket *sock, int level, int optname,
17199a4595bcSPatrick McHardy char __user *optval, int __user *optlen)
17209a4595bcSPatrick McHardy {
17219a4595bcSPatrick McHardy struct sock *sk = sock->sk;
17229a4595bcSPatrick McHardy struct netlink_sock *nlk = nlk_sk(sk);
1723d913d32cSKuniyuki Iwashima unsigned int flag;
1724d913d32cSKuniyuki Iwashima int len, val;
17259a4595bcSPatrick McHardy
17269a4595bcSPatrick McHardy if (level != SOL_NETLINK)
17279a4595bcSPatrick McHardy return -ENOPROTOOPT;
17289a4595bcSPatrick McHardy
17299a4595bcSPatrick McHardy if (get_user(len, optlen))
17309a4595bcSPatrick McHardy return -EFAULT;
17319a4595bcSPatrick McHardy if (len < 0)
17329a4595bcSPatrick McHardy return -EINVAL;
17339a4595bcSPatrick McHardy
17349a4595bcSPatrick McHardy switch (optname) {
17359a4595bcSPatrick McHardy case NETLINK_PKTINFO:
1736d913d32cSKuniyuki Iwashima flag = NETLINK_F_RECV_PKTINFO;
17379a4595bcSPatrick McHardy break;
1738be0c22a4SPablo Neira Ayuso case NETLINK_BROADCAST_ERROR:
1739d913d32cSKuniyuki Iwashima flag = NETLINK_F_BROADCAST_SEND_ERROR;
1740be0c22a4SPablo Neira Ayuso break;
174138938bfeSPablo Neira Ayuso case NETLINK_NO_ENOBUFS:
1742d913d32cSKuniyuki Iwashima flag = NETLINK_F_RECV_NO_ENOBUFS;
174338938bfeSPablo Neira Ayuso break;
1744b42be38bSDavid Herrmann case NETLINK_LIST_MEMBERSHIPS: {
1745d913d32cSKuniyuki Iwashima int pos, idx, shift, err = 0;
1746b42be38bSDavid Herrmann
174747191d65SDavid Herrmann netlink_lock_table();
1748b42be38bSDavid Herrmann for (pos = 0; pos * 8 < nlk->ngroups; pos += sizeof(u32)) {
1749b42be38bSDavid Herrmann if (len - pos < sizeof(u32))
1750b42be38bSDavid Herrmann break;
1751b42be38bSDavid Herrmann
1752b42be38bSDavid Herrmann idx = pos / sizeof(unsigned long);
1753b42be38bSDavid Herrmann shift = (pos % sizeof(unsigned long)) * 8;
1754b42be38bSDavid Herrmann if (put_user((u32)(nlk->groups[idx] >> shift),
1755b42be38bSDavid Herrmann (u32 __user *)(optval + pos))) {
1756b42be38bSDavid Herrmann err = -EFAULT;
1757b42be38bSDavid Herrmann break;
1758b42be38bSDavid Herrmann }
1759b42be38bSDavid Herrmann }
1760f4e45348SPedro Tammela if (put_user(ALIGN(BITS_TO_BYTES(nlk->ngroups), sizeof(u32)), optlen))
1761b42be38bSDavid Herrmann err = -EFAULT;
176247191d65SDavid Herrmann netlink_unlock_table();
1763d913d32cSKuniyuki Iwashima return err;
1764b42be38bSDavid Herrmann }
17650a6a3a23SChristophe Ricard case NETLINK_CAP_ACK:
1766d913d32cSKuniyuki Iwashima flag = NETLINK_F_CAP_ACK;
17670a6a3a23SChristophe Ricard break;
17682d4bc933SJohannes Berg case NETLINK_EXT_ACK:
1769d913d32cSKuniyuki Iwashima flag = NETLINK_F_EXT_ACK;
17702d4bc933SJohannes Berg break;
1771d3e8869eSJakub Kicinski case NETLINK_GET_STRICT_CHK:
1772d913d32cSKuniyuki Iwashima flag = NETLINK_F_STRICT_CHK;
177389d35528SDavid Ahern break;
17749a4595bcSPatrick McHardy default:
1775d913d32cSKuniyuki Iwashima return -ENOPROTOOPT;
17769a4595bcSPatrick McHardy }
1777d913d32cSKuniyuki Iwashima
1778d913d32cSKuniyuki Iwashima if (len < sizeof(int))
1779d913d32cSKuniyuki Iwashima return -EINVAL;
1780d913d32cSKuniyuki Iwashima
1781d913d32cSKuniyuki Iwashima len = sizeof(int);
17828fe08d70SEric Dumazet val = test_bit(flag, &nlk->flags);
1783d913d32cSKuniyuki Iwashima
1784d913d32cSKuniyuki Iwashima if (put_user(len, optlen) ||
1785d913d32cSKuniyuki Iwashima copy_to_user(optval, &val, len))
1786d913d32cSKuniyuki Iwashima return -EFAULT;
1787d913d32cSKuniyuki Iwashima
1788d913d32cSKuniyuki Iwashima return 0;
17899a4595bcSPatrick McHardy }
17909a4595bcSPatrick McHardy
netlink_cmsg_recv_pktinfo(struct msghdr * msg,struct sk_buff * skb)17919a4595bcSPatrick McHardy static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb)
17929a4595bcSPatrick McHardy {
17939a4595bcSPatrick McHardy struct nl_pktinfo info;
17949a4595bcSPatrick McHardy
17959a4595bcSPatrick McHardy info.group = NETLINK_CB(skb).dst_group;
17969a4595bcSPatrick McHardy put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info);
17979a4595bcSPatrick McHardy }
17989a4595bcSPatrick McHardy
netlink_cmsg_listen_all_nsid(struct sock * sk,struct msghdr * msg,struct sk_buff * skb)179959324cf3SNicolas Dichtel static void netlink_cmsg_listen_all_nsid(struct sock *sk, struct msghdr *msg,
180059324cf3SNicolas Dichtel struct sk_buff *skb)
180159324cf3SNicolas Dichtel {
180259324cf3SNicolas Dichtel if (!NETLINK_CB(skb).nsid_is_set)
180359324cf3SNicolas Dichtel return;
180459324cf3SNicolas Dichtel
180559324cf3SNicolas Dichtel put_cmsg(msg, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, sizeof(int),
180659324cf3SNicolas Dichtel &NETLINK_CB(skb).nsid);
180759324cf3SNicolas Dichtel }
180859324cf3SNicolas Dichtel
netlink_sendmsg(struct socket * sock,struct msghdr * msg,size_t len)18091b784140SYing Xue static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
18101da177e4SLinus Torvalds {
18111da177e4SLinus Torvalds struct sock *sk = sock->sk;
18121da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(sk);
1813342dfc30SSteffen Hurrle DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name);
181415e47304SEric W. Biederman u32 dst_portid;
1815d629b836SPatrick McHardy u32 dst_group;
18161da177e4SLinus Torvalds struct sk_buff *skb;
18171da177e4SLinus Torvalds int err;
18181da177e4SLinus Torvalds struct scm_cookie scm;
18192d7a85f4SEric W. Biederman u32 netlink_skb_flags = 0;
18201da177e4SLinus Torvalds
18211da177e4SLinus Torvalds if (msg->msg_flags & MSG_OOB)
18221da177e4SLinus Torvalds return -EOPNOTSUPP;
18231da177e4SLinus Torvalds
1824f123cffdSHarshit Mogalapalli if (len == 0) {
1825f123cffdSHarshit Mogalapalli pr_warn_once("Zero length message leads to an empty skb\n");
1826f123cffdSHarshit Mogalapalli return -ENODATA;
1827f123cffdSHarshit Mogalapalli }
1828f123cffdSHarshit Mogalapalli
18297cc05662SChristoph Hellwig err = scm_send(sock, msg, &scm, true);
18301da177e4SLinus Torvalds if (err < 0)
18311da177e4SLinus Torvalds return err;
18321da177e4SLinus Torvalds
18331da177e4SLinus Torvalds if (msg->msg_namelen) {
1834b47030c7SEric W. Biederman err = -EINVAL;
18356091f09cSEric Dumazet if (msg->msg_namelen < sizeof(struct sockaddr_nl))
18366091f09cSEric Dumazet goto out;
18371da177e4SLinus Torvalds if (addr->nl_family != AF_NETLINK)
1838b47030c7SEric W. Biederman goto out;
183915e47304SEric W. Biederman dst_portid = addr->nl_pid;
1840d629b836SPatrick McHardy dst_group = ffs(addr->nl_groups);
1841b47030c7SEric W. Biederman err = -EPERM;
184215e47304SEric W. Biederman if ((dst_group || dst_portid) &&
18435187cd05SEric W. Biederman !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
1844b47030c7SEric W. Biederman goto out;
18452d7a85f4SEric W. Biederman netlink_skb_flags |= NETLINK_SKB_DST;
18461da177e4SLinus Torvalds } else {
1847004db64dSEric Dumazet /* Paired with WRITE_ONCE() in netlink_connect() */
1848004db64dSEric Dumazet dst_portid = READ_ONCE(nlk->dst_portid);
1849004db64dSEric Dumazet dst_group = READ_ONCE(nlk->dst_group);
18501da177e4SLinus Torvalds }
18511da177e4SLinus Torvalds
18527707a4d0SEric Dumazet /* Paired with WRITE_ONCE() in netlink_insert() */
18537707a4d0SEric Dumazet if (!READ_ONCE(nlk->bound)) {
18541da177e4SLinus Torvalds err = netlink_autobind(sock);
18551da177e4SLinus Torvalds if (err)
18561da177e4SLinus Torvalds goto out;
1857da314c99SHerbert Xu } else {
1858da314c99SHerbert Xu /* Ensure nlk is hashed and visible. */
1859da314c99SHerbert Xu smp_rmb();
18601da177e4SLinus Torvalds }
18611da177e4SLinus Torvalds
18621da177e4SLinus Torvalds err = -EMSGSIZE;
18631da177e4SLinus Torvalds if (len > sk->sk_sndbuf - 32)
18641da177e4SLinus Torvalds goto out;
18651da177e4SLinus Torvalds err = -ENOBUFS;
18663a36515fSPablo Neira skb = netlink_alloc_large_skb(len, dst_group);
18671da177e4SLinus Torvalds if (skb == NULL)
18681da177e4SLinus Torvalds goto out;
18691da177e4SLinus Torvalds
187015e47304SEric W. Biederman NETLINK_CB(skb).portid = nlk->portid;
1871d629b836SPatrick McHardy NETLINK_CB(skb).dst_group = dst_group;
18727cc05662SChristoph Hellwig NETLINK_CB(skb).creds = scm.creds;
18732d7a85f4SEric W. Biederman NETLINK_CB(skb).flags = netlink_skb_flags;
18741da177e4SLinus Torvalds
18751da177e4SLinus Torvalds err = -EFAULT;
18766ce8e9ceSAl Viro if (memcpy_from_msg(skb_put(skb, len), msg, len)) {
18771da177e4SLinus Torvalds kfree_skb(skb);
18781da177e4SLinus Torvalds goto out;
18791da177e4SLinus Torvalds }
18801da177e4SLinus Torvalds
18811da177e4SLinus Torvalds err = security_netlink_send(sk, skb);
18821da177e4SLinus Torvalds if (err) {
18831da177e4SLinus Torvalds kfree_skb(skb);
18841da177e4SLinus Torvalds goto out;
18851da177e4SLinus Torvalds }
18861da177e4SLinus Torvalds
1887d629b836SPatrick McHardy if (dst_group) {
188863354797SReshetova, Elena refcount_inc(&skb->users);
188915e47304SEric W. Biederman netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL);
18901da177e4SLinus Torvalds }
189115e47304SEric W. Biederman err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags & MSG_DONTWAIT);
18921da177e4SLinus Torvalds
18931da177e4SLinus Torvalds out:
18947cc05662SChristoph Hellwig scm_destroy(&scm);
18951da177e4SLinus Torvalds return err;
18961da177e4SLinus Torvalds }
18971da177e4SLinus Torvalds
netlink_recvmsg(struct socket * sock,struct msghdr * msg,size_t len,int flags)18981b784140SYing Xue static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
18991da177e4SLinus Torvalds int flags)
19001da177e4SLinus Torvalds {
19011da177e4SLinus Torvalds struct scm_cookie scm;
19021da177e4SLinus Torvalds struct sock *sk = sock->sk;
19031da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(sk);
1904a1865f2eSEric Dumazet size_t copied, max_recvmsg_len;
190568d6ac6dSJohannes Berg struct sk_buff *skb, *data_skb;
1906b44d211eSAndrey Vagin int err, ret;
19071da177e4SLinus Torvalds
19081da177e4SLinus Torvalds if (flags & MSG_OOB)
19091da177e4SLinus Torvalds return -EOPNOTSUPP;
19101da177e4SLinus Torvalds
19111da177e4SLinus Torvalds copied = 0;
19121da177e4SLinus Torvalds
1913f4b41f06SOliver Hartkopp skb = skb_recv_datagram(sk, flags, &err);
19141da177e4SLinus Torvalds if (skb == NULL)
19151da177e4SLinus Torvalds goto out;
19161da177e4SLinus Torvalds
191768d6ac6dSJohannes Berg data_skb = skb;
191868d6ac6dSJohannes Berg
19191dacc76dSJohannes Berg #ifdef CONFIG_COMPAT_NETLINK_MESSAGES
19201dacc76dSJohannes Berg if (unlikely(skb_shinfo(skb)->frag_list)) {
19211dacc76dSJohannes Berg /*
192268d6ac6dSJohannes Berg * If this skb has a frag_list, then here that means that we
192368d6ac6dSJohannes Berg * will have to use the frag_list skb's data for compat tasks
192468d6ac6dSJohannes Berg * and the regular skb's data for normal (non-compat) tasks.
19251dacc76dSJohannes Berg *
192668d6ac6dSJohannes Berg * If we need to send the compat skb, assign it to the
192768d6ac6dSJohannes Berg * 'data_skb' variable so that it will be used below for data
192868d6ac6dSJohannes Berg * copying. We keep 'skb' for everything else, including
192968d6ac6dSJohannes Berg * freeing both later.
19301dacc76dSJohannes Berg */
193168d6ac6dSJohannes Berg if (flags & MSG_CMSG_COMPAT)
193268d6ac6dSJohannes Berg data_skb = skb_shinfo(skb)->frag_list;
19331dacc76dSJohannes Berg }
19341dacc76dSJohannes Berg #endif
19351dacc76dSJohannes Berg
19369063e21fSEric Dumazet /* Record the max length of recvmsg() calls for future allocations */
1937a1865f2eSEric Dumazet max_recvmsg_len = max(READ_ONCE(nlk->max_recvmsg_len), len);
1938a1865f2eSEric Dumazet max_recvmsg_len = min_t(size_t, max_recvmsg_len,
1939d35c99ffSEric Dumazet SKB_WITH_OVERHEAD(32768));
1940a1865f2eSEric Dumazet WRITE_ONCE(nlk->max_recvmsg_len, max_recvmsg_len);
19419063e21fSEric Dumazet
194268d6ac6dSJohannes Berg copied = data_skb->len;
19431da177e4SLinus Torvalds if (len < copied) {
19441da177e4SLinus Torvalds msg->msg_flags |= MSG_TRUNC;
19451da177e4SLinus Torvalds copied = len;
19461da177e4SLinus Torvalds }
19471da177e4SLinus Torvalds
194851f3d02bSDavid S. Miller err = skb_copy_datagram_msg(data_skb, 0, msg, copied);
19491da177e4SLinus Torvalds
19501da177e4SLinus Torvalds if (msg->msg_name) {
1951342dfc30SSteffen Hurrle DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name);
19521da177e4SLinus Torvalds addr->nl_family = AF_NETLINK;
19531da177e4SLinus Torvalds addr->nl_pad = 0;
195415e47304SEric W. Biederman addr->nl_pid = NETLINK_CB(skb).portid;
1955d629b836SPatrick McHardy addr->nl_groups = netlink_group_mask(NETLINK_CB(skb).dst_group);
19561da177e4SLinus Torvalds msg->msg_namelen = sizeof(*addr);
19571da177e4SLinus Torvalds }
19581da177e4SLinus Torvalds
19598fe08d70SEric Dumazet if (nlk_test_bit(RECV_PKTINFO, sk))
1960cc9a06cdSPatrick McHardy netlink_cmsg_recv_pktinfo(msg, skb);
19618fe08d70SEric Dumazet if (nlk_test_bit(LISTEN_ALL_NSID, sk))
196259324cf3SNicolas Dichtel netlink_cmsg_listen_all_nsid(sk, msg, skb);
1963cc9a06cdSPatrick McHardy
19641da177e4SLinus Torvalds memset(&scm, 0, sizeof(scm));
19657cc05662SChristoph Hellwig scm.creds = *NETLINK_CREDS(skb);
1966188ccb55SPatrick McHardy if (flags & MSG_TRUNC)
196768d6ac6dSJohannes Berg copied = data_skb->len;
1968daa3766eSDavid S. Miller
19691da177e4SLinus Torvalds skb_free_datagram(sk, skb);
19701da177e4SLinus Torvalds
1971a939d149SEric Dumazet if (READ_ONCE(nlk->cb_running) &&
197216b304f3SPravin B Shelar atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) {
19739cf3b89bSEric Dumazet ret = netlink_dump(sk, false);
1974b44d211eSAndrey Vagin if (ret) {
1975d0f95894SEric Dumazet WRITE_ONCE(sk->sk_err, -ret);
1976e3ae2365SAlexander Aring sk_error_report(sk);
1977b44d211eSAndrey Vagin }
1978b44d211eSAndrey Vagin }
19791da177e4SLinus Torvalds
19807cc05662SChristoph Hellwig scm_recv(sock, msg, &scm, flags);
19811da177e4SLinus Torvalds out:
19821da177e4SLinus Torvalds netlink_rcv_wake(sk);
19831da177e4SLinus Torvalds return err ? : copied;
19841da177e4SLinus Torvalds }
19851da177e4SLinus Torvalds
netlink_data_ready(struct sock * sk)1986676d2369SDavid S. Miller static void netlink_data_ready(struct sock *sk)
19871da177e4SLinus Torvalds {
1988cd40b7d3SDenis V. Lunev BUG();
19891da177e4SLinus Torvalds }
19901da177e4SLinus Torvalds
19911da177e4SLinus Torvalds /*
19921da177e4SLinus Torvalds * We export these functions to other modules. They provide a
19931da177e4SLinus Torvalds * complete set of kernel non-blocking support for message
19941da177e4SLinus Torvalds * queueing.
19951da177e4SLinus Torvalds */
19961da177e4SLinus Torvalds
19971da177e4SLinus Torvalds struct sock *
__netlink_kernel_create(struct net * net,int unit,struct module * module,struct netlink_kernel_cfg * cfg)19989f00d977SPablo Neira Ayuso __netlink_kernel_create(struct net *net, int unit, struct module *module,
1999a31f2d17SPablo Neira Ayuso struct netlink_kernel_cfg *cfg)
20001da177e4SLinus Torvalds {
20011da177e4SLinus Torvalds struct socket *sock;
20021da177e4SLinus Torvalds struct sock *sk;
200377247bbbSPatrick McHardy struct netlink_sock *nlk;
20045c398dc8SEric Dumazet struct listeners *listeners = NULL;
2005a31f2d17SPablo Neira Ayuso struct mutex *cb_mutex = cfg ? cfg->cb_mutex : NULL;
2006a31f2d17SPablo Neira Ayuso unsigned int groups;
20071da177e4SLinus Torvalds
2008fab2caf6SAkinobu Mita BUG_ON(!nl_table);
20091da177e4SLinus Torvalds
20101da177e4SLinus Torvalds if (unit < 0 || unit >= MAX_LINKS)
20111da177e4SLinus Torvalds return NULL;
20121da177e4SLinus Torvalds
20131da177e4SLinus Torvalds if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock))
20141da177e4SLinus Torvalds return NULL;
201513d3078eSEric W. Biederman
201613d3078eSEric W. Biederman if (__netlink_create(net, sock, cb_mutex, unit, 1) < 0)
201723fe1866SPavel Emelyanov goto out_sock_release_nosk;
201823fe1866SPavel Emelyanov
201923fe1866SPavel Emelyanov sk = sock->sk;
20204fdb3bb7SHarald Welte
2021a31f2d17SPablo Neira Ayuso if (!cfg || cfg->groups < 32)
20224277a083SPatrick McHardy groups = 32;
2023a31f2d17SPablo Neira Ayuso else
2024a31f2d17SPablo Neira Ayuso groups = cfg->groups;
20254277a083SPatrick McHardy
20265c398dc8SEric Dumazet listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL);
20274277a083SPatrick McHardy if (!listeners)
20284277a083SPatrick McHardy goto out_sock_release;
20294277a083SPatrick McHardy
20301da177e4SLinus Torvalds sk->sk_data_ready = netlink_data_ready;
2031a31f2d17SPablo Neira Ayuso if (cfg && cfg->input)
2032a31f2d17SPablo Neira Ayuso nlk_sk(sk)->netlink_rcv = cfg->input;
20331da177e4SLinus Torvalds
20348ea65f4aSHerbert Xu if (netlink_insert(sk, 0))
203577247bbbSPatrick McHardy goto out_sock_release;
203677247bbbSPatrick McHardy
203777247bbbSPatrick McHardy nlk = nlk_sk(sk);
20388fe08d70SEric Dumazet set_bit(NETLINK_F_KERNEL_SOCKET, &nlk->flags);
203977247bbbSPatrick McHardy
204077247bbbSPatrick McHardy netlink_table_grab();
2041b4b51029SEric W. Biederman if (!nl_table[unit].registered) {
20424277a083SPatrick McHardy nl_table[unit].groups = groups;
20435c398dc8SEric Dumazet rcu_assign_pointer(nl_table[unit].listeners, listeners);
2044af65bdfcSPatrick McHardy nl_table[unit].cb_mutex = cb_mutex;
204577247bbbSPatrick McHardy nl_table[unit].module = module;
20469785e10aSPablo Neira Ayuso if (cfg) {
20479785e10aSPablo Neira Ayuso nl_table[unit].bind = cfg->bind;
20486251edd9SHiroaki SHIMODA nl_table[unit].unbind = cfg->unbind;
2049a4c9a56eSAnjali Kulkarni nl_table[unit].release = cfg->release;
20509785e10aSPablo Neira Ayuso nl_table[unit].flags = cfg->flags;
20519785e10aSPablo Neira Ayuso }
2052ab33a171SPatrick McHardy nl_table[unit].registered = 1;
2053f937f1f4SJesper Juhl } else {
2054f937f1f4SJesper Juhl kfree(listeners);
2055869e58f8SDenis V. Lunev nl_table[unit].registered++;
2056b4b51029SEric W. Biederman }
205777247bbbSPatrick McHardy netlink_table_ungrab();
20584fdb3bb7SHarald Welte return sk;
20594fdb3bb7SHarald Welte
20604fdb3bb7SHarald Welte out_sock_release:
20614277a083SPatrick McHardy kfree(listeners);
20629dfbec1fSDenis V. Lunev netlink_kernel_release(sk);
206323fe1866SPavel Emelyanov return NULL;
206423fe1866SPavel Emelyanov
206523fe1866SPavel Emelyanov out_sock_release_nosk:
20664fdb3bb7SHarald Welte sock_release(sock);
206777247bbbSPatrick McHardy return NULL;
20681da177e4SLinus Torvalds }
20699f00d977SPablo Neira Ayuso EXPORT_SYMBOL(__netlink_kernel_create);
2070b7c6ba6eSDenis V. Lunev
2071b7c6ba6eSDenis V. Lunev void
netlink_kernel_release(struct sock * sk)2072b7c6ba6eSDenis V. Lunev netlink_kernel_release(struct sock *sk)
2073b7c6ba6eSDenis V. Lunev {
207413d3078eSEric W. Biederman if (sk == NULL || sk->sk_socket == NULL)
207513d3078eSEric W. Biederman return;
207613d3078eSEric W. Biederman
207713d3078eSEric W. Biederman sock_release(sk->sk_socket);
2078b7c6ba6eSDenis V. Lunev }
2079b7c6ba6eSDenis V. Lunev EXPORT_SYMBOL(netlink_kernel_release);
2080b7c6ba6eSDenis V. Lunev
__netlink_change_ngroups(struct sock * sk,unsigned int groups)2081d136f1bdSJohannes Berg int __netlink_change_ngroups(struct sock *sk, unsigned int groups)
2082b4ff4f04SJohannes Berg {
20835c398dc8SEric Dumazet struct listeners *new, *old;
2084b4ff4f04SJohannes Berg struct netlink_table *tbl = &nl_table[sk->sk_protocol];
2085b4ff4f04SJohannes Berg
2086b4ff4f04SJohannes Berg if (groups < 32)
2087b4ff4f04SJohannes Berg groups = 32;
2088b4ff4f04SJohannes Berg
2089b4ff4f04SJohannes Berg if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) {
20905c398dc8SEric Dumazet new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC);
20915c398dc8SEric Dumazet if (!new)
2092d136f1bdSJohannes Berg return -ENOMEM;
20936d772ac5SEric Dumazet old = nl_deref_protected(tbl->listeners);
20945c398dc8SEric Dumazet memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
20955c398dc8SEric Dumazet rcu_assign_pointer(tbl->listeners, new);
20965c398dc8SEric Dumazet
209737b6b935SLai Jiangshan kfree_rcu(old, rcu);
2098b4ff4f04SJohannes Berg }
2099b4ff4f04SJohannes Berg tbl->groups = groups;
2100b4ff4f04SJohannes Berg
2101d136f1bdSJohannes Berg return 0;
2102d136f1bdSJohannes Berg }
2103d136f1bdSJohannes Berg
2104d136f1bdSJohannes Berg /**
2105d136f1bdSJohannes Berg * netlink_change_ngroups - change number of multicast groups
2106d136f1bdSJohannes Berg *
2107d136f1bdSJohannes Berg * This changes the number of multicast groups that are available
2108d136f1bdSJohannes Berg * on a certain netlink family. Note that it is not possible to
2109d136f1bdSJohannes Berg * change the number of groups to below 32. Also note that it does
2110d136f1bdSJohannes Berg * not implicitly call netlink_clear_multicast_users() when the
2111d136f1bdSJohannes Berg * number of groups is reduced.
2112d136f1bdSJohannes Berg *
2113d136f1bdSJohannes Berg * @sk: The kernel netlink socket, as returned by netlink_kernel_create().
2114d136f1bdSJohannes Berg * @groups: The new number of groups.
2115d136f1bdSJohannes Berg */
netlink_change_ngroups(struct sock * sk,unsigned int groups)2116d136f1bdSJohannes Berg int netlink_change_ngroups(struct sock *sk, unsigned int groups)
2117d136f1bdSJohannes Berg {
2118d136f1bdSJohannes Berg int err;
2119d136f1bdSJohannes Berg
2120d136f1bdSJohannes Berg netlink_table_grab();
2121d136f1bdSJohannes Berg err = __netlink_change_ngroups(sk, groups);
2122b4ff4f04SJohannes Berg netlink_table_ungrab();
2123d136f1bdSJohannes Berg
2124b4ff4f04SJohannes Berg return err;
2125b4ff4f04SJohannes Berg }
2126b4ff4f04SJohannes Berg
__netlink_clear_multicast_users(struct sock * ksk,unsigned int group)2127b8273570SJohannes Berg void __netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
2128b8273570SJohannes Berg {
2129b8273570SJohannes Berg struct sock *sk;
2130b8273570SJohannes Berg struct netlink_table *tbl = &nl_table[ksk->sk_protocol];
21313be342e0SAnastasia Kovaleva struct hlist_node *tmp;
2132b8273570SJohannes Berg
21333be342e0SAnastasia Kovaleva sk_for_each_bound_safe(sk, tmp, &tbl->mc_list)
2134b8273570SJohannes Berg netlink_update_socket_mc(nlk_sk(sk), group, 0);
2135b8273570SJohannes Berg }
2136b8273570SJohannes Berg
2137a46621a3SDenys Vlasenko struct nlmsghdr *
__nlmsg_put(struct sk_buff * skb,u32 portid,u32 seq,int type,int len,int flags)213815e47304SEric W. Biederman __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags)
2139a46621a3SDenys Vlasenko {
2140a46621a3SDenys Vlasenko struct nlmsghdr *nlh;
2141573ce260SHong zhi guo int size = nlmsg_msg_size(len);
2142a46621a3SDenys Vlasenko
21434df864c1SJohannes Berg nlh = skb_put(skb, NLMSG_ALIGN(size));
2144a46621a3SDenys Vlasenko nlh->nlmsg_type = type;
2145a46621a3SDenys Vlasenko nlh->nlmsg_len = size;
2146a46621a3SDenys Vlasenko nlh->nlmsg_flags = flags;
214715e47304SEric W. Biederman nlh->nlmsg_pid = portid;
2148a46621a3SDenys Vlasenko nlh->nlmsg_seq = seq;
2149a46621a3SDenys Vlasenko if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0)
2150573ce260SHong zhi guo memset(nlmsg_data(nlh) + len, 0, NLMSG_ALIGN(size) - size);
2151a46621a3SDenys Vlasenko return nlh;
2152a46621a3SDenys Vlasenko }
2153a46621a3SDenys Vlasenko EXPORT_SYMBOL(__nlmsg_put);
2154a46621a3SDenys Vlasenko
21551da177e4SLinus Torvalds /*
21561da177e4SLinus Torvalds * It looks a bit ugly.
21571da177e4SLinus Torvalds * It would be better to create kernel thread.
21581da177e4SLinus Torvalds */
21591da177e4SLinus Torvalds
netlink_dump_done(struct netlink_sock * nlk,struct sk_buff * skb,struct netlink_callback * cb,struct netlink_ext_ack * extack)2160e11eb32dSDmitry Safonov static int netlink_dump_done(struct netlink_sock *nlk, struct sk_buff *skb,
2161e11eb32dSDmitry Safonov struct netlink_callback *cb,
2162e11eb32dSDmitry Safonov struct netlink_ext_ack *extack)
2163e11eb32dSDmitry Safonov {
2164e11eb32dSDmitry Safonov struct nlmsghdr *nlh;
2165e11eb32dSDmitry Safonov
2166e11eb32dSDmitry Safonov nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(nlk->dump_done_errno),
2167e11eb32dSDmitry Safonov NLM_F_MULTI | cb->answer_flags);
2168e11eb32dSDmitry Safonov if (WARN_ON(!nlh))
2169e11eb32dSDmitry Safonov return -ENOBUFS;
2170e11eb32dSDmitry Safonov
2171e11eb32dSDmitry Safonov nl_dump_check_consistent(cb, nlh);
2172e11eb32dSDmitry Safonov memcpy(nlmsg_data(nlh), &nlk->dump_done_errno, sizeof(nlk->dump_done_errno));
2173e11eb32dSDmitry Safonov
21748fe08d70SEric Dumazet if (extack->_msg && test_bit(NETLINK_F_EXT_ACK, &nlk->flags)) {
2175e11eb32dSDmitry Safonov nlh->nlmsg_flags |= NLM_F_ACK_TLVS;
2176e11eb32dSDmitry Safonov if (!nla_put_string(skb, NLMSGERR_ATTR_MSG, extack->_msg))
2177e11eb32dSDmitry Safonov nlmsg_end(skb, nlh);
2178e11eb32dSDmitry Safonov }
2179e11eb32dSDmitry Safonov
2180e11eb32dSDmitry Safonov return 0;
2181e11eb32dSDmitry Safonov }
2182e11eb32dSDmitry Safonov
netlink_dump(struct sock * sk,bool lock_taken)21839cf3b89bSEric Dumazet static int netlink_dump(struct sock *sk, bool lock_taken)
21841da177e4SLinus Torvalds {
21851da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(sk);
21864a19edb6SDavid Ahern struct netlink_ext_ack extack = {};
21871da177e4SLinus Torvalds struct netlink_callback *cb;
2188c7ac8679SGreg Rose struct sk_buff *skb = NULL;
2189a1865f2eSEric Dumazet size_t max_recvmsg_len;
219092964c79SHerbert Xu struct module *module;
21910642840bSJason A. Donenfeld int err = -ENOBUFS;
2192db65a3aaSArad, Ronen int alloc_min_size;
2193c7ac8679SGreg Rose int alloc_size;
21941da177e4SLinus Torvalds
21959cf3b89bSEric Dumazet if (!lock_taken)
2196c8c76f15SEric Dumazet mutex_lock(&nlk->nl_cb_mutex);
219716b304f3SPravin B Shelar if (!nlk->cb_running) {
2198bf8b79e4SThomas Graf err = -EINVAL;
2199bf8b79e4SThomas Graf goto errout_skb;
22001da177e4SLinus Torvalds }
22011da177e4SLinus Torvalds
2202d1b4c689SFlorian Westphal if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf)
2203f9c22888SPatrick McHardy goto errout_skb;
22049063e21fSEric Dumazet
22059063e21fSEric Dumazet /* NLMSG_GOODSIZE is small to avoid high order allocations being
22069063e21fSEric Dumazet * required, but it makes sense to _attempt_ a 16K bytes allocation
22079063e21fSEric Dumazet * to reduce number of system calls on dump operations, if user
22089063e21fSEric Dumazet * ever provided a big enough buffer.
22099063e21fSEric Dumazet */
2210db65a3aaSArad, Ronen cb = &nlk->cb;
2211db65a3aaSArad, Ronen alloc_min_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE);
2212db65a3aaSArad, Ronen
2213a1865f2eSEric Dumazet max_recvmsg_len = READ_ONCE(nlk->max_recvmsg_len);
2214a1865f2eSEric Dumazet if (alloc_min_size < max_recvmsg_len) {
2215a1865f2eSEric Dumazet alloc_size = max_recvmsg_len;
2216d35c99ffSEric Dumazet skb = alloc_skb(alloc_size,
2217d35c99ffSEric Dumazet (GFP_KERNEL & ~__GFP_DIRECT_RECLAIM) |
2218c5b0db32SFlorian Westphal __GFP_NOWARN | __GFP_NORETRY);
22199063e21fSEric Dumazet }
2220db65a3aaSArad, Ronen if (!skb) {
2221db65a3aaSArad, Ronen alloc_size = alloc_min_size;
2222c5b0db32SFlorian Westphal skb = alloc_skb(alloc_size, GFP_KERNEL);
2223db65a3aaSArad, Ronen }
2224c7ac8679SGreg Rose if (!skb)
2225c63d6ea3SDan Carpenter goto errout_skb;
2226db65a3aaSArad, Ronen
2227db65a3aaSArad, Ronen /* Trim skb to allocated size. User is expected to provide buffer as
2228db65a3aaSArad, Ronen * large as max(min_dump_alloc, 16KiB (mac_recvmsg_len capped at
2229db65a3aaSArad, Ronen * netlink_recvmsg())). dump will pack as many smaller messages as
2230db65a3aaSArad, Ronen * could fit within the allocated skb. skb is typically allocated
2231db65a3aaSArad, Ronen * with larger space than required (could be as much as near 2x the
2232db65a3aaSArad, Ronen * requested size with align to next power of 2 approach). Allowing
2233db65a3aaSArad, Ronen * dump to use the excess space makes it difficult for a user to have a
2234db65a3aaSArad, Ronen * reasonable static buffer based on the expected largest dump of a
2235db65a3aaSArad, Ronen * single netdev. The outcome is MSG_TRUNC error.
2236db65a3aaSArad, Ronen */
2237db65a3aaSArad, Ronen skb_reserve(skb, skb_tailroom(skb) - alloc_size);
223899c07327SEric Dumazet
223999c07327SEric Dumazet /* Make sure malicious BPF programs can not read unitialized memory
224099c07327SEric Dumazet * from skb->head -> skb->data
224199c07327SEric Dumazet */
224299c07327SEric Dumazet skb_reset_network_header(skb);
224399c07327SEric Dumazet skb_reset_mac_header(skb);
224499c07327SEric Dumazet
2245f9c22888SPatrick McHardy netlink_skb_set_owner_r(skb, sk);
2246c7ac8679SGreg Rose
22474a19edb6SDavid Ahern if (nlk->dump_done_errno > 0) {
2248c8c76f15SEric Dumazet struct mutex *extra_mutex = nlk->dump_cb_mutex;
2249c8c76f15SEric Dumazet
22504a19edb6SDavid Ahern cb->extack = &extack;
2251c8c76f15SEric Dumazet
2252ba5366b8SEric Dumazet if (cb->flags & RTNL_FLAG_DUMP_UNLOCKED)
2253ba5366b8SEric Dumazet extra_mutex = NULL;
2254c8c76f15SEric Dumazet if (extra_mutex)
2255c8c76f15SEric Dumazet mutex_lock(extra_mutex);
22560642840bSJason A. Donenfeld nlk->dump_done_errno = cb->dump(skb, cb);
2257c8c76f15SEric Dumazet if (extra_mutex)
2258c8c76f15SEric Dumazet mutex_unlock(extra_mutex);
2259c8c76f15SEric Dumazet
22604a19edb6SDavid Ahern cb->extack = NULL;
22614a19edb6SDavid Ahern }
22621da177e4SLinus Torvalds
22630642840bSJason A. Donenfeld if (nlk->dump_done_errno > 0 ||
22640642840bSJason A. Donenfeld skb_tailroom(skb) < nlmsg_total_size(sizeof(nlk->dump_done_errno))) {
2265c8c76f15SEric Dumazet mutex_unlock(&nlk->nl_cb_mutex);
2266b1153f29SStephen Hemminger
2267b1153f29SStephen Hemminger if (sk_filter(sk, skb))
2268b1153f29SStephen Hemminger kfree_skb(skb);
22694a7e7c2aSEric Dumazet else
22704a7e7c2aSEric Dumazet __netlink_sendskb(sk, skb);
22711da177e4SLinus Torvalds return 0;
22721da177e4SLinus Torvalds }
22731da177e4SLinus Torvalds
2274e11eb32dSDmitry Safonov if (netlink_dump_done(nlk, skb, cb, &extack))
2275bf8b79e4SThomas Graf goto errout_skb;
2276bf8b79e4SThomas Graf
2277e11eb32dSDmitry Safonov #ifdef CONFIG_COMPAT_NETLINK_MESSAGES
2278e11eb32dSDmitry Safonov /* frag_list skb's data is used for compat tasks
2279e11eb32dSDmitry Safonov * and the regular skb's data for normal (non-compat) tasks.
2280e11eb32dSDmitry Safonov * See netlink_recvmsg().
2281e11eb32dSDmitry Safonov */
2282e11eb32dSDmitry Safonov if (unlikely(skb_shinfo(skb)->frag_list)) {
2283e11eb32dSDmitry Safonov if (netlink_dump_done(nlk, skb_shinfo(skb)->frag_list, cb, &extack))
2284e11eb32dSDmitry Safonov goto errout_skb;
22854a19edb6SDavid Ahern }
2286e11eb32dSDmitry Safonov #endif
22874a19edb6SDavid Ahern
2288b1153f29SStephen Hemminger if (sk_filter(sk, skb))
2289b1153f29SStephen Hemminger kfree_skb(skb);
22904a7e7c2aSEric Dumazet else
22914a7e7c2aSEric Dumazet __netlink_sendskb(sk, skb);
22921da177e4SLinus Torvalds
2293a8f74b22SThomas Graf if (cb->done)
22941da177e4SLinus Torvalds cb->done(cb);
22951da177e4SLinus Torvalds
2296a939d149SEric Dumazet WRITE_ONCE(nlk->cb_running, false);
229792964c79SHerbert Xu module = cb->module;
229892964c79SHerbert Xu skb = cb->skb;
2299c8c76f15SEric Dumazet mutex_unlock(&nlk->nl_cb_mutex);
230092964c79SHerbert Xu module_put(module);
230192964c79SHerbert Xu consume_skb(skb);
23021da177e4SLinus Torvalds return 0;
23031797754eSThomas Graf
2304bf8b79e4SThomas Graf errout_skb:
2305c8c76f15SEric Dumazet mutex_unlock(&nlk->nl_cb_mutex);
2306bf8b79e4SThomas Graf kfree_skb(skb);
2307bf8b79e4SThomas Graf return err;
23081da177e4SLinus Torvalds }
23091da177e4SLinus Torvalds
__netlink_dump_start(struct sock * ssk,struct sk_buff * skb,const struct nlmsghdr * nlh,struct netlink_dump_control * control)23106dc878a8SGao feng int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
23113a6c2b41SPatrick McHardy const struct nlmsghdr *nlh,
231280d326faSPablo Neira Ayuso struct netlink_dump_control *control)
23131da177e4SLinus Torvalds {
23141da177e4SLinus Torvalds struct netlink_callback *cb;
23158fe08d70SEric Dumazet struct netlink_sock *nlk;
23161da177e4SLinus Torvalds struct sock *sk;
2317b44d211eSAndrey Vagin int ret;
23181da177e4SLinus Torvalds
231963354797SReshetova, Elena refcount_inc(&skb->users);
2320f9c22888SPatrick McHardy
232116b304f3SPravin B Shelar sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid);
232216b304f3SPravin B Shelar if (sk == NULL) {
232316b304f3SPravin B Shelar ret = -ECONNREFUSED;
232416b304f3SPravin B Shelar goto error_free;
232516b304f3SPravin B Shelar }
232616b304f3SPravin B Shelar
232716b304f3SPravin B Shelar nlk = nlk_sk(sk);
2328c8c76f15SEric Dumazet mutex_lock(&nlk->nl_cb_mutex);
232916b304f3SPravin B Shelar /* A dump is in progress... */
233016b304f3SPravin B Shelar if (nlk->cb_running) {
233116b304f3SPravin B Shelar ret = -EBUSY;
233216b304f3SPravin B Shelar goto error_unlock;
233316b304f3SPravin B Shelar }
233416b304f3SPravin B Shelar /* add reference of module which cb->dump belongs to */
233516b304f3SPravin B Shelar if (!try_module_get(control->module)) {
233616b304f3SPravin B Shelar ret = -EPROTONOSUPPORT;
233716b304f3SPravin B Shelar goto error_unlock;
233816b304f3SPravin B Shelar }
233916b304f3SPravin B Shelar
234016b304f3SPravin B Shelar cb = &nlk->cb;
234116b304f3SPravin B Shelar memset(cb, 0, sizeof(*cb));
234280d326faSPablo Neira Ayuso cb->dump = control->dump;
234380d326faSPablo Neira Ayuso cb->done = control->done;
23441da177e4SLinus Torvalds cb->nlh = nlh;
23457175c883SPablo Neira Ayuso cb->data = control->data;
23466dc878a8SGao feng cb->module = control->module;
234780d326faSPablo Neira Ayuso cb->min_dump_alloc = control->min_dump_alloc;
2348ba5366b8SEric Dumazet cb->flags = control->flags;
23491da177e4SLinus Torvalds cb->skb = skb;
23501da177e4SLinus Torvalds
23518fe08d70SEric Dumazet cb->strict_check = nlk_test_bit(STRICT_CHK, NETLINK_CB(skb).sk);
235289d35528SDavid Ahern
23533730cf4dSFlorian Westphal if (control->start) {
23545ab8c41cSJakub Kicinski cb->extack = control->extack;
23553730cf4dSFlorian Westphal ret = control->start(cb);
23565ab8c41cSJakub Kicinski cb->extack = NULL;
235741c87425SJason A. Donenfeld if (ret)
2358b87b6194SJason A. Donenfeld goto error_put;
235941c87425SJason A. Donenfeld }
236041c87425SJason A. Donenfeld
2361a939d149SEric Dumazet WRITE_ONCE(nlk->cb_running, true);
23620642840bSJason A. Donenfeld nlk->dump_done_errno = INT_MAX;
23636dc878a8SGao feng
23649cf3b89bSEric Dumazet ret = netlink_dump(sk, true);
2365fef0035cSJason A. Donenfeld
23661da177e4SLinus Torvalds sock_put(sk);
23675c58298cSDenis V. Lunev
2368b44d211eSAndrey Vagin if (ret)
2369b44d211eSAndrey Vagin return ret;
2370b44d211eSAndrey Vagin
23715c58298cSDenis V. Lunev /* We successfully started a dump, by returning -EINTR we
23725c58298cSDenis V. Lunev * signal not to send ACK even if it was requested.
23735c58298cSDenis V. Lunev */
23745c58298cSDenis V. Lunev return -EINTR;
237516b304f3SPravin B Shelar
2376b87b6194SJason A. Donenfeld error_put:
2377b87b6194SJason A. Donenfeld module_put(control->module);
237816b304f3SPravin B Shelar error_unlock:
237916b304f3SPravin B Shelar sock_put(sk);
2380c8c76f15SEric Dumazet mutex_unlock(&nlk->nl_cb_mutex);
238116b304f3SPravin B Shelar error_free:
238216b304f3SPravin B Shelar kfree_skb(skb);
238316b304f3SPravin B Shelar return ret;
23841da177e4SLinus Torvalds }
23856dc878a8SGao feng EXPORT_SYMBOL(__netlink_dump_start);
23861da177e4SLinus Torvalds
23870c95cea2SJakub Kicinski static size_t
netlink_ack_tlv_len(struct netlink_sock * nlk,int err,const struct netlink_ext_ack * extack)23880c95cea2SJakub Kicinski netlink_ack_tlv_len(struct netlink_sock *nlk, int err,
23890c95cea2SJakub Kicinski const struct netlink_ext_ack *extack)
23900c95cea2SJakub Kicinski {
23910c95cea2SJakub Kicinski size_t tlvlen;
23920c95cea2SJakub Kicinski
23938fe08d70SEric Dumazet if (!extack || !test_bit(NETLINK_F_EXT_ACK, &nlk->flags))
23940c95cea2SJakub Kicinski return 0;
23950c95cea2SJakub Kicinski
23960c95cea2SJakub Kicinski tlvlen = 0;
23970c95cea2SJakub Kicinski if (extack->_msg)
23980c95cea2SJakub Kicinski tlvlen += nla_total_size(strlen(extack->_msg) + 1);
23990c95cea2SJakub Kicinski if (extack->cookie_len)
24000c95cea2SJakub Kicinski tlvlen += nla_total_size(extack->cookie_len);
24010c95cea2SJakub Kicinski
24020c95cea2SJakub Kicinski /* Following attributes are only reported as error (not warning) */
24030c95cea2SJakub Kicinski if (!err)
24040c95cea2SJakub Kicinski return tlvlen;
24050c95cea2SJakub Kicinski
24060c95cea2SJakub Kicinski if (extack->bad_attr)
24070c95cea2SJakub Kicinski tlvlen += nla_total_size(sizeof(u32));
24080c95cea2SJakub Kicinski if (extack->policy)
24090c95cea2SJakub Kicinski tlvlen += netlink_policy_dump_attr_size_estimate(extack->policy);
2410690252f1SJakub Kicinski if (extack->miss_type)
2411690252f1SJakub Kicinski tlvlen += nla_total_size(sizeof(u32));
2412690252f1SJakub Kicinski if (extack->miss_nest)
2413690252f1SJakub Kicinski tlvlen += nla_total_size(sizeof(u32));
24140c95cea2SJakub Kicinski
24150c95cea2SJakub Kicinski return tlvlen;
24160c95cea2SJakub Kicinski }
24170c95cea2SJakub Kicinski
24180c95cea2SJakub Kicinski static void
netlink_ack_tlv_fill(struct sk_buff * in_skb,struct sk_buff * skb,struct nlmsghdr * nlh,int err,const struct netlink_ext_ack * extack)24190c95cea2SJakub Kicinski netlink_ack_tlv_fill(struct sk_buff *in_skb, struct sk_buff *skb,
24200c95cea2SJakub Kicinski struct nlmsghdr *nlh, int err,
24210c95cea2SJakub Kicinski const struct netlink_ext_ack *extack)
24220c95cea2SJakub Kicinski {
24230c95cea2SJakub Kicinski if (extack->_msg)
24240c95cea2SJakub Kicinski WARN_ON(nla_put_string(skb, NLMSGERR_ATTR_MSG, extack->_msg));
24250c95cea2SJakub Kicinski if (extack->cookie_len)
24260c95cea2SJakub Kicinski WARN_ON(nla_put(skb, NLMSGERR_ATTR_COOKIE,
24270c95cea2SJakub Kicinski extack->cookie_len, extack->cookie));
24280c95cea2SJakub Kicinski
24290c95cea2SJakub Kicinski if (!err)
24300c95cea2SJakub Kicinski return;
24310c95cea2SJakub Kicinski
24320c95cea2SJakub Kicinski if (extack->bad_attr &&
24330c95cea2SJakub Kicinski !WARN_ON((u8 *)extack->bad_attr < in_skb->data ||
24340c95cea2SJakub Kicinski (u8 *)extack->bad_attr >= in_skb->data + in_skb->len))
24350c95cea2SJakub Kicinski WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_OFFS,
24360c95cea2SJakub Kicinski (u8 *)extack->bad_attr - (u8 *)nlh));
24370c95cea2SJakub Kicinski if (extack->policy)
24380c95cea2SJakub Kicinski netlink_policy_dump_write_attr(skb, extack->policy,
24390c95cea2SJakub Kicinski NLMSGERR_ATTR_POLICY);
2440690252f1SJakub Kicinski if (extack->miss_type)
2441690252f1SJakub Kicinski WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_TYPE,
2442690252f1SJakub Kicinski extack->miss_type));
2443690252f1SJakub Kicinski if (extack->miss_nest &&
2444690252f1SJakub Kicinski !WARN_ON((u8 *)extack->miss_nest < in_skb->data ||
2445690252f1SJakub Kicinski (u8 *)extack->miss_nest > in_skb->data + in_skb->len))
2446690252f1SJakub Kicinski WARN_ON(nla_put_u32(skb, NLMSGERR_ATTR_MISS_NEST,
2447690252f1SJakub Kicinski (u8 *)extack->miss_nest - (u8 *)nlh));
24480c95cea2SJakub Kicinski }
24490c95cea2SJakub Kicinski
netlink_ack(struct sk_buff * in_skb,struct nlmsghdr * nlh,int err,const struct netlink_ext_ack * extack)24502d4bc933SJohannes Berg void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err,
24512d4bc933SJohannes Berg const struct netlink_ext_ack *extack)
24521da177e4SLinus Torvalds {
24531da177e4SLinus Torvalds struct sk_buff *skb;
24541da177e4SLinus Torvalds struct nlmsghdr *rep;
24551da177e4SLinus Torvalds struct nlmsgerr *errmsg;
2456339bf98fSThomas Graf size_t payload = sizeof(*errmsg);
24570a6a3a23SChristophe Ricard struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk);
24582d4bc933SJohannes Berg unsigned int flags = 0;
24590c95cea2SJakub Kicinski size_t tlvlen;
24601da177e4SLinus Torvalds
24610a6a3a23SChristophe Ricard /* Error messages get the original request appened, unless the user
24622d4bc933SJohannes Berg * requests to cap the error message, and get extra error data if
24632d4bc933SJohannes Berg * requested.
24640a6a3a23SChristophe Ricard */
24658fe08d70SEric Dumazet if (err && !test_bit(NETLINK_F_CAP_ACK, &nlk->flags))
2466339bf98fSThomas Graf payload += nlmsg_len(nlh);
24672d4bc933SJohannes Berg else
24682d4bc933SJohannes Berg flags |= NLM_F_CAPPED;
24691da177e4SLinus Torvalds
24700c95cea2SJakub Kicinski tlvlen = netlink_ack_tlv_len(nlk, err, extack);
24712d4bc933SJohannes Berg if (tlvlen)
24722d4bc933SJohannes Berg flags |= NLM_F_ACK_TLVS;
24732d4bc933SJohannes Berg
24742d4bc933SJohannes Berg skb = nlmsg_new(payload + tlvlen, GFP_KERNEL);
2475738136a0SJakub Kicinski if (!skb)
2476e6976148STao Chen goto err_skb;
24771da177e4SLinus Torvalds
2478710d21fdSKees Cook rep = nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq,
2479738136a0SJakub Kicinski NLMSG_ERROR, sizeof(*errmsg), flags);
2480738136a0SJakub Kicinski if (!rep)
2481738136a0SJakub Kicinski goto err_bad_put;
2482bf8b79e4SThomas Graf errmsg = nlmsg_data(rep);
24831da177e4SLinus Torvalds errmsg->error = err;
2484738136a0SJakub Kicinski errmsg->msg = *nlh;
2485738136a0SJakub Kicinski
2486738136a0SJakub Kicinski if (!(flags & NLM_F_CAPPED)) {
2487738136a0SJakub Kicinski if (!nlmsg_append(skb, nlmsg_len(nlh)))
2488738136a0SJakub Kicinski goto err_bad_put;
2489738136a0SJakub Kicinski
2490c73a72f4SJakub Kicinski memcpy(nlmsg_data(&errmsg->msg), nlmsg_data(nlh),
2491738136a0SJakub Kicinski nlmsg_len(nlh));
2492738136a0SJakub Kicinski }
24932d4bc933SJohannes Berg
24940c95cea2SJakub Kicinski if (tlvlen)
24950c95cea2SJakub Kicinski netlink_ack_tlv_fill(in_skb, skb, nlh, err, extack);
24962d4bc933SJohannes Berg
24972d4bc933SJohannes Berg nlmsg_end(skb, rep);
24982d4bc933SJohannes Berg
249901757f53SYajun Deng nlmsg_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid);
2500738136a0SJakub Kicinski
2501738136a0SJakub Kicinski return;
2502738136a0SJakub Kicinski
2503738136a0SJakub Kicinski err_bad_put:
2504e6976148STao Chen nlmsg_free(skb);
2505e6976148STao Chen err_skb:
2506d0f95894SEric Dumazet WRITE_ONCE(NETLINK_CB(in_skb).sk->sk_err, ENOBUFS);
2507738136a0SJakub Kicinski sk_error_report(NETLINK_CB(in_skb).sk);
25081da177e4SLinus Torvalds }
25096ac552fdSPatrick McHardy EXPORT_SYMBOL(netlink_ack);
25101da177e4SLinus Torvalds
netlink_rcv_skb(struct sk_buff * skb,int (* cb)(struct sk_buff *,struct nlmsghdr *,struct netlink_ext_ack *))2511cd40b7d3SDenis V. Lunev int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *,
25122d4bc933SJohannes Berg struct nlmsghdr *,
25132d4bc933SJohannes Berg struct netlink_ext_ack *))
251482ace47aSThomas Graf {
2515cbbdf843SDavid Ahern struct netlink_ext_ack extack;
251682ace47aSThomas Graf struct nlmsghdr *nlh;
251782ace47aSThomas Graf int err;
251882ace47aSThomas Graf
251982ace47aSThomas Graf while (skb->len >= nlmsg_total_size(0)) {
2520cd40b7d3SDenis V. Lunev int msglen;
2521cd40b7d3SDenis V. Lunev
2522cd443f1eSXin Long memset(&extack, 0, sizeof(extack));
2523b529ccf2SArnaldo Carvalho de Melo nlh = nlmsg_hdr(skb);
2524d35b6856SThomas Graf err = 0;
252582ace47aSThomas Graf
2526ad8e4b75SMartin Murray if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len)
252782ace47aSThomas Graf return 0;
252882ace47aSThomas Graf
2529d35b6856SThomas Graf /* Only requests are handled by the kernel */
2530d35b6856SThomas Graf if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
25315c58298cSDenis V. Lunev goto ack;
2532d35b6856SThomas Graf
253345e7ae7fSThomas Graf /* Skip control messages */
253445e7ae7fSThomas Graf if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
25355c58298cSDenis V. Lunev goto ack;
253645e7ae7fSThomas Graf
25372d4bc933SJohannes Berg err = cb(skb, nlh, &extack);
25385c58298cSDenis V. Lunev if (err == -EINTR)
25395c58298cSDenis V. Lunev goto skip;
25405c58298cSDenis V. Lunev
25415c58298cSDenis V. Lunev ack:
2542d35b6856SThomas Graf if (nlh->nlmsg_flags & NLM_F_ACK || err)
25432d4bc933SJohannes Berg netlink_ack(skb, nlh, err, &extack);
254482ace47aSThomas Graf
25455c58298cSDenis V. Lunev skip:
2546cd40b7d3SDenis V. Lunev msglen = NLMSG_ALIGN(nlh->nlmsg_len);
2547cd40b7d3SDenis V. Lunev if (msglen > skb->len)
2548cd40b7d3SDenis V. Lunev msglen = skb->len;
2549cd40b7d3SDenis V. Lunev skb_pull(skb, msglen);
255082ace47aSThomas Graf }
255182ace47aSThomas Graf
255282ace47aSThomas Graf return 0;
255382ace47aSThomas Graf }
25546ac552fdSPatrick McHardy EXPORT_SYMBOL(netlink_rcv_skb);
255582ace47aSThomas Graf
255682ace47aSThomas Graf /**
2557d387f6adSThomas Graf * nlmsg_notify - send a notification netlink message
2558d387f6adSThomas Graf * @sk: netlink socket to use
2559d387f6adSThomas Graf * @skb: notification message
256015e47304SEric W. Biederman * @portid: destination netlink portid for reports or 0
2561d387f6adSThomas Graf * @group: destination multicast group or 0
2562d387f6adSThomas Graf * @report: 1 to report back, 0 to disable
2563d387f6adSThomas Graf * @flags: allocation flags
2564d387f6adSThomas Graf */
nlmsg_notify(struct sock * sk,struct sk_buff * skb,u32 portid,unsigned int group,int report,gfp_t flags)256515e47304SEric W. Biederman int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid,
2566d387f6adSThomas Graf unsigned int group, int report, gfp_t flags)
2567d387f6adSThomas Graf {
2568d387f6adSThomas Graf int err = 0;
2569d387f6adSThomas Graf
2570d387f6adSThomas Graf if (group) {
257115e47304SEric W. Biederman int exclude_portid = 0;
2572d387f6adSThomas Graf
2573d387f6adSThomas Graf if (report) {
257463354797SReshetova, Elena refcount_inc(&skb->users);
257515e47304SEric W. Biederman exclude_portid = portid;
2576d387f6adSThomas Graf }
2577d387f6adSThomas Graf
25781ce85fe4SPablo Neira Ayuso /* errors reported via destination sk->sk_err, but propagate
25791ce85fe4SPablo Neira Ayuso * delivery errors if NETLINK_BROADCAST_ERROR flag is set */
258015e47304SEric W. Biederman err = nlmsg_multicast(sk, skb, exclude_portid, group, flags);
2581fef773fcSYajun Deng if (err == -ESRCH)
2582fef773fcSYajun Deng err = 0;
2583d387f6adSThomas Graf }
2584d387f6adSThomas Graf
25851ce85fe4SPablo Neira Ayuso if (report) {
25861ce85fe4SPablo Neira Ayuso int err2;
25871ce85fe4SPablo Neira Ayuso
258815e47304SEric W. Biederman err2 = nlmsg_unicast(sk, skb, portid);
2589fef773fcSYajun Deng if (!err)
25901ce85fe4SPablo Neira Ayuso err = err2;
25911ce85fe4SPablo Neira Ayuso }
2592d387f6adSThomas Graf
2593d387f6adSThomas Graf return err;
2594d387f6adSThomas Graf }
25956ac552fdSPatrick McHardy EXPORT_SYMBOL(nlmsg_notify);
2596d387f6adSThomas Graf
25971da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
25981da177e4SLinus Torvalds struct nl_seq_iter {
2599e372c414SDenis V. Lunev struct seq_net_private p;
260056d28b1eSHerbert Xu struct rhashtable_iter hti;
26011da177e4SLinus Torvalds int link;
26021da177e4SLinus Torvalds };
26031da177e4SLinus Torvalds
netlink_walk_start(struct nl_seq_iter * iter)2604abf9979fSTaehee Yoo static void netlink_walk_start(struct nl_seq_iter *iter)
260556d28b1eSHerbert Xu {
26066c4128f6SHerbert Xu rhashtable_walk_enter(&nl_table[iter->link].hash, &iter->hti);
260797a6ec4aSTom Herbert rhashtable_walk_start(&iter->hti);
260856d28b1eSHerbert Xu }
260956d28b1eSHerbert Xu
netlink_walk_stop(struct nl_seq_iter * iter)261056d28b1eSHerbert Xu static void netlink_walk_stop(struct nl_seq_iter *iter)
261156d28b1eSHerbert Xu {
261256d28b1eSHerbert Xu rhashtable_walk_stop(&iter->hti);
261356d28b1eSHerbert Xu rhashtable_walk_exit(&iter->hti);
261456d28b1eSHerbert Xu }
261556d28b1eSHerbert Xu
__netlink_seq_next(struct seq_file * seq)261656d28b1eSHerbert Xu static void *__netlink_seq_next(struct seq_file *seq)
26171da177e4SLinus Torvalds {
26181da177e4SLinus Torvalds struct nl_seq_iter *iter = seq->private;
2619e341694eSThomas Graf struct netlink_sock *nlk;
26201da177e4SLinus Torvalds
262156d28b1eSHerbert Xu do {
262256d28b1eSHerbert Xu for (;;) {
262356d28b1eSHerbert Xu nlk = rhashtable_walk_next(&iter->hti);
262488d6ed15SThomas Graf
262556d28b1eSHerbert Xu if (IS_ERR(nlk)) {
262656d28b1eSHerbert Xu if (PTR_ERR(nlk) == -EAGAIN)
2627b4b51029SEric W. Biederman continue;
262856d28b1eSHerbert Xu
262956d28b1eSHerbert Xu return nlk;
26301da177e4SLinus Torvalds }
26311da177e4SLinus Torvalds
263256d28b1eSHerbert Xu if (nlk)
263356d28b1eSHerbert Xu break;
263456d28b1eSHerbert Xu
263556d28b1eSHerbert Xu netlink_walk_stop(iter);
263656d28b1eSHerbert Xu if (++iter->link >= MAX_LINKS)
263756d28b1eSHerbert Xu return NULL;
263856d28b1eSHerbert Xu
2639abf9979fSTaehee Yoo netlink_walk_start(iter);
264056d28b1eSHerbert Xu }
264156d28b1eSHerbert Xu } while (sock_net(&nlk->sk) != seq_file_net(seq));
264256d28b1eSHerbert Xu
264356d28b1eSHerbert Xu return nlk;
264456d28b1eSHerbert Xu }
264556d28b1eSHerbert Xu
netlink_seq_start(struct seq_file * seq,loff_t * posp)264656d28b1eSHerbert Xu static void *netlink_seq_start(struct seq_file *seq, loff_t *posp)
264764fbca01SJules Irenge __acquires(RCU)
26481da177e4SLinus Torvalds {
264956d28b1eSHerbert Xu struct nl_seq_iter *iter = seq->private;
265056d28b1eSHerbert Xu void *obj = SEQ_START_TOKEN;
265156d28b1eSHerbert Xu loff_t pos;
265256d28b1eSHerbert Xu
265356d28b1eSHerbert Xu iter->link = 0;
265456d28b1eSHerbert Xu
2655abf9979fSTaehee Yoo netlink_walk_start(iter);
265656d28b1eSHerbert Xu
265756d28b1eSHerbert Xu for (pos = *posp; pos && obj && !IS_ERR(obj); pos--)
265856d28b1eSHerbert Xu obj = __netlink_seq_next(seq);
265956d28b1eSHerbert Xu
266056d28b1eSHerbert Xu return obj;
26611da177e4SLinus Torvalds }
26621da177e4SLinus Torvalds
netlink_seq_next(struct seq_file * seq,void * v,loff_t * pos)26631da177e4SLinus Torvalds static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos)
26641da177e4SLinus Torvalds {
26651da177e4SLinus Torvalds ++*pos;
266656d28b1eSHerbert Xu return __netlink_seq_next(seq);
26671da177e4SLinus Torvalds }
26681da177e4SLinus Torvalds
netlink_native_seq_stop(struct seq_file * seq,void * v)2669138d0be3SYonghong Song static void netlink_native_seq_stop(struct seq_file *seq, void *v)
26701da177e4SLinus Torvalds {
267156d28b1eSHerbert Xu struct nl_seq_iter *iter = seq->private;
267256d28b1eSHerbert Xu
267356d28b1eSHerbert Xu if (iter->link >= MAX_LINKS)
267456d28b1eSHerbert Xu return;
267556d28b1eSHerbert Xu
267656d28b1eSHerbert Xu netlink_walk_stop(iter);
26771da177e4SLinus Torvalds }
26781da177e4SLinus Torvalds
26791da177e4SLinus Torvalds
netlink_native_seq_show(struct seq_file * seq,void * v)2680138d0be3SYonghong Song static int netlink_native_seq_show(struct seq_file *seq, void *v)
26811da177e4SLinus Torvalds {
2682658cb354SEric Dumazet if (v == SEQ_START_TOKEN) {
26831da177e4SLinus Torvalds seq_puts(seq,
26841da177e4SLinus Torvalds "sk Eth Pid Groups "
2685cf0aa4e0SMasatake YAMATO "Rmem Wmem Dump Locks Drops Inode\n");
2686658cb354SEric Dumazet } else {
26871da177e4SLinus Torvalds struct sock *s = v;
26881da177e4SLinus Torvalds struct netlink_sock *nlk = nlk_sk(s);
26891da177e4SLinus Torvalds
2690ea9a0379SPatrick Talbert seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8u %-8lu\n",
26911da177e4SLinus Torvalds s,
26921da177e4SLinus Torvalds s->sk_protocol,
269315e47304SEric W. Biederman nlk->portid,
2694513c2500SPatrick McHardy nlk->groups ? (u32)nlk->groups[0] : 0,
269531e6d363SEric Dumazet sk_rmem_alloc_get(s),
269631e6d363SEric Dumazet sk_wmem_alloc_get(s),
2697a939d149SEric Dumazet READ_ONCE(nlk->cb_running),
269841c6d650SReshetova, Elena refcount_read(&s->sk_refcnt),
2699cf0aa4e0SMasatake YAMATO atomic_read(&s->sk_drops),
2700cf0aa4e0SMasatake YAMATO sock_i_ino(s)
27011da177e4SLinus Torvalds );
27021da177e4SLinus Torvalds
27031da177e4SLinus Torvalds }
27041da177e4SLinus Torvalds return 0;
27051da177e4SLinus Torvalds }
27061da177e4SLinus Torvalds
2707138d0be3SYonghong Song #ifdef CONFIG_BPF_SYSCALL
2708138d0be3SYonghong Song struct bpf_iter__netlink {
2709138d0be3SYonghong Song __bpf_md_ptr(struct bpf_iter_meta *, meta);
2710138d0be3SYonghong Song __bpf_md_ptr(struct netlink_sock *, sk);
2711138d0be3SYonghong Song };
2712138d0be3SYonghong Song
DEFINE_BPF_ITER_FUNC(netlink,struct bpf_iter_meta * meta,struct netlink_sock * sk)2713138d0be3SYonghong Song DEFINE_BPF_ITER_FUNC(netlink, struct bpf_iter_meta *meta, struct netlink_sock *sk)
2714138d0be3SYonghong Song
2715138d0be3SYonghong Song static int netlink_prog_seq_show(struct bpf_prog *prog,
2716138d0be3SYonghong Song struct bpf_iter_meta *meta,
2717138d0be3SYonghong Song void *v)
2718138d0be3SYonghong Song {
2719138d0be3SYonghong Song struct bpf_iter__netlink ctx;
2720138d0be3SYonghong Song
2721138d0be3SYonghong Song meta->seq_num--; /* skip SEQ_START_TOKEN */
2722138d0be3SYonghong Song ctx.meta = meta;
2723138d0be3SYonghong Song ctx.sk = nlk_sk((struct sock *)v);
2724138d0be3SYonghong Song return bpf_iter_run_prog(prog, &ctx);
2725138d0be3SYonghong Song }
2726138d0be3SYonghong Song
netlink_seq_show(struct seq_file * seq,void * v)2727138d0be3SYonghong Song static int netlink_seq_show(struct seq_file *seq, void *v)
2728138d0be3SYonghong Song {
2729138d0be3SYonghong Song struct bpf_iter_meta meta;
2730138d0be3SYonghong Song struct bpf_prog *prog;
2731138d0be3SYonghong Song
2732138d0be3SYonghong Song meta.seq = seq;
2733138d0be3SYonghong Song prog = bpf_iter_get_info(&meta, false);
2734138d0be3SYonghong Song if (!prog)
2735138d0be3SYonghong Song return netlink_native_seq_show(seq, v);
2736138d0be3SYonghong Song
2737138d0be3SYonghong Song if (v != SEQ_START_TOKEN)
2738138d0be3SYonghong Song return netlink_prog_seq_show(prog, &meta, v);
2739138d0be3SYonghong Song
2740138d0be3SYonghong Song return 0;
2741138d0be3SYonghong Song }
2742138d0be3SYonghong Song
netlink_seq_stop(struct seq_file * seq,void * v)2743138d0be3SYonghong Song static void netlink_seq_stop(struct seq_file *seq, void *v)
2744138d0be3SYonghong Song {
2745138d0be3SYonghong Song struct bpf_iter_meta meta;
2746138d0be3SYonghong Song struct bpf_prog *prog;
2747138d0be3SYonghong Song
2748138d0be3SYonghong Song if (!v) {
2749138d0be3SYonghong Song meta.seq = seq;
2750138d0be3SYonghong Song prog = bpf_iter_get_info(&meta, true);
2751138d0be3SYonghong Song if (prog)
2752138d0be3SYonghong Song (void)netlink_prog_seq_show(prog, &meta, v);
2753138d0be3SYonghong Song }
2754138d0be3SYonghong Song
2755138d0be3SYonghong Song netlink_native_seq_stop(seq, v);
2756138d0be3SYonghong Song }
2757138d0be3SYonghong Song #else
netlink_seq_show(struct seq_file * seq,void * v)2758138d0be3SYonghong Song static int netlink_seq_show(struct seq_file *seq, void *v)
2759138d0be3SYonghong Song {
2760138d0be3SYonghong Song return netlink_native_seq_show(seq, v);
2761138d0be3SYonghong Song }
2762138d0be3SYonghong Song
netlink_seq_stop(struct seq_file * seq,void * v)2763138d0be3SYonghong Song static void netlink_seq_stop(struct seq_file *seq, void *v)
2764138d0be3SYonghong Song {
2765138d0be3SYonghong Song netlink_native_seq_stop(seq, v);
2766138d0be3SYonghong Song }
2767138d0be3SYonghong Song #endif
2768138d0be3SYonghong Song
276956b3d975SPhilippe De Muyter static const struct seq_operations netlink_seq_ops = {
27701da177e4SLinus Torvalds .start = netlink_seq_start,
27711da177e4SLinus Torvalds .next = netlink_seq_next,
27721da177e4SLinus Torvalds .stop = netlink_seq_stop,
27731da177e4SLinus Torvalds .show = netlink_seq_show,
27741da177e4SLinus Torvalds };
27751da177e4SLinus Torvalds #endif
27761da177e4SLinus Torvalds
netlink_register_notifier(struct notifier_block * nb)27771da177e4SLinus Torvalds int netlink_register_notifier(struct notifier_block *nb)
27781da177e4SLinus Torvalds {
2779efa172f4SWANG Cong return blocking_notifier_chain_register(&netlink_chain, nb);
27801da177e4SLinus Torvalds }
27816ac552fdSPatrick McHardy EXPORT_SYMBOL(netlink_register_notifier);
27821da177e4SLinus Torvalds
netlink_unregister_notifier(struct notifier_block * nb)27831da177e4SLinus Torvalds int netlink_unregister_notifier(struct notifier_block *nb)
27841da177e4SLinus Torvalds {
2785efa172f4SWANG Cong return blocking_notifier_chain_unregister(&netlink_chain, nb);
27861da177e4SLinus Torvalds }
27876ac552fdSPatrick McHardy EXPORT_SYMBOL(netlink_unregister_notifier);
27881da177e4SLinus Torvalds
278990ddc4f0SEric Dumazet static const struct proto_ops netlink_ops = {
27901da177e4SLinus Torvalds .family = PF_NETLINK,
27911da177e4SLinus Torvalds .owner = THIS_MODULE,
27921da177e4SLinus Torvalds .release = netlink_release,
27931da177e4SLinus Torvalds .bind = netlink_bind,
27941da177e4SLinus Torvalds .connect = netlink_connect,
27951da177e4SLinus Torvalds .socketpair = sock_no_socketpair,
27961da177e4SLinus Torvalds .accept = sock_no_accept,
27971da177e4SLinus Torvalds .getname = netlink_getname,
2798a11e1d43SLinus Torvalds .poll = datagram_poll,
2799025c6818SDavid Decotigny .ioctl = netlink_ioctl,
28001da177e4SLinus Torvalds .listen = sock_no_listen,
28011da177e4SLinus Torvalds .shutdown = sock_no_shutdown,
28029a4595bcSPatrick McHardy .setsockopt = netlink_setsockopt,
28039a4595bcSPatrick McHardy .getsockopt = netlink_getsockopt,
28041da177e4SLinus Torvalds .sendmsg = netlink_sendmsg,
28051da177e4SLinus Torvalds .recvmsg = netlink_recvmsg,
2806d1b4c689SFlorian Westphal .mmap = sock_no_mmap,
28071da177e4SLinus Torvalds };
28081da177e4SLinus Torvalds
2809ec1b4cf7SStephen Hemminger static const struct net_proto_family netlink_family_ops = {
28101da177e4SLinus Torvalds .family = PF_NETLINK,
28111da177e4SLinus Torvalds .create = netlink_create,
28121da177e4SLinus Torvalds .owner = THIS_MODULE, /* for consistency 8) */
28131da177e4SLinus Torvalds };
28141da177e4SLinus Torvalds
netlink_net_init(struct net * net)28154665079cSPavel Emelyanov static int __net_init netlink_net_init(struct net *net)
2816b4b51029SEric W. Biederman {
2817b4b51029SEric W. Biederman #ifdef CONFIG_PROC_FS
2818c3506372SChristoph Hellwig if (!proc_create_net("netlink", 0, net->proc_net, &netlink_seq_ops,
2819c3506372SChristoph Hellwig sizeof(struct nl_seq_iter)))
2820b4b51029SEric W. Biederman return -ENOMEM;
2821b4b51029SEric W. Biederman #endif
2822b4b51029SEric W. Biederman return 0;
2823b4b51029SEric W. Biederman }
2824b4b51029SEric W. Biederman
netlink_net_exit(struct net * net)28254665079cSPavel Emelyanov static void __net_exit netlink_net_exit(struct net *net)
2826b4b51029SEric W. Biederman {
2827b4b51029SEric W. Biederman #ifdef CONFIG_PROC_FS
2828ece31ffdSGao feng remove_proc_entry("netlink", net->proc_net);
2829b4b51029SEric W. Biederman #endif
2830b4b51029SEric W. Biederman }
2831b4b51029SEric W. Biederman
netlink_add_usersock_entry(void)2832b963ea89SDavid S. Miller static void __init netlink_add_usersock_entry(void)
2833b963ea89SDavid S. Miller {
28345c398dc8SEric Dumazet struct listeners *listeners;
2835b963ea89SDavid S. Miller int groups = 32;
2836b963ea89SDavid S. Miller
28375c398dc8SEric Dumazet listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL);
2838b963ea89SDavid S. Miller if (!listeners)
28395c398dc8SEric Dumazet panic("netlink_add_usersock_entry: Cannot allocate listeners\n");
2840b963ea89SDavid S. Miller
2841b963ea89SDavid S. Miller netlink_table_grab();
2842b963ea89SDavid S. Miller
2843b963ea89SDavid S. Miller nl_table[NETLINK_USERSOCK].groups = groups;
28445c398dc8SEric Dumazet rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners);
2845b963ea89SDavid S. Miller nl_table[NETLINK_USERSOCK].module = THIS_MODULE;
2846b963ea89SDavid S. Miller nl_table[NETLINK_USERSOCK].registered = 1;
28479785e10aSPablo Neira Ayuso nl_table[NETLINK_USERSOCK].flags = NL_CFG_F_NONROOT_SEND;
2848b963ea89SDavid S. Miller
2849b963ea89SDavid S. Miller netlink_table_ungrab();
2850b963ea89SDavid S. Miller }
2851b963ea89SDavid S. Miller
2852022cbae6SDenis V. Lunev static struct pernet_operations __net_initdata netlink_net_ops = {
2853b4b51029SEric W. Biederman .init = netlink_net_init,
2854b4b51029SEric W. Biederman .exit = netlink_net_exit,
2855b4b51029SEric W. Biederman };
2856b4b51029SEric W. Biederman
netlink_hash(const void * data,u32 len,u32 seed)285749f7b33eSPatrick McHardy static inline u32 netlink_hash(const void *data, u32 len, u32 seed)
2858c428ecd1SHerbert Xu {
2859c428ecd1SHerbert Xu const struct netlink_sock *nlk = data;
2860c428ecd1SHerbert Xu struct netlink_compare_arg arg;
2861c428ecd1SHerbert Xu
2862da314c99SHerbert Xu netlink_compare_arg_init(&arg, sock_net(&nlk->sk), nlk->portid);
286311b58ba1SHerbert Xu return jhash2((u32 *)&arg, netlink_compare_arg_len / sizeof(u32), seed);
2864c428ecd1SHerbert Xu }
2865c428ecd1SHerbert Xu
2866c428ecd1SHerbert Xu static const struct rhashtable_params netlink_rhashtable_params = {
2867c428ecd1SHerbert Xu .head_offset = offsetof(struct netlink_sock, node),
2868c428ecd1SHerbert Xu .key_len = netlink_compare_arg_len,
2869c428ecd1SHerbert Xu .obj_hashfn = netlink_hash,
2870c428ecd1SHerbert Xu .obj_cmpfn = netlink_compare,
2871b5e2c150SThomas Graf .automatic_shrinking = true,
2872c428ecd1SHerbert Xu };
2873c428ecd1SHerbert Xu
2874138d0be3SYonghong Song #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
2875951cf368SYonghong Song BTF_ID_LIST(btf_netlink_sock_id)
2876951cf368SYonghong Song BTF_ID(struct, netlink_sock)
2877951cf368SYonghong Song
287814fc6bd6SYonghong Song static const struct bpf_iter_seq_info netlink_seq_info = {
2879138d0be3SYonghong Song .seq_ops = &netlink_seq_ops,
2880138d0be3SYonghong Song .init_seq_private = bpf_iter_init_seq_net,
2881138d0be3SYonghong Song .fini_seq_private = bpf_iter_fini_seq_net,
2882138d0be3SYonghong Song .seq_priv_size = sizeof(struct nl_seq_iter),
288314fc6bd6SYonghong Song };
288414fc6bd6SYonghong Song
288514fc6bd6SYonghong Song static struct bpf_iter_reg netlink_reg_info = {
288614fc6bd6SYonghong Song .target = "netlink",
28873c32cc1bSYonghong Song .ctx_arg_info_size = 1,
28883c32cc1bSYonghong Song .ctx_arg_info = {
28893c32cc1bSYonghong Song { offsetof(struct bpf_iter__netlink, sk),
28903c32cc1bSYonghong Song PTR_TO_BTF_ID_OR_NULL },
28913c32cc1bSYonghong Song },
289214fc6bd6SYonghong Song .seq_info = &netlink_seq_info,
2893138d0be3SYonghong Song };
2894138d0be3SYonghong Song
bpf_iter_register(void)289515172a46SYonghong Song static int __init bpf_iter_register(void)
289615172a46SYonghong Song {
2897951cf368SYonghong Song netlink_reg_info.ctx_arg_info[0].btf_id = *btf_netlink_sock_id;
289815172a46SYonghong Song return bpf_iter_reg_target(&netlink_reg_info);
2899138d0be3SYonghong Song }
2900138d0be3SYonghong Song #endif
2901138d0be3SYonghong Song
netlink_proto_init(void)29021da177e4SLinus Torvalds static int __init netlink_proto_init(void)
29031da177e4SLinus Torvalds {
29041da177e4SLinus Torvalds int i;
29051da177e4SLinus Torvalds int err = proto_register(&netlink_proto, 0);
29061da177e4SLinus Torvalds
29071da177e4SLinus Torvalds if (err != 0)
29081da177e4SLinus Torvalds goto out;
29091da177e4SLinus Torvalds
2910138d0be3SYonghong Song #if defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
2911138d0be3SYonghong Song err = bpf_iter_register();
2912138d0be3SYonghong Song if (err)
2913138d0be3SYonghong Song goto out;
2914138d0be3SYonghong Song #endif
2915138d0be3SYonghong Song
2916c593642cSPankaj Bharadiya BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > sizeof_field(struct sk_buff, cb));
29171da177e4SLinus Torvalds
29180da974f4SPanagiotis Issaris nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL);
2919fab2caf6SAkinobu Mita if (!nl_table)
2920fab2caf6SAkinobu Mita goto panic;
29211da177e4SLinus Torvalds
29221da177e4SLinus Torvalds for (i = 0; i < MAX_LINKS; i++) {
2923c428ecd1SHerbert Xu if (rhashtable_init(&nl_table[i].hash,
2924c428ecd1SHerbert Xu &netlink_rhashtable_params) < 0) {
2925e341694eSThomas Graf while (--i > 0)
2926e341694eSThomas Graf rhashtable_destroy(&nl_table[i].hash);
29271da177e4SLinus Torvalds kfree(nl_table);
2928fab2caf6SAkinobu Mita goto panic;
29291da177e4SLinus Torvalds }
29301da177e4SLinus Torvalds }
29311da177e4SLinus Torvalds
2932b963ea89SDavid S. Miller netlink_add_usersock_entry();
2933b963ea89SDavid S. Miller
29341da177e4SLinus Torvalds sock_register(&netlink_family_ops);
2935b4b51029SEric W. Biederman register_pernet_subsys(&netlink_net_ops);
293625e3f70fSCong Wang register_pernet_subsys(&netlink_tap_net_ops);
29371da177e4SLinus Torvalds /* The netlink device handler may be needed early. */
29381da177e4SLinus Torvalds rtnetlink_init();
29391da177e4SLinus Torvalds out:
29401da177e4SLinus Torvalds return err;
2941fab2caf6SAkinobu Mita panic:
2942fab2caf6SAkinobu Mita panic("netlink_init: Cannot allocate nl_table\n");
29431da177e4SLinus Torvalds }
29441da177e4SLinus Torvalds
29451da177e4SLinus Torvalds core_initcall(netlink_proto_init);
2946