aboutsummaryrefslogtreecommitdiffstats
path: root/net/netlink
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2013-08-13 03:04:05 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-13 03:57:06 -0400
commit58ad436fcf49810aa006016107f494c9ac9013db (patch)
tree0853904283d081562e2c07bed067c36e03936c0c /net/netlink
parent771085d6bf3c52de29fc213e5bad07a82e57c23e (diff)
genetlink: fix family dump race
When dumping generic netlink families, only the first dump call is locked with genl_lock(), which protects the list of families, and thus subsequent calls can access the data without locking, racing against family addition/removal. This can cause a crash. Fix it - the locking needs to be conditional because the first time around it's already locked. A similar bug was reported to me on an old kernel (3.4.47) but the exact scenario that happened there is no longer possible, on those kernels the first round wasn't locked either. Looking at the current code I found the race described above, which had also existed on the old kernel. Cc: stable@vger.kernel.org Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r--net/netlink/genetlink.c7
1 files changed, 7 insertions, 0 deletions
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 512718adb0d5..f85f8a2ad6cf 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -789,6 +789,10 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
789 struct net *net = sock_net(skb->sk); 789 struct net *net = sock_net(skb->sk);
790 int chains_to_skip = cb->args[0]; 790 int chains_to_skip = cb->args[0];
791 int fams_to_skip = cb->args[1]; 791 int fams_to_skip = cb->args[1];
792 bool need_locking = chains_to_skip || fams_to_skip;
793
794 if (need_locking)
795 genl_lock();
792 796
793 for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) { 797 for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) {
794 n = 0; 798 n = 0;
@@ -810,6 +814,9 @@ errout:
810 cb->args[0] = i; 814 cb->args[0] = i;
811 cb->args[1] = n; 815 cb->args[1] = n;
812 816
817 if (need_locking)
818 genl_unlock();
819
813 return skb->len; 820 return skb->len;
814} 821}
815 822