Although RCU protection would be possible during diag dump, doing
so allows for concurrent table mutations which can render the
in-table offset between individual Netlink messages invalid and
thus cause legitimate sockets to be skipped in the dump.
Since the diag dump is relatively low volume and consistency is
more important than performance, the table mutex is held during
dump.
Reported-by: Andrey Wagin <avagin@gmail.com>
Signed-off-by: Thomas Graf <tgraf@suug.ch>
Fixes: e341694e3e ("netlink: Convert netlink_lookup() to use RCU protected hash table")
Signed-off-by: David S. Miller <davem@davemloft.net>
		
	
			
		
			
				
	
	
		
			78 lines
		
	
	
	
		
			1.8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			78 lines
		
	
	
	
		
			1.8 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
#ifndef _AF_NETLINK_H
 | 
						|
#define _AF_NETLINK_H
 | 
						|
 | 
						|
#include <linux/rhashtable.h>
 | 
						|
#include <net/sock.h>
 | 
						|
 | 
						|
#define NLGRPSZ(x)	(ALIGN(x, sizeof(unsigned long) * 8) / 8)
 | 
						|
#define NLGRPLONGS(x)	(NLGRPSZ(x)/sizeof(unsigned long))
 | 
						|
 | 
						|
struct netlink_ring {
 | 
						|
	void			**pg_vec;
 | 
						|
	unsigned int		head;
 | 
						|
	unsigned int		frames_per_block;
 | 
						|
	unsigned int		frame_size;
 | 
						|
	unsigned int		frame_max;
 | 
						|
 | 
						|
	unsigned int		pg_vec_order;
 | 
						|
	unsigned int		pg_vec_pages;
 | 
						|
	unsigned int		pg_vec_len;
 | 
						|
 | 
						|
	atomic_t		pending;
 | 
						|
};
 | 
						|
 | 
						|
struct netlink_sock {
 | 
						|
	/* struct sock has to be the first member of netlink_sock */
 | 
						|
	struct sock		sk;
 | 
						|
	u32			portid;
 | 
						|
	u32			dst_portid;
 | 
						|
	u32			dst_group;
 | 
						|
	u32			flags;
 | 
						|
	u32			subscriptions;
 | 
						|
	u32			ngroups;
 | 
						|
	unsigned long		*groups;
 | 
						|
	unsigned long		state;
 | 
						|
	size_t			max_recvmsg_len;
 | 
						|
	wait_queue_head_t	wait;
 | 
						|
	bool			cb_running;
 | 
						|
	struct netlink_callback	cb;
 | 
						|
	struct mutex		*cb_mutex;
 | 
						|
	struct mutex		cb_def_mutex;
 | 
						|
	void			(*netlink_rcv)(struct sk_buff *skb);
 | 
						|
	int			(*netlink_bind)(int group);
 | 
						|
	void			(*netlink_unbind)(int group);
 | 
						|
	struct module		*module;
 | 
						|
#ifdef CONFIG_NETLINK_MMAP
 | 
						|
	struct mutex		pg_vec_lock;
 | 
						|
	struct netlink_ring	rx_ring;
 | 
						|
	struct netlink_ring	tx_ring;
 | 
						|
	atomic_t		mapped;
 | 
						|
#endif /* CONFIG_NETLINK_MMAP */
 | 
						|
 | 
						|
	struct rhash_head	node;
 | 
						|
};
 | 
						|
 | 
						|
static inline struct netlink_sock *nlk_sk(struct sock *sk)
 | 
						|
{
 | 
						|
	return container_of(sk, struct netlink_sock, sk);
 | 
						|
}
 | 
						|
 | 
						|
struct netlink_table {
 | 
						|
	struct rhashtable	hash;
 | 
						|
	struct hlist_head	mc_list;
 | 
						|
	struct listeners __rcu	*listeners;
 | 
						|
	unsigned int		flags;
 | 
						|
	unsigned int		groups;
 | 
						|
	struct mutex		*cb_mutex;
 | 
						|
	struct module		*module;
 | 
						|
	int			(*bind)(int group);
 | 
						|
	void			(*unbind)(int group);
 | 
						|
	bool			(*compare)(struct net *net, struct sock *sock);
 | 
						|
	int			registered;
 | 
						|
};
 | 
						|
 | 
						|
extern struct netlink_table *nl_table;
 | 
						|
extern rwlock_t nl_table_lock;
 | 
						|
extern struct mutex nl_sk_hash_lock;
 | 
						|
 | 
						|
#endif
 |