aboutsummaryrefslogtreecommitdiffstats
path: root/net/econet
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-06-09 12:33:05 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-11 21:37:08 -0400
commit0c78a92fbd655ab990e2799f645707f05f548e2f (patch)
tree8dd5bb176c76c142c6b310b4ce4d076d36acaec3 /net/econet
parentc7de2cf053420d63bac85133469c965d4b1083e1 (diff)
econet: fix locking
econet lacks proper locking. It holds econet_lock only when inserting or deleting an entry in econet_sklist, not during lookups. - convert econet_lock from rwlock to spinlock - use econet_lock in ec_listening_socket() lookup - use appropriate sock_hold() / sock_put() to avoid corruptions. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/econet')
-rw-r--r--net/econet/af_econet.c27
1 files changed, 18 insertions, 9 deletions
diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c
index 2a5a8053e000..dc54bd0d083b 100644
--- a/net/econet/af_econet.c
+++ b/net/econet/af_econet.c
@@ -48,7 +48,7 @@
48 48
49static const struct proto_ops econet_ops; 49static const struct proto_ops econet_ops;
50static struct hlist_head econet_sklist; 50static struct hlist_head econet_sklist;
51static DEFINE_RWLOCK(econet_lock); 51static DEFINE_SPINLOCK(econet_lock);
52static DEFINE_MUTEX(econet_mutex); 52static DEFINE_MUTEX(econet_mutex);
53 53
54/* Since there are only 256 possible network numbers (or fewer, depends 54/* Since there are only 256 possible network numbers (or fewer, depends
@@ -98,16 +98,16 @@ struct ec_cb
98 98
99static void econet_remove_socket(struct hlist_head *list, struct sock *sk) 99static void econet_remove_socket(struct hlist_head *list, struct sock *sk)
100{ 100{
101 write_lock_bh(&econet_lock); 101 spin_lock_bh(&econet_lock);
102 sk_del_node_init(sk); 102 sk_del_node_init(sk);
103 write_unlock_bh(&econet_lock); 103 spin_unlock_bh(&econet_lock);
104} 104}
105 105
106static void econet_insert_socket(struct hlist_head *list, struct sock *sk) 106static void econet_insert_socket(struct hlist_head *list, struct sock *sk)
107{ 107{
108 write_lock_bh(&econet_lock); 108 spin_lock_bh(&econet_lock);
109 sk_add_node(sk, list); 109 sk_add_node(sk, list);
110 write_unlock_bh(&econet_lock); 110 spin_unlock_bh(&econet_lock);
111} 111}
112 112
113/* 113/*
@@ -782,15 +782,19 @@ static struct sock *ec_listening_socket(unsigned char port, unsigned char
782 struct sock *sk; 782 struct sock *sk;
783 struct hlist_node *node; 783 struct hlist_node *node;
784 784
785 spin_lock(&econet_lock);
785 sk_for_each(sk, node, &econet_sklist) { 786 sk_for_each(sk, node, &econet_sklist) {
786 struct econet_sock *opt = ec_sk(sk); 787 struct econet_sock *opt = ec_sk(sk);
787 if ((opt->port == port || opt->port == 0) && 788 if ((opt->port == port || opt->port == 0) &&
788 (opt->station == station || opt->station == 0) && 789 (opt->station == station || opt->station == 0) &&
789 (opt->net == net || opt->net == 0)) 790 (opt->net == net || opt->net == 0)) {
791 sock_hold(sk);
790 goto found; 792 goto found;
793 }
791 } 794 }
792 sk = NULL; 795 sk = NULL;
793found: 796found:
797 spin_unlock(&econet_lock);
794 return sk; 798 return sk;
795} 799}
796 800
@@ -852,7 +856,7 @@ static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
852{ 856{
853 struct iphdr *ip = ip_hdr(skb); 857 struct iphdr *ip = ip_hdr(skb);
854 unsigned char stn = ntohl(ip->saddr) & 0xff; 858 unsigned char stn = ntohl(ip->saddr) & 0xff;
855 struct sock *sk; 859 struct sock *sk = NULL;
856 struct sk_buff *newskb; 860 struct sk_buff *newskb;
857 struct ec_device *edev = skb->dev->ec_ptr; 861 struct ec_device *edev = skb->dev->ec_ptr;
858 862
@@ -882,10 +886,13 @@ static void aun_incoming(struct sk_buff *skb, struct aunhdr *ah, size_t len)
882 } 886 }
883 887
884 aun_send_response(ip->saddr, ah->handle, 3, 0); 888 aun_send_response(ip->saddr, ah->handle, 3, 0);
889 sock_put(sk);
885 return; 890 return;
886 891
887bad: 892bad:
888 aun_send_response(ip->saddr, ah->handle, 4, 0); 893 aun_send_response(ip->saddr, ah->handle, 4, 0);
894 if (sk)
895 sock_put(sk);
889} 896}
890 897
891/* 898/*
@@ -1050,7 +1057,7 @@ release:
1050static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) 1057static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
1051{ 1058{
1052 struct ec_framehdr *hdr; 1059 struct ec_framehdr *hdr;
1053 struct sock *sk; 1060 struct sock *sk = NULL;
1054 struct ec_device *edev = dev->ec_ptr; 1061 struct ec_device *edev = dev->ec_ptr;
1055 1062
1056 if (!net_eq(dev_net(dev), &init_net)) 1063 if (!net_eq(dev_net(dev), &init_net))
@@ -1085,10 +1092,12 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet
1085 if (ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb, 1092 if (ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb,
1086 hdr->port)) 1093 hdr->port))
1087 goto drop; 1094 goto drop;
1088 1095 sock_put(sk);
1089 return NET_RX_SUCCESS; 1096 return NET_RX_SUCCESS;
1090 1097
1091drop: 1098drop:
1099 if (sk)
1100 sock_put(sk);
1092 kfree_skb(skb); 1101 kfree_skb(skb);
1093 return NET_RX_DROP; 1102 return NET_RX_DROP;
1094} 1103}