1
0
Fork 0

iucv: Remove SKB list assumptions.

Eliminate the assumption that SKBs and SKB list heads can
be cast to eachother in SKB list handling code.

This change also appears to fix a bug since the list->next pointer is
sampled outside of holding the SKB queue lock.

Signed-off-by: David S. Miller <davem@davemloft.net>
hifive-unleashed-5.1
David S. Miller 2018-08-22 17:01:51 -07:00
parent 4a5a553dde
commit 9e733177c7
1 changed files with 15 additions and 26 deletions

View File

@ -1873,30 +1873,26 @@ static void iucv_callback_txdone(struct iucv_path *path,
struct sock *sk = path->private; struct sock *sk = path->private;
struct sk_buff *this = NULL; struct sk_buff *this = NULL;
struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q; struct sk_buff_head *list = &iucv_sk(sk)->send_skb_q;
struct sk_buff *list_skb = list->next; struct sk_buff *list_skb;
unsigned long flags; unsigned long flags;
bh_lock_sock(sk); bh_lock_sock(sk);
if (!skb_queue_empty(list)) {
spin_lock_irqsave(&list->lock, flags);
while (list_skb != (struct sk_buff *)list) { spin_lock_irqsave(&list->lock, flags);
if (msg->tag == IUCV_SKB_CB(list_skb)->tag) { skb_queue_walk(list, list_skb) {
this = list_skb; if (msg->tag == IUCV_SKB_CB(list_skb)->tag) {
break; this = list_skb;
} break;
list_skb = list_skb->next;
} }
if (this) }
__skb_unlink(this, list); if (this)
__skb_unlink(this, list);
spin_unlock_irqrestore(&list->lock, flags);
spin_unlock_irqrestore(&list->lock, flags); if (this) {
kfree_skb(this);
if (this) { /* wake up any process waiting for sending */
kfree_skb(this); iucv_sock_wake_msglim(sk);
/* wake up any process waiting for sending */
iucv_sock_wake_msglim(sk);
}
} }
if (sk->sk_state == IUCV_CLOSING) { if (sk->sk_state == IUCV_CLOSING) {
@ -2284,11 +2280,7 @@ static void afiucv_hs_callback_txnotify(struct sk_buff *skb,
list = &iucv->send_skb_q; list = &iucv->send_skb_q;
spin_lock_irqsave(&list->lock, flags); spin_lock_irqsave(&list->lock, flags);
if (skb_queue_empty(list)) skb_queue_walk_safe(list, list_skb, nskb) {
goto out_unlock;
list_skb = list->next;
nskb = list_skb->next;
while (list_skb != (struct sk_buff *)list) {
if (skb_shinfo(list_skb) == skb_shinfo(skb)) { if (skb_shinfo(list_skb) == skb_shinfo(skb)) {
switch (n) { switch (n) {
case TX_NOTIFY_OK: case TX_NOTIFY_OK:
@ -2321,10 +2313,7 @@ static void afiucv_hs_callback_txnotify(struct sk_buff *skb,
} }
break; break;
} }
list_skb = nskb;
nskb = nskb->next;
} }
out_unlock:
spin_unlock_irqrestore(&list->lock, flags); spin_unlock_irqrestore(&list->lock, flags);
if (sk->sk_state == IUCV_CLOSING) { if (sk->sk_state == IUCV_CLOSING) {