Skip to content

Commit

Permalink
Bluetooth: RFCOMM: Replace use of memcpy_from_msg with bt_skb_sendmmsg
Browse files Browse the repository at this point in the history
commit 81be03e upstream.

This makes use of bt_skb_sendmmsg instead using memcpy_from_msg which
is not considered safe to be used when lock_sock is held.

Also make rfcomm_dlc_send handle skb with fragments and queue them all
atomically.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Cc: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Vudentz authored and gregkh committed Jul 29, 2022
1 parent 1864e82 commit 367bece
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 43 deletions.
50 changes: 43 additions & 7 deletions net/bluetooth/rfcomm/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,22 +549,58 @@ struct rfcomm_dlc *rfcomm_dlc_exists(bdaddr_t *src, bdaddr_t *dst, u8 channel)
return dlc;
}

static int rfcomm_dlc_send_frag(struct rfcomm_dlc *d, struct sk_buff *frag)
{
int len = frag->len;

BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);

if (len > d->mtu)
return -EINVAL;

rfcomm_make_uih(frag, d->addr);
__skb_queue_tail(&d->tx_queue, frag);

return len;
}

int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
{
int len = skb->len;
unsigned long flags;
struct sk_buff *frag, *next;
int len;

if (d->state != BT_CONNECTED)
return -ENOTCONN;

BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
frag = skb_shinfo(skb)->frag_list;
skb_shinfo(skb)->frag_list = NULL;

if (len > d->mtu)
return -EINVAL;
/* Queue all fragments atomically. */
spin_lock_irqsave(&d->tx_queue.lock, flags);

rfcomm_make_uih(skb, d->addr);
skb_queue_tail(&d->tx_queue, skb);
len = rfcomm_dlc_send_frag(d, skb);
if (len < 0 || !frag)
goto unlock;

for (; frag; frag = next) {
int ret;

next = frag->next;

ret = rfcomm_dlc_send_frag(d, frag);
if (ret < 0) {
kfree_skb(frag);
goto unlock;
}

len += ret;
}

unlock:
spin_unlock_irqrestore(&d->tx_queue.lock, flags);

if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
if (len > 0 && !test_bit(RFCOMM_TX_THROTTLED, &d->flags))
rfcomm_schedule();
return len;
}
Expand Down
46 changes: 10 additions & 36 deletions net/bluetooth/rfcomm/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,46 +575,20 @@ static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg,
lock_sock(sk);

sent = bt_sock_wait_ready(sk, msg->msg_flags);
if (sent)
goto done;

while (len) {
size_t size = min_t(size_t, len, d->mtu);
int err;

skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb) {
if (sent == 0)
sent = err;
break;
}
skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);

err = memcpy_from_msg(skb_put(skb, size), msg, size);
if (err) {
kfree_skb(skb);
if (sent == 0)
sent = err;
break;
}

skb->priority = sk->sk_priority;
release_sock(sk);

err = rfcomm_dlc_send(d, skb);
if (err < 0) {
kfree_skb(skb);
if (sent == 0)
sent = err;
break;
}
if (sent)
return sent;

sent += size;
len -= size;
}
skb = bt_skb_sendmmsg(sk, msg, len, d->mtu, RFCOMM_SKB_HEAD_RESERVE,
RFCOMM_SKB_TAIL_RESERVE);
if (IS_ERR_OR_NULL(skb))
return PTR_ERR(skb);

done:
release_sock(sk);
sent = rfcomm_dlc_send(d, skb);
if (sent < 0)
kfree_skb(skb);

return sent;
}
Expand Down

0 comments on commit 367bece

Please sign in to comment.