Skip to content

Commit 0d60d8d

Browse files
edumazetkuba-moo
authored andcommitted
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: 5f18426 ("netdev: expose DPLL pin handle for netdevice") Signed-off-by: Eric Dumazet <[email protected]> Cc: Arkadiusz Kubalewski <[email protected]> Cc: Vadim Fedorenko <[email protected]> Reviewed-by: Jiri Pirko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 0e67899 commit 0d60d8d

File tree

5 files changed

+16
-12
lines changed

5 files changed

+16
-12
lines changed

drivers/dpll/dpll_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ void dpll_pin_put(struct dpll_pin *pin)
564564
xa_destroy(&pin->parent_refs);
565565
xa_erase(&dpll_pin_xa, pin->id);
566566
dpll_pin_prop_free(&pin->prop);
567-
kfree(pin);
567+
kfree_rcu(pin, rcu);
568568
}
569569
mutex_unlock(&dpll_lock);
570570
}

drivers/dpll/dpll_core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct dpll_device {
4747
* @prop: pin properties copied from the registerer
4848
* @rclk_dev_name: holds name of device when pin can recover clock from it
4949
* @refcount: refcount
50+
* @rcu: rcu_head for kfree_rcu()
5051
**/
5152
struct dpll_pin {
5253
u32 id;
@@ -57,6 +58,7 @@ struct dpll_pin {
5758
struct xarray parent_refs;
5859
struct dpll_pin_properties prop;
5960
refcount_t refcount;
61+
struct rcu_head rcu;
6062
};
6163

6264
/**

include/linux/dpll.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <uapi/linux/dpll.h>
1111
#include <linux/device.h>
1212
#include <linux/netlink.h>
13+
#include <linux/netdevice.h>
14+
#include <linux/rtnetlink.h>
1315

1416
struct dpll_device;
1517
struct dpll_pin;
@@ -167,4 +169,13 @@ int dpll_device_change_ntf(struct dpll_device *dpll);
167169

168170
int dpll_pin_change_ntf(struct dpll_pin *pin);
169171

172+
static inline struct dpll_pin *netdev_dpll_pin(const struct net_device *dev)
173+
{
174+
#if IS_ENABLED(CONFIG_DPLL)
175+
return rcu_dereference_rtnl(dev->dpll_pin);
176+
#else
177+
return NULL;
178+
#endif
179+
}
180+
170181
#endif

include/linux/netdevice.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,7 +2469,7 @@ struct net_device {
24692469
struct devlink_port *devlink_port;
24702470

24712471
#if IS_ENABLED(CONFIG_DPLL)
2472-
struct dpll_pin *dpll_pin;
2472+
struct dpll_pin __rcu *dpll_pin;
24732473
#endif
24742474
#if IS_ENABLED(CONFIG_PAGE_POOL)
24752475
/** @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);
40354035
void netdev_dpll_pin_set(struct net_device *dev, struct dpll_pin *dpll_pin);
40364036
void netdev_dpll_pin_clear(struct net_device *dev);
40374037

4038-
static inline struct dpll_pin *netdev_dpll_pin(const struct net_device *dev)
4039-
{
4040-
#if IS_ENABLED(CONFIG_DPLL)
4041-
return dev->dpll_pin;
4042-
#else
4043-
return NULL;
4044-
#endif
4045-
}
4046-
40474038
struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev, bool *again);
40484039
struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
40494040
struct netdev_queue *txq, int *ret);

net/core/dev.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9078,7 +9078,7 @@ static void netdev_dpll_pin_assign(struct net_device *dev, struct dpll_pin *dpll
90789078
{
90799079
#if IS_ENABLED(CONFIG_DPLL)
90809080
rtnl_lock();
9081-
dev->dpll_pin = dpll_pin;
9081+
rcu_assign_pointer(dev->dpll_pin, dpll_pin);
90829082
rtnl_unlock();
90839083
#endif
90849084
}

0 commit comments

Comments
 (0)