aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2010-07-14 23:50:29 -0400
committerDavid S. Miller <davem@davemloft.net>2010-07-14 23:50:29 -0400
commitb0f77d0eae0c58a5a9691a067ada112ceeae2d00 (patch)
tree2bab159a95f51e32dbb4eb2d554328de3190c678
parent91a72a70594e5212c97705ca6a694bd307f7a26b (diff)
net: fix problem in reading sock TX queue
Fix problem in reading the tx_queue recorded in a socket. In dev_pick_tx, the TX queue is read by doing a check with sk_tx_queue_recorded on the socket, followed by a sk_tx_queue_get. The problem is that there is not mutual exclusion across these calls in the socket so it it is possible that the queue in the sock can be invalidated after sk_tx_queue_recorded is called so that sk_tx_queue get returns -1, which sets 65535 in queue_index and thus dev_pick_tx returns 65536 which is a bogus queue and can cause crash in dev_queue_xmit. We fix this by only calling sk_tx_queue_get which does the proper checks. The interface is that sk_tx_queue_get returns the TX queue if the sock argument is non-NULL and TX queue is recorded, else it returns -1. sk_tx_queue_recorded is no longer used so it can be completely removed. Signed-off-by: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/sock.h7
-rw-r--r--net/core/dev.c7
2 files changed, 4 insertions, 10 deletions
diff --git a/include/net/sock.h b/include/net/sock.h
index 731150d52799..0a691ea7654a 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1224,12 +1224,7 @@ static inline void sk_tx_queue_clear(struct sock *sk)
1224 1224
1225static inline int sk_tx_queue_get(const struct sock *sk) 1225static inline int sk_tx_queue_get(const struct sock *sk)
1226{ 1226{
1227 return sk->sk_tx_queue_mapping; 1227 return sk ? sk->sk_tx_queue_mapping : -1;
1228}
1229
1230static inline bool sk_tx_queue_recorded(const struct sock *sk)
1231{
1232 return (sk && sk->sk_tx_queue_mapping >= 0);
1233} 1228}
1234 1229
1235static inline void sk_set_socket(struct sock *sk, struct socket *sock) 1230static inline void sk_set_socket(struct sock *sk, struct socket *sock)
diff --git a/net/core/dev.c b/net/core/dev.c
index 4b05fdf762ab..0ea10f849be8 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2029,12 +2029,11 @@ static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index)
2029static struct netdev_queue *dev_pick_tx(struct net_device *dev, 2029static struct netdev_queue *dev_pick_tx(struct net_device *dev,
2030 struct sk_buff *skb) 2030 struct sk_buff *skb)
2031{ 2031{
2032 u16 queue_index; 2032 int queue_index;
2033 struct sock *sk = skb->sk; 2033 struct sock *sk = skb->sk;
2034 2034
2035 if (sk_tx_queue_recorded(sk)) { 2035 queue_index = sk_tx_queue_get(sk);
2036 queue_index = sk_tx_queue_get(sk); 2036 if (queue_index < 0) {
2037 } else {
2038 const struct net_device_ops *ops = dev->netdev_ops; 2037 const struct net_device_ops *ops = dev->netdev_ops;
2039 2038
2040 if (ops->ndo_select_queue) { 2039 if (ops->ndo_select_queue) {