Skip to content

usb: gadget: f_ncm: Fix Kernel Panic due to access of invalid gadget ptr

Should help with #495 (closed), #496 (closed), #497 (closed), #498 (closed), #499 (closed), OS-issues#349 (closed), OS-issues#351 (closed)

Draft because I'm occasionally experiencing the phone not being able to resume from suspend and I'm not yet sure whether it's related or not.

Taken from https://lore.kernel.org/linux-usb/20240307161849.9145-1-hgajjar@de.adit-jv.com/


In the scenario where the system enters suspend to RAM mode (STR) triggers the disconnection of Dual Role USB Hub, and the UDC platform driver calls usb_del_gadget_udc() to cleanup and delete the associated gadget.

However, at this point, the usb0 interface is not yet deleted, leading to a race condition with the TCP/IP stack attempting to access the network device parent (gadget pointer), through operations like the GETLINK net message.

This patch addresses the issue by clearing the netdevice's parent device pointer when the ncm unbinds, effectively preventing the race condition during this critical phase.

Followinfg is the backtrace of such race condition

[ 3566.105792] Call trace:
[ 3566.105984] if_nlmsg_size+0x48/0x3b0
[ 3566.107497] rtnetlink_rcv_msg+0x1cc/0x408
[ 3566.107905] netlink_rcv_skb+0x12c/0x164
[ 3566.108264] rtnetlink_rcv+0x18/0x24
[ 3566.108851] netlink_unicast_kernel+0xc4/0x14c
[ 3566.109192] netlink_unicast+0x210/0x2b0
[ 3566.109606] netlink_sendmsg+0x2ec/0x360
[ 3566.110046] __sys_sendto+0x1b8/0x25c
[ 3566.111594] __arm64_sys_sendto+0x28/0x38
[ 3566.112599] el0_svc_common+0xb4/0x19c
[ 3566.112978] el0_svc_handler+0x74/0x98
[ 3566.113269] el0_svc+0x8/0xc
  • code: if_nlmsg_size call the following function
static inline int rtnl_vfinfo_size(const struct net_device *dev,
				   u32 ext_filter_mask)
{
	// dev->dev.parent is not NULL
	if (dev->dev.parent && (ext_filter_mask & RTEXT_FILTER_VF)) {
		// dev_num_vf use the dev->dev.parent->bus lead to kernel panic.
		int num_vfs = dev_num_vf(dev->dev.parent);
		size_t size = nla_total_size(0);
		size += num_vfs *
			(nla_total_size(0) +
			 nla_total_size(sizeof(struct ifla_vf_mac)) +
			 nla_total_size(sizeof(struct ifla_vf_vlan)) +
			 nla_total_size(0) + /* nest IFLA_VF_VLAN_LIST *

Signed-off-by: Hardik Gajjar hgajjar@de.adit-jv.com

Edited by Sebastian Krzyszkowiak

Merge request reports