mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	dpll: rely on rcu for netdev_dpll_pin()
This fixes a possible UAF in if_nlmsg_size(),
which can run without RTNL.
Add rcu protection to "struct dpll_pin"
Move netdev_dpll_pin() from netdevice.h to dpll.h to
decrease name pollution.
Note: This looks possible to no longer acquire RTNL in
netdev_dpll_pin_assign() later in net-next.
v2: do not force rcu_read_lock() in rtnl_dpll_pin_size() (Jiri Pirko)
Fixes: 5f18426928 ("netdev: expose DPLL pin handle for netdevice")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>
Cc: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Reviewed-by: Jiri Pirko <jiri@nvidia.com>
Link: https://lore.kernel.org/r/20240223123208.3543319-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									0e67899abf
								
							
						
					
					
						commit
						0d60d8df6f
					
				
					 5 changed files with 16 additions and 12 deletions
				
			
		| 
						 | 
				
			
			@ -564,7 +564,7 @@ void dpll_pin_put(struct dpll_pin *pin)
 | 
			
		|||
		xa_destroy(&pin->parent_refs);
 | 
			
		||||
		xa_erase(&dpll_pin_xa, pin->id);
 | 
			
		||||
		dpll_pin_prop_free(&pin->prop);
 | 
			
		||||
		kfree(pin);
 | 
			
		||||
		kfree_rcu(pin, rcu);
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&dpll_lock);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -47,6 +47,7 @@ struct dpll_device {
 | 
			
		|||
 * @prop:		pin properties copied from the registerer
 | 
			
		||||
 * @rclk_dev_name:	holds name of device when pin can recover clock from it
 | 
			
		||||
 * @refcount:		refcount
 | 
			
		||||
 * @rcu:		rcu_head for kfree_rcu()
 | 
			
		||||
 **/
 | 
			
		||||
struct dpll_pin {
 | 
			
		||||
	u32 id;
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +58,7 @@ struct dpll_pin {
 | 
			
		|||
	struct xarray parent_refs;
 | 
			
		||||
	struct dpll_pin_properties prop;
 | 
			
		||||
	refcount_t refcount;
 | 
			
		||||
	struct rcu_head rcu;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,8 @@
 | 
			
		|||
#include <uapi/linux/dpll.h>
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
#include <linux/netlink.h>
 | 
			
		||||
#include <linux/netdevice.h>
 | 
			
		||||
#include <linux/rtnetlink.h>
 | 
			
		||||
 | 
			
		||||
struct dpll_device;
 | 
			
		||||
struct dpll_pin;
 | 
			
		||||
| 
						 | 
				
			
			@ -167,4 +169,13 @@ int dpll_device_change_ntf(struct dpll_device *dpll);
 | 
			
		|||
 | 
			
		||||
int dpll_pin_change_ntf(struct dpll_pin *pin);
 | 
			
		||||
 | 
			
		||||
static inline struct dpll_pin *netdev_dpll_pin(const struct net_device *dev)
 | 
			
		||||
{
 | 
			
		||||
#if IS_ENABLED(CONFIG_DPLL)
 | 
			
		||||
	return rcu_dereference_rtnl(dev->dpll_pin);
 | 
			
		||||
#else
 | 
			
		||||
	return NULL;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2469,7 +2469,7 @@ struct net_device {
 | 
			
		|||
	struct devlink_port	*devlink_port;
 | 
			
		||||
 | 
			
		||||
#if IS_ENABLED(CONFIG_DPLL)
 | 
			
		||||
	struct dpll_pin		*dpll_pin;
 | 
			
		||||
	struct dpll_pin	__rcu	*dpll_pin;
 | 
			
		||||
#endif
 | 
			
		||||
#if IS_ENABLED(CONFIG_PAGE_POOL)
 | 
			
		||||
	/** @page_pools: page pools created for this netdevice */
 | 
			
		||||
| 
						 | 
				
			
			@ -4035,15 +4035,6 @@ bool netdev_port_same_parent_id(struct net_device *a, struct net_device *b);
 | 
			
		|||
void netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin);
 | 
			
		||||
void netdev_dpll_pin_clear(struct net_device *dev);
 | 
			
		||||
 | 
			
		||||
static inline struct dpll_pin *netdev_dpll_pin(const struct net_device *dev)
 | 
			
		||||
{
 | 
			
		||||
#if IS_ENABLED(CONFIG_DPLL)
 | 
			
		||||
	return dev->dpll_pin;
 | 
			
		||||
#else
 | 
			
		||||
	return NULL;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev, bool *again);
 | 
			
		||||
struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 | 
			
		||||
				    struct netdev_queue *txq, int *ret);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9078,7 +9078,7 @@ static void netdev_dpll_pin_assign(struct net_device *dev, struct dpll_pin *dpll
 | 
			
		|||
{
 | 
			
		||||
#if IS_ENABLED(CONFIG_DPLL)
 | 
			
		||||
	rtnl_lock();
 | 
			
		||||
	dev->dpll_pin = dpll_pin;
 | 
			
		||||
	rcu_assign_pointer(dev->dpll_pin, dpll_pin);
 | 
			
		||||
	rtnl_unlock();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue