Skip to content

Commit e418273

Browse files
committed
Merge branch 'netdevsim-psp-fix-init-and-uninit-bugs'
Daniel Zahka says: ==================== netdevsim: psp: fix init and uninit bugs This series has three fixes. The first is a straightforward NULL pointer dereference that is reachable by creating and destroying some vfs on a kernel with INET_PSP enabled. The last two patches deal with nsim_psp_rereg_write(), which is a debugfs handler that reregisters netdevsim's psp_dev without aquiescing and disabling tx/rx processing. This was added to enable some tests in psp.py where a psp device is unregistered while it still referenced by tcp socket state. There are two issues with this code: 1. Calls to nsim_psp_uninit() are not properly serialized 2. netdevsim's psp_dev refcount can be released while nsim_do_psp() is reading from it. ==================== Link: https://patch.msgid.link/20260505-psd-rcu-v1-0-a8f69ec1ab96@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 7aaa8f5 + 07bdec3 commit e418273

3 files changed

Lines changed: 51 additions & 21 deletions

File tree

drivers/net/netdevsim/netdev.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1182,7 +1182,8 @@ void nsim_destroy(struct netdevsim *ns)
11821182
unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb,
11831183
&ns->nn);
11841184

1185-
nsim_psp_uninit(ns);
1185+
if (nsim_dev_port_is_pf(ns->nsim_dev_port))
1186+
nsim_psp_uninit(ns);
11861187

11871188
rtnl_lock();
11881189
peer = rtnl_dereference(ns->peer);

drivers/net/netdevsim/netdevsim.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ 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;
124+
struct dentry *rereg;
125+
struct mutex rereg_lock;
124126
u32 spi;
125127
u32 assoc_cnt;
126128
} psp;

drivers/net/netdevsim/psp.c

Lines changed: 46 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,26 +210,50 @@ static struct psp_dev_caps nsim_psp_caps = {
209210
.assoc_drv_spc = sizeof(void *),
210211
};
211212

212-
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

228+
void nsim_psp_uninit(struct netdevsim *ns)
229+
{
230+
debugfs_remove(ns->psp.rereg);
231+
mutex_destroy(&ns->psp.rereg_lock);
232+
__nsim_psp_uninit(ns, true);
233+
}
234+
219235
static ssize_t
220236
nsim_psp_rereg_write(struct file *file, const char __user *data, size_t count,
221237
loff_t *ppos)
222238
{
223239
struct netdevsim *ns = file->private_data;
224-
int err;
240+
struct psp_dev *psd;
241+
ssize_t ret;
242+
243+
mutex_lock(&ns->psp.rereg_lock);
244+
__nsim_psp_uninit(ns, false);
225245

226-
nsim_psp_uninit(ns);
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+
}
227251

228-
ns->psp.dev = psp_dev_create(ns->netdev, &nsim_psp_ops,
229-
&nsim_psp_caps, ns);
230-
err = PTR_ERR_OR_ZERO(ns->psp.dev);
231-
return err ?: count;
252+
rcu_assign_pointer(ns->psp.dev, psd);
253+
ret = count;
254+
out:
255+
mutex_unlock(&ns->psp.rereg_lock);
256+
return ret;
232257
}
233258

234259
static const struct file_operations nsim_psp_rereg_fops = {
@@ -241,14 +266,16 @@ static const struct file_operations nsim_psp_rereg_fops = {
241266
int nsim_psp_init(struct netdevsim *ns)
242267
{
243268
struct dentry *ddir = ns->nsim_dev_port->ddir;
244-
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);
245274

246-
ns->psp.dev = psp_dev_create(ns->netdev, &nsim_psp_ops,
247-
&nsim_psp_caps, ns);
248-
err = PTR_ERR_OR_ZERO(ns->psp.dev);
249-
if (err)
250-
return err;
275+
rcu_assign_pointer(ns->psp.dev, psd);
251276

252-
debugfs_create_file("psp_rereg", 0200, ddir, ns, &nsim_psp_rereg_fops);
277+
mutex_init(&ns->psp.rereg_lock);
278+
ns->psp.rereg = debugfs_create_file("psp_rereg", 0200, ddir, ns,
279+
&nsim_psp_rereg_fops);
253280
return 0;
254281
}

0 commit comments

Comments
 (0)