netlink: hold nl_sock_hash_lock during diag dump
authorThomas Graf <tgraf@suug.ch>
Wed, 6 Aug 2014 23:18:47 +0000 (00:18 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 7 Aug 2014 02:17:44 +0000 (19:17 -0700)
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: e341694e3eb57fc ("netlink: Convert netlink_lookup() to use RCU protected hash table")
Signed-off-by: David S. Miller <davem@davemloft.net>
net/netlink/af_netlink.c
net/netlink/af_netlink.h
net/netlink/diag.c

index 479a344563d836a9ea13250665cb9c04da7fc587..a324b4b34c909094f1b1aac14e986e3777bccd5d 100644 (file)
@@ -104,6 +104,7 @@ static atomic_t nl_table_users = ATOMIC_INIT(0);
 
 /* Protects netlink socket hash table mutations */
 DEFINE_MUTEX(nl_sk_hash_lock);
+EXPORT_SYMBOL_GPL(nl_sk_hash_lock);
 
 static int lockdep_nl_sk_hash_is_held(void)
 {
index 60f631fb7087485f0a71f100807035c9255b989d..b20a1731759b2e6dc8bbe3064933bb3d67134d26 100644 (file)
@@ -73,5 +73,6 @@ struct netlink_table {
 
 extern struct netlink_table *nl_table;
 extern rwlock_t nl_table_lock;
+extern struct mutex nl_sk_hash_lock;
 
 #endif
index 7301850eb56fe32ad700d5d50daeab25f706284d..de8c74a3c0615ac98ee13ab403491afd8fcac3eb 100644 (file)
@@ -170,6 +170,7 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 
        req = nlmsg_data(cb->nlh);
 
+       mutex_lock(&nl_sk_hash_lock);
        read_lock(&nl_table_lock);
 
        if (req->sdiag_protocol == NDIAG_PROTO_ALL) {
@@ -183,6 +184,7 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
        } else {
                if (req->sdiag_protocol >= MAX_LINKS) {
                        read_unlock(&nl_table_lock);
+                       mutex_unlock(&nl_sk_hash_lock);
                        return -ENOENT;
                }
 
@@ -190,6 +192,7 @@ static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
        }
 
        read_unlock(&nl_table_lock);
+       mutex_unlock(&nl_sk_hash_lock);
 
        return skb->len;
 }