Skip to content

Commit 07bdec3

Browse files
Daniel Zahkakuba-moo
authored andcommitted
netdevsim: psp: rcu protect psp_dev reference
There are two issues with the way psp_dev is used in nsim_do_psp(): 1. There is no check for IS_ERR() on the peers psp_dev, before dereferencing. 2. The refcount on this psp_dev can be dropped by nsim_psp_rereg_write() To fix this, we can make netdevsim's reference to its psp_dev an rcu reference, and then nsim_do_psp() can read the fields it needs from an rcu critical section. Fixes: f857478 ("netdevsim: a basic test PSP implementation") Signed-off-by: Daniel Zahka <daniel.zahka@gmail.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Link: https://patch.msgid.link/20260505-psd-rcu-v1-3-a8f69ec1ab96@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 24c96a4 commit 07bdec3

2 files changed

Lines changed: 36 additions & 20 deletions

File tree

drivers/net/netdevsim/netdevsim.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ struct netdevsim {
120120
u64_stats_t tx_packets;
121121
u64_stats_t tx_bytes;
122122
struct u64_stats_sync syncp;
123-
struct psp_dev *dev;
123+
struct psp_dev __rcu *dev;
124124
struct dentry *rereg;
125125
struct mutex rereg_lock;
126126
u32 spi;

drivers/net/netdevsim/psp.c

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
1919
struct netdevsim *peer_ns, struct skb_ext **psp_ext)
2020
{
2121
enum skb_drop_reason rc = 0;
22+
struct psp_dev *peer_psd;
2223
struct psp_assoc *pas;
2324
struct net *net;
2425
void **ptr;
@@ -48,7 +49,8 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
4849
}
4950

5051
/* Now pretend we just received this frame */
51-
if (peer_ns->psp.dev->config.versions & (1 << pas->version)) {
52+
peer_psd = rcu_dereference(peer_ns->psp.dev);
53+
if (peer_psd && peer_psd->config.versions & (1 << pas->version)) {
5254
bool strip_icv = false;
5355
u8 generation;
5456

@@ -61,8 +63,7 @@ nsim_do_psp(struct sk_buff *skb, struct netdevsim *ns,
6163

6264
skb_ext_reset(skb);
6365
skb->mac_len = ETH_HLEN;
64-
if (psp_dev_rcv(skb, peer_ns->psp.dev->id, generation,
65-
strip_icv)) {
66+
if (psp_dev_rcv(skb, peer_psd->id, generation, strip_icv)) {
6667
rc = SKB_DROP_REASON_PSP_OUTPUT;
6768
goto out_unlock;
6869
}
@@ -209,35 +210,50 @@ static struct psp_dev_caps nsim_psp_caps = {
209210
.assoc_drv_spc = sizeof(void *),
210211
};
211212

212-
static void __nsim_psp_uninit(struct netdevsim *ns)
213+
static void __nsim_psp_uninit(struct netdevsim *ns, bool teardown)
213214
{
214-
if (!IS_ERR(ns->psp.dev))
215-
psp_dev_unregister(ns->psp.dev);
215+
struct psp_dev *psd;
216+
217+
psd = rcu_dereference_protected(ns->psp.dev,
218+
teardown ||
219+
lockdep_is_held(&ns->psp.rereg_lock));
220+
if (psd) {
221+
rcu_assign_pointer(ns->psp.dev, NULL);
222+
synchronize_rcu();
223+
psp_dev_unregister(psd);
224+
}
216225
WARN_ON(ns->psp.assoc_cnt);
217226
}
218227

219228
void nsim_psp_uninit(struct netdevsim *ns)
220229
{
221230
debugfs_remove(ns->psp.rereg);
222231
mutex_destroy(&ns->psp.rereg_lock);
223-
__nsim_psp_uninit(ns);
232+
__nsim_psp_uninit(ns, true);
224233
}
225234

226235
static ssize_t
227236
nsim_psp_rereg_write(struct file *file, const char __user *data, size_t count,
228237
loff_t *ppos)
229238
{
230239
struct netdevsim *ns = file->private_data;
231-
int err;
240+
struct psp_dev *psd;
241+
ssize_t ret;
232242

233243
mutex_lock(&ns->psp.rereg_lock);
234-
__nsim_psp_uninit(ns);
244+
__nsim_psp_uninit(ns, false);
245+
246+
psd = psp_dev_create(ns->netdev, &nsim_psp_ops, &nsim_psp_caps, ns);
247+
if (IS_ERR(psd)) {
248+
ret = PTR_ERR(psd);
249+
goto out;
250+
}
235251

236-
ns->psp.dev = psp_dev_create(ns->netdev, &nsim_psp_ops,
237-
&nsim_psp_caps, ns);
238-
err = PTR_ERR_OR_ZERO(ns->psp.dev);
252+
rcu_assign_pointer(ns->psp.dev, psd);
253+
ret = count;
254+
out:
239255
mutex_unlock(&ns->psp.rereg_lock);
240-
return err ?: count;
256+
return ret;
241257
}
242258

243259
static const struct file_operations nsim_psp_rereg_fops = {
@@ -250,13 +266,13 @@ static const struct file_operations nsim_psp_rereg_fops = {
250266
int nsim_psp_init(struct netdevsim *ns)
251267
{
252268
struct dentry *ddir = ns->nsim_dev_port->ddir;
253-
int err;
269+
struct psp_dev *psd;
270+
271+
psd = psp_dev_create(ns->netdev, &nsim_psp_ops, &nsim_psp_caps, ns);
272+
if (IS_ERR(psd))
273+
return PTR_ERR(psd);
254274

255-
ns->psp.dev = psp_dev_create(ns->netdev, &nsim_psp_ops,
256-
&nsim_psp_caps, ns);
257-
err = PTR_ERR_OR_ZERO(ns->psp.dev);
258-
if (err)
259-
return err;
275+
rcu_assign_pointer(ns->psp.dev, psd);
260276

261277
mutex_init(&ns->psp.rereg_lock);
262278
ns->psp.rereg = debugfs_create_file("psp_rereg", 0200, ddir, ns,

0 commit comments

Comments
 (0)