Commit 936fd2c5 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'linux-can-fixes-for-6.5-20230717' of...

Merge tag 'linux-can-fixes-for-6.5-20230717' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can

Marc Kleine-Budde says:

====================
pull-request: can 2023-07-17

The 1st patch is by Ziyang Xuan and fixes a possible memory leak in
the receiver handling in the CAN RAW protocol.

YueHaibing contributes a use after free in bcm_proc_show() of the
Broad Cast Manager (BCM) CAN protocol.

The next 2 patches are by me and fix a possible null pointer
dereference in the RX path of the gs_usb driver with activated
hardware timestamps and the candlelight firmware.

The last patch is by Fedor Ross, Marek Vasut and me and targets the
mcp251xfd driver. The polling timeout of __mcp251xfd_chip_set_mode()
is increased to fix bus joining on busy CAN buses and very low bit
rate.

* tag 'linux-can-fixes-for-6.5-20230717' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can:
  can: mcp251xfd: __mcp251xfd_chip_set_mode(): increase poll timeout
  can: gs_usb: fix time stamp counter initialization
  can: gs_usb: gs_can_open(): improve error handling
  can: bcm: Fix UAF in bcm_proc_show()
  can: raw: fix receiver memory leak
====================

Link: https://lore.kernel.org/r/20230717180938.230816-1-mkl@pengutronix.de


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 195e903b 9efa1a54
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -227,6 +227,8 @@ static int
__mcp251xfd_chip_set_mode(const struct mcp251xfd_priv *priv,
			  const u8 mode_req, bool nowait)
{
	const struct can_bittiming *bt = &priv->can.bittiming;
	unsigned long timeout_us = MCP251XFD_POLL_TIMEOUT_US;
	u32 con = 0, con_reqop, osc = 0;
	u8 mode;
	int err;
@@ -246,12 +248,16 @@ __mcp251xfd_chip_set_mode(const struct mcp251xfd_priv *priv,
	if (mode_req == MCP251XFD_REG_CON_MODE_SLEEP || nowait)
		return 0;

	if (bt->bitrate)
		timeout_us = max_t(unsigned long, timeout_us,
				   MCP251XFD_FRAME_LEN_MAX_BITS * USEC_PER_SEC /
				   bt->bitrate);

	err = regmap_read_poll_timeout(priv->map_reg, MCP251XFD_REG_CON, con,
				       !mcp251xfd_reg_invalid(con) &&
				       FIELD_GET(MCP251XFD_REG_CON_OPMOD_MASK,
						 con) == mode_req,
				       MCP251XFD_POLL_SLEEP_US,
				       MCP251XFD_POLL_TIMEOUT_US);
				       MCP251XFD_POLL_SLEEP_US, timeout_us);
	if (err != -ETIMEDOUT && err != -EBADMSG)
		return err;

+1 −0
Original line number Diff line number Diff line
@@ -387,6 +387,7 @@ static_assert(MCP251XFD_TIMESTAMP_WORK_DELAY_SEC <
#define MCP251XFD_OSC_STAB_TIMEOUT_US (10 * MCP251XFD_OSC_STAB_SLEEP_US)
#define MCP251XFD_POLL_SLEEP_US (10)
#define MCP251XFD_POLL_TIMEOUT_US (USEC_PER_MSEC)
#define MCP251XFD_FRAME_LEN_MAX_BITS (736)

/* Misc */
#define MCP251XFD_NAPI_WEIGHT 32
+74 −56
Original line number Diff line number Diff line
@@ -303,12 +303,6 @@ struct gs_can {
	struct can_bittiming_const bt_const, data_bt_const;
	unsigned int channel;	/* channel number */

	/* time counter for hardware timestamps */
	struct cyclecounter cc;
	struct timecounter tc;
	spinlock_t tc_lock; /* spinlock to guard access tc->cycle_last */
	struct delayed_work timestamp;

	u32 feature;
	unsigned int hf_size_tx;

@@ -325,6 +319,13 @@ struct gs_usb {
	struct gs_can *canch[GS_MAX_INTF];
	struct usb_anchor rx_submitted;
	struct usb_device *udev;

	/* time counter for hardware timestamps */
	struct cyclecounter cc;
	struct timecounter tc;
	spinlock_t tc_lock; /* spinlock to guard access tc->cycle_last */
	struct delayed_work timestamp;

	unsigned int hf_size_rx;
	u8 active_channels;
};
@@ -388,15 +389,15 @@ static int gs_cmd_reset(struct gs_can *dev)
				    GFP_KERNEL);
}

static inline int gs_usb_get_timestamp(const struct gs_can *dev,
static inline int gs_usb_get_timestamp(const struct gs_usb *parent,
				       u32 *timestamp_p)
{
	__le32 timestamp;
	int rc;

	rc = usb_control_msg_recv(dev->udev, 0, GS_USB_BREQ_TIMESTAMP,
	rc = usb_control_msg_recv(parent->udev, 0, GS_USB_BREQ_TIMESTAMP,
				  USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
				  dev->channel, 0,
				  0, 0,
				  &timestamp, sizeof(timestamp),
				  USB_CTRL_GET_TIMEOUT,
				  GFP_KERNEL);
@@ -410,18 +411,18 @@ static inline int gs_usb_get_timestamp(const struct gs_can *dev,

static u64 gs_usb_timestamp_read(const struct cyclecounter *cc) __must_hold(&dev->tc_lock)
{
	struct gs_can *dev = container_of(cc, struct gs_can, cc);
	struct gs_usb *parent = container_of(cc, struct gs_usb, cc);
	u32 timestamp = 0;
	int err;

	lockdep_assert_held(&dev->tc_lock);
	lockdep_assert_held(&parent->tc_lock);

	/* drop lock for synchronous USB transfer */
	spin_unlock_bh(&dev->tc_lock);
	err = gs_usb_get_timestamp(dev, &timestamp);
	spin_lock_bh(&dev->tc_lock);
	spin_unlock_bh(&parent->tc_lock);
	err = gs_usb_get_timestamp(parent, &timestamp);
	spin_lock_bh(&parent->tc_lock);
	if (err)
		netdev_err(dev->netdev,
		dev_err(&parent->udev->dev,
			"Error %d while reading timestamp. HW timestamps may be inaccurate.",
			err);

@@ -431,14 +432,14 @@ static u64 gs_usb_timestamp_read(const struct cyclecounter *cc) __must_hold(&dev
static void gs_usb_timestamp_work(struct work_struct *work)
{
	struct delayed_work *delayed_work = to_delayed_work(work);
	struct gs_can *dev;
	struct gs_usb *parent;

	dev = container_of(delayed_work, struct gs_can, timestamp);
	spin_lock_bh(&dev->tc_lock);
	timecounter_read(&dev->tc);
	spin_unlock_bh(&dev->tc_lock);
	parent = container_of(delayed_work, struct gs_usb, timestamp);
	spin_lock_bh(&parent->tc_lock);
	timecounter_read(&parent->tc);
	spin_unlock_bh(&parent->tc_lock);

	schedule_delayed_work(&dev->timestamp,
	schedule_delayed_work(&parent->timestamp,
			      GS_USB_TIMESTAMP_WORK_DELAY_SEC * HZ);
}

@@ -446,37 +447,38 @@ static void gs_usb_skb_set_timestamp(struct gs_can *dev,
				     struct sk_buff *skb, u32 timestamp)
{
	struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
	struct gs_usb *parent = dev->parent;
	u64 ns;

	spin_lock_bh(&dev->tc_lock);
	ns = timecounter_cyc2time(&dev->tc, timestamp);
	spin_unlock_bh(&dev->tc_lock);
	spin_lock_bh(&parent->tc_lock);
	ns = timecounter_cyc2time(&parent->tc, timestamp);
	spin_unlock_bh(&parent->tc_lock);

	hwtstamps->hwtstamp = ns_to_ktime(ns);
}

static void gs_usb_timestamp_init(struct gs_can *dev)
static void gs_usb_timestamp_init(struct gs_usb *parent)
{
	struct cyclecounter *cc = &dev->cc;
	struct cyclecounter *cc = &parent->cc;

	cc->read = gs_usb_timestamp_read;
	cc->mask = CYCLECOUNTER_MASK(32);
	cc->shift = 32 - bits_per(NSEC_PER_SEC / GS_USB_TIMESTAMP_TIMER_HZ);
	cc->mult = clocksource_hz2mult(GS_USB_TIMESTAMP_TIMER_HZ, cc->shift);

	spin_lock_init(&dev->tc_lock);
	spin_lock_bh(&dev->tc_lock);
	timecounter_init(&dev->tc, &dev->cc, ktime_get_real_ns());
	spin_unlock_bh(&dev->tc_lock);
	spin_lock_init(&parent->tc_lock);
	spin_lock_bh(&parent->tc_lock);
	timecounter_init(&parent->tc, &parent->cc, ktime_get_real_ns());
	spin_unlock_bh(&parent->tc_lock);

	INIT_DELAYED_WORK(&dev->timestamp, gs_usb_timestamp_work);
	schedule_delayed_work(&dev->timestamp,
	INIT_DELAYED_WORK(&parent->timestamp, gs_usb_timestamp_work);
	schedule_delayed_work(&parent->timestamp,
			      GS_USB_TIMESTAMP_WORK_DELAY_SEC * HZ);
}

static void gs_usb_timestamp_stop(struct gs_can *dev)
static void gs_usb_timestamp_stop(struct gs_usb *parent)
{
	cancel_delayed_work_sync(&dev->timestamp);
	cancel_delayed_work_sync(&parent->timestamp);
}

static void gs_update_state(struct gs_can *dev, struct can_frame *cf)
@@ -560,6 +562,9 @@ static void gs_usb_receive_bulk_callback(struct urb *urb)
	if (!netif_device_present(netdev))
		return;

	if (!netif_running(netdev))
		goto resubmit_urb;

	if (hf->echo_id == -1) { /* normal rx */
		if (hf->flags & GS_CAN_FLAG_FD) {
			skb = alloc_canfd_skb(dev->netdev, &cfd);
@@ -833,6 +838,7 @@ static int gs_can_open(struct net_device *netdev)
		.mode = cpu_to_le32(GS_CAN_MODE_START),
	};
	struct gs_host_frame *hf;
	struct urb *urb = NULL;
	u32 ctrlmode;
	u32 flags = 0;
	int rc, i;
@@ -855,14 +861,18 @@ static int gs_can_open(struct net_device *netdev)
	}

	if (!parent->active_channels) {
		if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
			gs_usb_timestamp_init(parent);

		for (i = 0; i < GS_MAX_RX_URBS; i++) {
			struct urb *urb;
			u8 *buf;

			/* alloc rx urb */
			urb = usb_alloc_urb(0, GFP_KERNEL);
			if (!urb)
				return -ENOMEM;
			if (!urb) {
				rc = -ENOMEM;
				goto out_usb_kill_anchored_urbs;
			}

			/* alloc rx buffer */
			buf = kmalloc(dev->parent->hf_size_rx,
@@ -870,8 +880,8 @@ static int gs_can_open(struct net_device *netdev)
			if (!buf) {
				netdev_err(netdev,
					   "No memory left for USB buffer\n");
				usb_free_urb(urb);
				return -ENOMEM;
				rc = -ENOMEM;
				goto out_usb_free_urb;
			}

			/* fill, anchor, and submit rx urb */
@@ -894,9 +904,7 @@ static int gs_can_open(struct net_device *netdev)
				netdev_err(netdev,
					   "usb_submit failed (err=%d)\n", rc);

				usb_unanchor_urb(urb);
				usb_free_urb(urb);
				break;
				goto out_usb_unanchor_urb;
			}

			/* Drop reference,
@@ -926,13 +934,9 @@ static int gs_can_open(struct net_device *netdev)
		flags |= GS_CAN_MODE_FD;

	/* if hardware supports timestamps, enable it */
	if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP) {
	if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
		flags |= GS_CAN_MODE_HW_TIMESTAMP;

		/* start polling timestamp */
		gs_usb_timestamp_init(dev);
	}

	/* finally start device */
	dev->can.state = CAN_STATE_ERROR_ACTIVE;
	dm.flags = cpu_to_le32(flags);
@@ -942,10 +946,9 @@ static int gs_can_open(struct net_device *netdev)
				  GFP_KERNEL);
	if (rc) {
		netdev_err(netdev, "Couldn't start device (err=%d)\n", rc);
		if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
			gs_usb_timestamp_stop(dev);
		dev->can.state = CAN_STATE_STOPPED;
		return rc;

		goto out_usb_kill_anchored_urbs;
	}

	parent->active_channels++;
@@ -953,6 +956,22 @@ static int gs_can_open(struct net_device *netdev)
		netif_start_queue(netdev);

	return 0;

out_usb_unanchor_urb:
	usb_unanchor_urb(urb);
out_usb_free_urb:
	usb_free_urb(urb);
out_usb_kill_anchored_urbs:
	if (!parent->active_channels) {
		usb_kill_anchored_urbs(&dev->tx_submitted);

		if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
			gs_usb_timestamp_stop(parent);
	}

	close_candev(netdev);

	return rc;
}

static int gs_usb_get_state(const struct net_device *netdev,
@@ -998,14 +1017,13 @@ static int gs_can_close(struct net_device *netdev)

	netif_stop_queue(netdev);

	/* stop polling timestamp */
	if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
		gs_usb_timestamp_stop(dev);

	/* Stop polling */
	parent->active_channels--;
	if (!parent->active_channels) {
		usb_kill_anchored_urbs(&parent->rx_submitted);

		if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
			gs_usb_timestamp_stop(parent);
	}

	/* Stop sending URBs */
+6 −6
Original line number Diff line number Diff line
@@ -1526,6 +1526,12 @@ static int bcm_release(struct socket *sock)

	lock_sock(sk);

#if IS_ENABLED(CONFIG_PROC_FS)
	/* remove procfs entry */
	if (net->can.bcmproc_dir && bo->bcm_proc_read)
		remove_proc_entry(bo->procname, net->can.bcmproc_dir);
#endif /* CONFIG_PROC_FS */

	list_for_each_entry_safe(op, next, &bo->tx_ops, list)
		bcm_remove_op(op);

@@ -1561,12 +1567,6 @@ static int bcm_release(struct socket *sock)
	list_for_each_entry_safe(op, next, &bo->rx_ops, list)
		bcm_remove_op(op);

#if IS_ENABLED(CONFIG_PROC_FS)
	/* remove procfs entry */
	if (net->can.bcmproc_dir && bo->bcm_proc_read)
		remove_proc_entry(bo->procname, net->can.bcmproc_dir);
#endif /* CONFIG_PROC_FS */

	/* remove device reference */
	if (bo->bound) {
		bo->bound   = 0;
+24 −33
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@ struct raw_sock {
	struct sock sk;
	int bound;
	int ifindex;
	struct net_device *dev;
	struct list_head notifier;
	int loopback;
	int recv_own_msgs;
@@ -277,7 +278,7 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,
	if (!net_eq(dev_net(dev), sock_net(sk)))
		return;

	if (ro->ifindex != dev->ifindex)
	if (ro->dev != dev)
		return;

	switch (msg) {
@@ -292,6 +293,7 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,

		ro->ifindex = 0;
		ro->bound = 0;
		ro->dev = NULL;
		ro->count = 0;
		release_sock(sk);

@@ -337,6 +339,7 @@ static int raw_init(struct sock *sk)

	ro->bound            = 0;
	ro->ifindex          = 0;
	ro->dev              = NULL;

	/* set default filter to single entry dfilter */
	ro->dfilter.can_id   = 0;
@@ -385,28 +388,24 @@ static int raw_release(struct socket *sock)

	lock_sock(sk);

	rtnl_lock();
	/* remove current filters & unregister */
	if (ro->bound) {
		if (ro->ifindex) {
			struct net_device *dev;

			dev = dev_get_by_index(sock_net(sk), ro->ifindex);
			if (dev) {
				raw_disable_allfilters(dev_net(dev), dev, sk);
				dev_put(dev);
			}
		} else {
		if (ro->dev)
			raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk);
		else
			raw_disable_allfilters(sock_net(sk), NULL, sk);
	}
	}

	if (ro->count > 1)
		kfree(ro->filter);

	ro->ifindex = 0;
	ro->bound = 0;
	ro->dev = NULL;
	ro->count = 0;
	free_percpu(ro->uniq);
	rtnl_unlock();

	sock_orphan(sk);
	sock->sk = NULL;
@@ -422,6 +421,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
	struct sock *sk = sock->sk;
	struct raw_sock *ro = raw_sk(sk);
	struct net_device *dev = NULL;
	int ifindex;
	int err = 0;
	int notify_enetdown = 0;
@@ -431,14 +431,13 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
	if (addr->can_family != AF_CAN)
		return -EINVAL;

	rtnl_lock();
	lock_sock(sk);

	if (ro->bound && addr->can_ifindex == ro->ifindex)
		goto out;

	if (addr->can_ifindex) {
		struct net_device *dev;

		dev = dev_get_by_index(sock_net(sk), addr->can_ifindex);
		if (!dev) {
			err = -ENODEV;
@@ -467,26 +466,20 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
	if (!err) {
		if (ro->bound) {
			/* unregister old filters */
			if (ro->ifindex) {
				struct net_device *dev;

				dev = dev_get_by_index(sock_net(sk),
						       ro->ifindex);
				if (dev) {
					raw_disable_allfilters(dev_net(dev),
							       dev, sk);
					dev_put(dev);
				}
			} else {
			if (ro->dev)
				raw_disable_allfilters(dev_net(ro->dev),
						       ro->dev, sk);
			else
				raw_disable_allfilters(sock_net(sk), NULL, sk);
		}
		}
		ro->ifindex = ifindex;
		ro->bound = 1;
		ro->dev = dev;
	}

 out:
	release_sock(sk);
	rtnl_unlock();

	if (notify_enetdown) {
		sk->sk_err = ENETDOWN;
@@ -553,9 +546,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
		rtnl_lock();
		lock_sock(sk);

		if (ro->bound && ro->ifindex) {
			dev = dev_get_by_index(sock_net(sk), ro->ifindex);
			if (!dev) {
		dev = ro->dev;
		if (ro->bound && dev) {
			if (dev->reg_state != NETREG_REGISTERED) {
				if (count > 1)
					kfree(filter);
				err = -ENODEV;
@@ -596,7 +589,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
		ro->count  = count;

 out_fil:
		dev_put(dev);
		release_sock(sk);
		rtnl_unlock();

@@ -614,9 +606,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
		rtnl_lock();
		lock_sock(sk);

		if (ro->bound && ro->ifindex) {
			dev = dev_get_by_index(sock_net(sk), ro->ifindex);
			if (!dev) {
		dev = ro->dev;
		if (ro->bound && dev) {
			if (dev->reg_state != NETREG_REGISTERED) {
				err = -ENODEV;
				goto out_err;
			}
@@ -640,7 +632,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
		ro->err_mask = err_mask;

 out_err:
		dev_put(dev);
		release_sock(sk);
		rtnl_unlock();