mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-16 01:54:00 +00: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: 5f1842692880 ("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
@ -564,7 +564,7 @@ void dpll_pin_put(struct dpll_pin *pin)
|
|||||||
xa_destroy(&pin->parent_refs);
|
xa_destroy(&pin->parent_refs);
|
||||||
xa_erase(&dpll_pin_xa, pin->id);
|
xa_erase(&dpll_pin_xa, pin->id);
|
||||||
dpll_pin_prop_free(&pin->prop);
|
dpll_pin_prop_free(&pin->prop);
|
||||||
kfree(pin);
|
kfree_rcu(pin, rcu);
|
||||||
}
|
}
|
||||||
mutex_unlock(&dpll_lock);
|
mutex_unlock(&dpll_lock);
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ struct dpll_device {
|
|||||||
* @prop: pin properties copied from the registerer
|
* @prop: pin properties copied from the registerer
|
||||||
* @rclk_dev_name: holds name of device when pin can recover clock from it
|
* @rclk_dev_name: holds name of device when pin can recover clock from it
|
||||||
* @refcount: refcount
|
* @refcount: refcount
|
||||||
|
* @rcu: rcu_head for kfree_rcu()
|
||||||
**/
|
**/
|
||||||
struct dpll_pin {
|
struct dpll_pin {
|
||||||
u32 id;
|
u32 id;
|
||||||
@ -57,6 +58,7 @@ struct dpll_pin {
|
|||||||
struct xarray parent_refs;
|
struct xarray parent_refs;
|
||||||
struct dpll_pin_properties prop;
|
struct dpll_pin_properties prop;
|
||||||
refcount_t refcount;
|
refcount_t refcount;
|
||||||
|
struct rcu_head rcu;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
#include <uapi/linux/dpll.h>
|
#include <uapi/linux/dpll.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
struct dpll_device;
|
struct dpll_device;
|
||||||
struct dpll_pin;
|
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);
|
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
|
#endif
|
||||||
|
@ -2469,7 +2469,7 @@ struct net_device {
|
|||||||
struct devlink_port *devlink_port;
|
struct devlink_port *devlink_port;
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_DPLL)
|
#if IS_ENABLED(CONFIG_DPLL)
|
||||||
struct dpll_pin *dpll_pin;
|
struct dpll_pin __rcu *dpll_pin;
|
||||||
#endif
|
#endif
|
||||||
#if IS_ENABLED(CONFIG_PAGE_POOL)
|
#if IS_ENABLED(CONFIG_PAGE_POOL)
|
||||||
/** @page_pools: page pools created for this netdevice */
|
/** @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_set(struct net_device *dev, struct dpll_pin *dpll_pin);
|
||||||
void netdev_dpll_pin_clear(struct net_device *dev);
|
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 *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 sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
|
||||||
struct netdev_queue *txq, int *ret);
|
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)
|
#if IS_ENABLED(CONFIG_DPLL)
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
dev->dpll_pin = dpll_pin;
|
rcu_assign_pointer(dev->dpll_pin, dpll_pin);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user