Skip to content

Commit

Permalink
Merge tag 'linux-can-fixes-for-5.13-20210616' of git://git.kernel.org…
Browse files Browse the repository at this point in the history
…/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2021-06-16

this is a pull request of 4 patches for net/master.

The first patch is by Oleksij Rempel and fixes a Use-after-Free found
by syzbot in the j1939 stack.

The next patch is by Tetsuo Handa and fixes hung task detected by
syzbot in the bcm, raw and isotp protocols.

Norbert Slusarek's patch fixes a infoleak in bcm's struct
bcm_msg_head.

Pavel Skripkin's patch fixes a memory leak in the mcba_usb driver.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Jun 16, 2021
2 parents d8e2973 + 91c0255 commit e82a35a
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 56 deletions.
17 changes: 15 additions & 2 deletions drivers/net/can/usb/mcba_usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ struct mcba_priv {
bool can_ka_first_pass;
bool can_speed_check;
atomic_t free_ctx_cnt;
void *rxbuf[MCBA_MAX_RX_URBS];
dma_addr_t rxbuf_dma[MCBA_MAX_RX_URBS];
};

/* CAN frame */
Expand Down Expand Up @@ -633,6 +635,7 @@ static int mcba_usb_start(struct mcba_priv *priv)
for (i = 0; i < MCBA_MAX_RX_URBS; i++) {
struct urb *urb = NULL;
u8 *buf;
dma_addr_t buf_dma;

/* create a URB, and a buffer for it */
urb = usb_alloc_urb(0, GFP_KERNEL);
Expand All @@ -642,7 +645,7 @@ static int mcba_usb_start(struct mcba_priv *priv)
}

buf = usb_alloc_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
GFP_KERNEL, &urb->transfer_dma);
GFP_KERNEL, &buf_dma);
if (!buf) {
netdev_err(netdev, "No memory left for USB buffer\n");
usb_free_urb(urb);
Expand All @@ -661,11 +664,14 @@ static int mcba_usb_start(struct mcba_priv *priv)
if (err) {
usb_unanchor_urb(urb);
usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
buf, urb->transfer_dma);
buf, buf_dma);
usb_free_urb(urb);
break;
}

priv->rxbuf[i] = buf;
priv->rxbuf_dma[i] = buf_dma;

/* Drop reference, USB core will take care of freeing it */
usb_free_urb(urb);
}
Expand Down Expand Up @@ -708,7 +714,14 @@ static int mcba_usb_open(struct net_device *netdev)

static void mcba_urb_unlink(struct mcba_priv *priv)
{
int i;

usb_kill_anchored_urbs(&priv->rx_submitted);

for (i = 0; i < MCBA_MAX_RX_URBS; ++i)
usb_free_coherent(priv->udev, MCBA_USB_RX_BUFF_SIZE,
priv->rxbuf[i], priv->rxbuf_dma[i]);

usb_kill_anchored_urbs(&priv->tx_submitted);
}

Expand Down
62 changes: 49 additions & 13 deletions net/can/bcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,18 @@ struct bcm_sock {
struct sock sk;
int bound;
int ifindex;
struct notifier_block notifier;
struct list_head notifier;
struct list_head rx_ops;
struct list_head tx_ops;
unsigned long dropped_usr_msgs;
struct proc_dir_entry *bcm_proc_read;
char procname [32]; /* inode number in decimal with \0 */
};

static LIST_HEAD(bcm_notifier_list);
static DEFINE_SPINLOCK(bcm_notifier_lock);
static struct bcm_sock *bcm_busy_notifier;

static inline struct bcm_sock *bcm_sk(const struct sock *sk)
{
return (struct bcm_sock *)sk;
Expand Down Expand Up @@ -402,6 +406,7 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
if (!op->count && (op->flags & TX_COUNTEVT)) {

/* create notification to user */
memset(&msg_head, 0, sizeof(msg_head));
msg_head.opcode = TX_EXPIRED;
msg_head.flags = op->flags;
msg_head.count = op->count;
Expand Down Expand Up @@ -439,6 +444,7 @@ static void bcm_rx_changed(struct bcm_op *op, struct canfd_frame *data)
/* this element is not throttled anymore */
data->flags &= (BCM_CAN_FLAGS_MASK|RX_RECV);

memset(&head, 0, sizeof(head));
head.opcode = RX_CHANGED;
head.flags = op->flags;
head.count = op->count;
Expand Down Expand Up @@ -560,6 +566,7 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
}

/* create notification to user */
memset(&msg_head, 0, sizeof(msg_head));
msg_head.opcode = RX_TIMEOUT;
msg_head.flags = op->flags;
msg_head.count = op->count;
Expand Down Expand Up @@ -1378,20 +1385,15 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
/*
* notification handler for netdevice status changes
*/
static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
void *ptr)
static void bcm_notify(struct bcm_sock *bo, unsigned long msg,
struct net_device *dev)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct bcm_sock *bo = container_of(nb, struct bcm_sock, notifier);
struct sock *sk = &bo->sk;
struct bcm_op *op;
int notify_enodev = 0;

if (!net_eq(dev_net(dev), sock_net(sk)))
return NOTIFY_DONE;

if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
return;

switch (msg) {

Expand Down Expand Up @@ -1426,7 +1428,28 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
sk->sk_error_report(sk);
}
}
}

static int bcm_notifier(struct notifier_block *nb, unsigned long msg,
void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);

if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
if (unlikely(bcm_busy_notifier)) /* Check for reentrant bug. */
return NOTIFY_DONE;

spin_lock(&bcm_notifier_lock);
list_for_each_entry(bcm_busy_notifier, &bcm_notifier_list, notifier) {
spin_unlock(&bcm_notifier_lock);
bcm_notify(bcm_busy_notifier, msg, dev);
spin_lock(&bcm_notifier_lock);
}
bcm_busy_notifier = NULL;
spin_unlock(&bcm_notifier_lock);
return NOTIFY_DONE;
}

Expand All @@ -1446,9 +1469,9 @@ static int bcm_init(struct sock *sk)
INIT_LIST_HEAD(&bo->rx_ops);

/* set notifier */
bo->notifier.notifier_call = bcm_notifier;

register_netdevice_notifier(&bo->notifier);
spin_lock(&bcm_notifier_lock);
list_add_tail(&bo->notifier, &bcm_notifier_list);
spin_unlock(&bcm_notifier_lock);

return 0;
}
Expand All @@ -1471,7 +1494,14 @@ static int bcm_release(struct socket *sock)

/* remove bcm_ops, timer, rx_unregister(), etc. */

unregister_netdevice_notifier(&bo->notifier);
spin_lock(&bcm_notifier_lock);
while (bcm_busy_notifier == bo) {
spin_unlock(&bcm_notifier_lock);
schedule_timeout_uninterruptible(1);
spin_lock(&bcm_notifier_lock);
}
list_del(&bo->notifier);
spin_unlock(&bcm_notifier_lock);

lock_sock(sk);

Expand Down Expand Up @@ -1692,6 +1722,10 @@ static struct pernet_operations canbcm_pernet_ops __read_mostly = {
.exit = canbcm_pernet_exit,
};

static struct notifier_block canbcm_notifier = {
.notifier_call = bcm_notifier
};

static int __init bcm_module_init(void)
{
int err;
Expand All @@ -1705,12 +1739,14 @@ static int __init bcm_module_init(void)
}

register_pernet_subsys(&canbcm_pernet_ops);
register_netdevice_notifier(&canbcm_notifier);
return 0;
}

static void __exit bcm_module_exit(void)
{
can_proto_unregister(&bcm_can_proto);
unregister_netdevice_notifier(&canbcm_notifier);
unregister_pernet_subsys(&canbcm_pernet_ops);
}

Expand Down
61 changes: 48 additions & 13 deletions net/can/isotp.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,14 @@ struct isotp_sock {
u32 force_tx_stmin;
u32 force_rx_stmin;
struct tpcon rx, tx;
struct notifier_block notifier;
struct list_head notifier;
wait_queue_head_t wait;
};

static LIST_HEAD(isotp_notifier_list);
static DEFINE_SPINLOCK(isotp_notifier_lock);
static struct isotp_sock *isotp_busy_notifier;

static inline struct isotp_sock *isotp_sk(const struct sock *sk)
{
return (struct isotp_sock *)sk;
Expand Down Expand Up @@ -1013,7 +1017,14 @@ static int isotp_release(struct socket *sock)
/* wait for complete transmission of current pdu */
wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);

unregister_netdevice_notifier(&so->notifier);
spin_lock(&isotp_notifier_lock);
while (isotp_busy_notifier == so) {
spin_unlock(&isotp_notifier_lock);
schedule_timeout_uninterruptible(1);
spin_lock(&isotp_notifier_lock);
}
list_del(&so->notifier);
spin_unlock(&isotp_notifier_lock);

lock_sock(sk);

Expand Down Expand Up @@ -1317,21 +1328,16 @@ static int isotp_getsockopt(struct socket *sock, int level, int optname,
return 0;
}

static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
void *ptr)
static void isotp_notify(struct isotp_sock *so, unsigned long msg,
struct net_device *dev)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct isotp_sock *so = container_of(nb, struct isotp_sock, notifier);
struct sock *sk = &so->sk;

if (!net_eq(dev_net(dev), sock_net(sk)))
return NOTIFY_DONE;

if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
return;

if (so->ifindex != dev->ifindex)
return NOTIFY_DONE;
return;

switch (msg) {
case NETDEV_UNREGISTER:
Expand All @@ -1357,7 +1363,28 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
sk->sk_error_report(sk);
break;
}
}

static int isotp_notifier(struct notifier_block *nb, unsigned long msg,
void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);

if (dev->type != ARPHRD_CAN)
return NOTIFY_DONE;
if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN)
return NOTIFY_DONE;
if (unlikely(isotp_busy_notifier)) /* Check for reentrant bug. */
return NOTIFY_DONE;

spin_lock(&isotp_notifier_lock);
list_for_each_entry(isotp_busy_notifier, &isotp_notifier_list, notifier) {
spin_unlock(&isotp_notifier_lock);
isotp_notify(isotp_busy_notifier, msg, dev);
spin_lock(&isotp_notifier_lock);
}
isotp_busy_notifier = NULL;
spin_unlock(&isotp_notifier_lock);
return NOTIFY_DONE;
}

Expand Down Expand Up @@ -1394,8 +1421,9 @@ static int isotp_init(struct sock *sk)

init_waitqueue_head(&so->wait);

so->notifier.notifier_call = isotp_notifier;
register_netdevice_notifier(&so->notifier);
spin_lock(&isotp_notifier_lock);
list_add_tail(&so->notifier, &isotp_notifier_list);
spin_unlock(&isotp_notifier_lock);

return 0;
}
Expand Down Expand Up @@ -1442,6 +1470,10 @@ static const struct can_proto isotp_can_proto = {
.prot = &isotp_proto,
};

static struct notifier_block canisotp_notifier = {
.notifier_call = isotp_notifier
};

static __init int isotp_module_init(void)
{
int err;
Expand All @@ -1451,13 +1483,16 @@ static __init int isotp_module_init(void)
err = can_proto_register(&isotp_can_proto);
if (err < 0)
pr_err("can: registration of isotp protocol failed\n");
else
register_netdevice_notifier(&canisotp_notifier);

return err;
}

static __exit void isotp_module_exit(void)
{
can_proto_unregister(&isotp_can_proto);
unregister_netdevice_notifier(&canisotp_notifier);
}

module_init(isotp_module_init);
Expand Down
Loading

0 comments on commit e82a35a

Please sign in to comment.