diff options
author | Ursula Braun <braunu@de.ibm.com> | 2008-02-07 21:07:44 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-02-07 21:07:44 -0500 |
commit | f2a77991a918218be4a3ac78250e7eba2282be59 (patch) | |
tree | 40bdf696b7d2e83a0335ce1357808b45b41184dc /net/iucv/af_iucv.c | |
parent | d44447229e35115675d166b51a52e512c281475c (diff) |
[AF_IUCV]: defensive programming of iucv_callback_txdone
The loop in iucv_callback_txdone presumes existence of an entry
with msg->tag in the send_skb_q list. In error cases this
assumption might be wrong and might cause an endless loop.
Loop is rewritten to guarantee loop end in case of missing
msg->tag entry in send_skb_q.
Signed-off-by: Ursula Braun <braunu@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/iucv/af_iucv.c')
-rw-r--r-- | net/iucv/af_iucv.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index b3f5f840d067..fee22caf1bad 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c | |||
@@ -1112,24 +1112,31 @@ static void iucv_callback_txdone(struct iucv_path *path, | |||
1112 | struct iucv_message *msg) | 1112 | struct iucv_message *msg) |
1113 | { | 1113 | { |
1114 | struct sock *sk = path->private; | 1114 | struct sock *sk = path->private; |
1115 | struct sk_buff *this; | 1115 | struct sk_buff *this = NULL; |
1116 | struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q; | 1116 | struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q; |
1117 | struct sk_buff *list_skb = list->next; | 1117 | struct sk_buff *list_skb = list->next; |
1118 | unsigned long flags; | 1118 | unsigned long flags; |
1119 | 1119 | ||
1120 | if (list_skb) { | 1120 | if (!skb_queue_empty(list)) { |
1121 | spin_lock_irqsave(&list->lock, flags); | 1121 | spin_lock_irqsave(&list->lock, flags); |
1122 | 1122 | ||
1123 | do { | 1123 | while (list_skb != (struct sk_buff *)list) { |
1124 | this = list_skb; | 1124 | if (!memcmp(&msg->tag, list_skb->cb, 4)) { |
1125 | this = list_skb; | ||
1126 | break; | ||
1127 | } | ||
1125 | list_skb = list_skb->next; | 1128 | list_skb = list_skb->next; |
1126 | } while (memcmp(&msg->tag, this->cb, 4) && list_skb); | 1129 | } |
1127 | __skb_unlink(this, list); | 1130 | if (this) |
1131 | __skb_unlink(this, list); | ||
1128 | 1132 | ||
1129 | spin_unlock_irqrestore(&list->lock, flags); | 1133 | spin_unlock_irqrestore(&list->lock, flags); |
1130 | 1134 | ||
1131 | kfree_skb(this); | 1135 | if (this) |
1136 | kfree_skb(this); | ||
1132 | } | 1137 | } |
1138 | if (!this) | ||
1139 | printk(KERN_ERR "AF_IUCV msg tag %u not found\n", msg->tag); | ||
1133 | 1140 | ||
1134 | if (sk->sk_state == IUCV_CLOSING) { | 1141 | if (sk->sk_state == IUCV_CLOSING) { |
1135 | if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) { | 1142 | if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) { |