Skip to content

Commit a444ad1

Browse files
committed
Merge branch 'netdevsim-fix-several-bugs-in-netdevsim-module'
Taehee Yoo says: ===================== netdevsim: fix several bugs in netdevsim module This patchset fixes several bugs in netdevsim module. 1. The first patch fixes using uninitialized resources This patch fixes two similar problems, which is to use uninitialized resources. a) In the current code, {new/del}_device_store() use resource, they are initialized by __init(). But, these functions could be called before __init() is finished. So, accessing uninitialized data could occur and it eventually makes panic. b) In the current code, {new/del}_port_store() uses resource, they are initialized by new_device_store(). But thes functions could be called before new_device_store() is finished. 2. The second patch fixes another race condition. The main problem is a race condition in {new/del}_port() and devlink reload function. These functions would allocate and remove resources. So these functions should not be executed concurrently. 3. The third patch fixes a panic in nsim_dev_take_snapshot_write(). nsim_dev_take_snapshot_write() uses nsim_dev and nsim_dev->dummy_region. But these data could be removed by both reload routine and del_device_store(). And these functions could be executed concurrently. 4. The fourth patch fixes stack-out-of-bound in nsim_dev_debugfs_init(). nsim_dev_debugfs_init() provides only 16bytes for name pointer. But, there are some case the name length is over 16bytes. So, stack-out-of-bound occurs. 5. The fifth patch uses IS_ERR instead of IS_ERR_OR_NULL. debugfs_create_{dir/file} doesn't return NULL. So, IS_ERR() is more correct. 6. The sixth patch avoids kmalloc warning. When too large memory allocation is requested by user-space, kmalloc internally prints warning message. That warning message is not necessary. In order to avoid that, it adds __GFP_NOWARN. 7. The last patch removes an unused sdev.c file Change log: v2 -> v3: - Use smp_load_acquire() and smp_store_release() for flag variables. - Change variable names. - Fix deadlock in second patch. - Update lock variable comment. - Add new patch for fixing panic in snapshot_write(). - Include Reviewed-by tags. - Update some log messages and comment. v1 -> v2: - Splits a fixing race condition patch into two patches. - Fix incorrect Fixes tags. - Update comments - Fix use-after-free - Add a new patch, which removes an unused sdev.c file. - Remove a patch, which tries to avoid debugfs warning. ===================== Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 2b5ea29 + 2453116 commit a444ad1

File tree

6 files changed

+93
-91
lines changed

6 files changed

+93
-91
lines changed

drivers/net/netdevsim/bpf.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ static int nsim_bpf_create_prog(struct nsim_dev *nsim_dev,
218218
{
219219
struct nsim_bpf_bound_prog *state;
220220
char name[16];
221+
int ret;
221222

222223
state = kzalloc(sizeof(*state), GFP_KERNEL);
223224
if (!state)
@@ -230,9 +231,10 @@ static int nsim_bpf_create_prog(struct nsim_dev *nsim_dev,
230231
/* Program id is not populated yet when we create the state. */
231232
sprintf(name, "%u", nsim_dev->prog_id_gen++);
232233
state->ddir = debugfs_create_dir(name, nsim_dev->ddir_bpf_bound_progs);
233-
if (IS_ERR_OR_NULL(state->ddir)) {
234+
if (IS_ERR(state->ddir)) {
235+
ret = PTR_ERR(state->ddir);
234236
kfree(state);
235-
return -ENOMEM;
237+
return ret;
236238
}
237239

238240
debugfs_create_u32("id", 0400, state->ddir, &prog->aux->id);
@@ -587,8 +589,8 @@ int nsim_bpf_dev_init(struct nsim_dev *nsim_dev)
587589

588590
nsim_dev->ddir_bpf_bound_progs = debugfs_create_dir("bpf_bound_progs",
589591
nsim_dev->ddir);
590-
if (IS_ERR_OR_NULL(nsim_dev->ddir_bpf_bound_progs))
591-
return -ENOMEM;
592+
if (IS_ERR(nsim_dev->ddir_bpf_bound_progs))
593+
return PTR_ERR(nsim_dev->ddir_bpf_bound_progs);
592594

593595
nsim_dev->bpf_dev = bpf_offload_dev_create(&nsim_bpf_dev_ops, nsim_dev);
594596
err = PTR_ERR_OR_ZERO(nsim_dev->bpf_dev);

drivers/net/netdevsim/bus.c

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
static DEFINE_IDA(nsim_bus_dev_ids);
1818
static LIST_HEAD(nsim_bus_dev_list);
1919
static DEFINE_MUTEX(nsim_bus_dev_list_lock);
20+
static bool nsim_bus_enable;
2021

2122
static struct nsim_bus_dev *to_nsim_bus_dev(struct device *dev)
2223
{
@@ -28,7 +29,7 @@ static int nsim_bus_dev_vfs_enable(struct nsim_bus_dev *nsim_bus_dev,
2829
{
2930
nsim_bus_dev->vfconfigs = kcalloc(num_vfs,
3031
sizeof(struct nsim_vf_config),
31-
GFP_KERNEL);
32+
GFP_KERNEL | __GFP_NOWARN);
3233
if (!nsim_bus_dev->vfconfigs)
3334
return -ENOMEM;
3435
nsim_bus_dev->num_vfs = num_vfs;
@@ -96,13 +97,25 @@ new_port_store(struct device *dev, struct device_attribute *attr,
9697
const char *buf, size_t count)
9798
{
9899
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
100+
struct nsim_dev *nsim_dev = dev_get_drvdata(dev);
101+
struct devlink *devlink;
99102
unsigned int port_index;
100103
int ret;
101104

105+
/* Prevent to use nsim_bus_dev before initialization. */
106+
if (!smp_load_acquire(&nsim_bus_dev->init))
107+
return -EBUSY;
102108
ret = kstrtouint(buf, 0, &port_index);
103109
if (ret)
104110
return ret;
111+
112+
devlink = priv_to_devlink(nsim_dev);
113+
114+
mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock);
115+
devlink_reload_disable(devlink);
105116
ret = nsim_dev_port_add(nsim_bus_dev, port_index);
117+
devlink_reload_enable(devlink);
118+
mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock);
106119
return ret ? ret : count;
107120
}
108121

@@ -113,13 +126,25 @@ del_port_store(struct device *dev, struct device_attribute *attr,
113126
const char *buf, size_t count)
114127
{
115128
struct nsim_bus_dev *nsim_bus_dev = to_nsim_bus_dev(dev);
129+
struct nsim_dev *nsim_dev = dev_get_drvdata(dev);
130+
struct devlink *devlink;
116131
unsigned int port_index;
117132
int ret;
118133

134+
/* Prevent to use nsim_bus_dev before initialization. */
135+
if (!smp_load_acquire(&nsim_bus_dev->init))
136+
return -EBUSY;
119137
ret = kstrtouint(buf, 0, &port_index);
120138
if (ret)
121139
return ret;
140+
141+
devlink = priv_to_devlink(nsim_dev);
142+
143+
mutex_lock(&nsim_bus_dev->nsim_bus_reload_lock);
144+
devlink_reload_disable(devlink);
122145
ret = nsim_dev_port_del(nsim_bus_dev, port_index);
146+
devlink_reload_enable(devlink);
147+
mutex_unlock(&nsim_bus_dev->nsim_bus_reload_lock);
123148
return ret ? ret : count;
124149
}
125150

@@ -179,15 +204,30 @@ new_device_store(struct bus_type *bus, const char *buf, size_t count)
179204
pr_err("Format for adding new device is \"id port_count\" (uint uint).\n");
180205
return -EINVAL;
181206
}
182-
nsim_bus_dev = nsim_bus_dev_new(id, port_count);
183-
if (IS_ERR(nsim_bus_dev))
184-
return PTR_ERR(nsim_bus_dev);
185207

186208
mutex_lock(&nsim_bus_dev_list_lock);
209+
/* Prevent to use resource before initialization. */
210+
if (!smp_load_acquire(&nsim_bus_enable)) {
211+
err = -EBUSY;
212+
goto err;
213+
}
214+
215+
nsim_bus_dev = nsim_bus_dev_new(id, port_count);
216+
if (IS_ERR(nsim_bus_dev)) {
217+
err = PTR_ERR(nsim_bus_dev);
218+
goto err;
219+
}
220+
221+
/* Allow using nsim_bus_dev */
222+
smp_store_release(&nsim_bus_dev->init, true);
223+
187224
list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list);
188225
mutex_unlock(&nsim_bus_dev_list_lock);
189226

190227
return count;
228+
err:
229+
mutex_unlock(&nsim_bus_dev_list_lock);
230+
return err;
191231
}
192232
static BUS_ATTR_WO(new_device);
193233

@@ -215,6 +255,11 @@ del_device_store(struct bus_type *bus, const char *buf, size_t count)
215255

216256
err = -ENOENT;
217257
mutex_lock(&nsim_bus_dev_list_lock);
258+
/* Prevent to use resource before initialization. */
259+
if (!smp_load_acquire(&nsim_bus_enable)) {
260+
mutex_unlock(&nsim_bus_dev_list_lock);
261+
return -EBUSY;
262+
}
218263
list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) {
219264
if (nsim_bus_dev->dev.id != id)
220265
continue;
@@ -284,6 +329,9 @@ nsim_bus_dev_new(unsigned int id, unsigned int port_count)
284329
nsim_bus_dev->dev.type = &nsim_bus_dev_type;
285330
nsim_bus_dev->port_count = port_count;
286331
nsim_bus_dev->initial_net = current->nsproxy->net_ns;
332+
mutex_init(&nsim_bus_dev->nsim_bus_reload_lock);
333+
/* Disallow using nsim_bus_dev */
334+
smp_store_release(&nsim_bus_dev->init, false);
287335

288336
err = device_register(&nsim_bus_dev->dev);
289337
if (err)
@@ -299,6 +347,8 @@ nsim_bus_dev_new(unsigned int id, unsigned int port_count)
299347

300348
static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev)
301349
{
350+
/* Disallow using nsim_bus_dev */
351+
smp_store_release(&nsim_bus_dev->init, false);
302352
device_unregister(&nsim_bus_dev->dev);
303353
ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id);
304354
kfree(nsim_bus_dev);
@@ -320,6 +370,8 @@ int nsim_bus_init(void)
320370
err = driver_register(&nsim_driver);
321371
if (err)
322372
goto err_bus_unregister;
373+
/* Allow using resources */
374+
smp_store_release(&nsim_bus_enable, true);
323375
return 0;
324376

325377
err_bus_unregister:
@@ -331,12 +383,16 @@ void nsim_bus_exit(void)
331383
{
332384
struct nsim_bus_dev *nsim_bus_dev, *tmp;
333385

386+
/* Disallow using resources */
387+
smp_store_release(&nsim_bus_enable, false);
388+
334389
mutex_lock(&nsim_bus_dev_list_lock);
335390
list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) {
336391
list_del(&nsim_bus_dev->list);
337392
nsim_bus_dev_del(nsim_bus_dev);
338393
}
339394
mutex_unlock(&nsim_bus_dev_list_lock);
395+
340396
driver_unregister(&nsim_driver);
341397
bus_unregister(&nsim_bus);
342398
}

drivers/net/netdevsim/dev.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,23 +73,26 @@ static const struct file_operations nsim_dev_take_snapshot_fops = {
7373

7474
static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)
7575
{
76-
char dev_ddir_name[16];
76+
char dev_ddir_name[sizeof(DRV_NAME) + 10];
7777

7878
sprintf(dev_ddir_name, DRV_NAME "%u", nsim_dev->nsim_bus_dev->dev.id);
7979
nsim_dev->ddir = debugfs_create_dir(dev_ddir_name, nsim_dev_ddir);
80-
if (IS_ERR_OR_NULL(nsim_dev->ddir))
81-
return PTR_ERR_OR_ZERO(nsim_dev->ddir) ?: -EINVAL;
80+
if (IS_ERR(nsim_dev->ddir))
81+
return PTR_ERR(nsim_dev->ddir);
8282
nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir);
83-
if (IS_ERR_OR_NULL(nsim_dev->ports_ddir))
84-
return PTR_ERR_OR_ZERO(nsim_dev->ports_ddir) ?: -EINVAL;
83+
if (IS_ERR(nsim_dev->ports_ddir))
84+
return PTR_ERR(nsim_dev->ports_ddir);
8585
debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir,
8686
&nsim_dev->fw_update_status);
8787
debugfs_create_u32("max_macs", 0600, nsim_dev->ddir,
8888
&nsim_dev->max_macs);
8989
debugfs_create_bool("test1", 0600, nsim_dev->ddir,
9090
&nsim_dev->test1);
91-
debugfs_create_file("take_snapshot", 0200, nsim_dev->ddir, nsim_dev,
92-
&nsim_dev_take_snapshot_fops);
91+
nsim_dev->take_snapshot = debugfs_create_file("take_snapshot",
92+
0200,
93+
nsim_dev->ddir,
94+
nsim_dev,
95+
&nsim_dev_take_snapshot_fops);
9396
debugfs_create_bool("dont_allow_reload", 0600, nsim_dev->ddir,
9497
&nsim_dev->dont_allow_reload);
9598
debugfs_create_bool("fail_reload", 0600, nsim_dev->ddir,
@@ -112,8 +115,8 @@ static int nsim_dev_port_debugfs_init(struct nsim_dev *nsim_dev,
112115
sprintf(port_ddir_name, "%u", nsim_dev_port->port_index);
113116
nsim_dev_port->ddir = debugfs_create_dir(port_ddir_name,
114117
nsim_dev->ports_ddir);
115-
if (IS_ERR_OR_NULL(nsim_dev_port->ddir))
116-
return -ENOMEM;
118+
if (IS_ERR(nsim_dev_port->ddir))
119+
return PTR_ERR(nsim_dev_port->ddir);
117120

118121
sprintf(dev_link_name, "../../../" DRV_NAME "%u",
119122
nsim_dev->nsim_bus_dev->dev.id);
@@ -740,6 +743,11 @@ static int nsim_dev_reload_create(struct nsim_dev *nsim_dev,
740743
if (err)
741744
goto err_health_exit;
742745

746+
nsim_dev->take_snapshot = debugfs_create_file("take_snapshot",
747+
0200,
748+
nsim_dev->ddir,
749+
nsim_dev,
750+
&nsim_dev_take_snapshot_fops);
743751
return 0;
744752

745753
err_health_exit:
@@ -853,6 +861,7 @@ static void nsim_dev_reload_destroy(struct nsim_dev *nsim_dev)
853861

854862
if (devlink_is_reload_failed(devlink))
855863
return;
864+
debugfs_remove(nsim_dev->take_snapshot);
856865
nsim_dev_port_del_all(nsim_dev);
857866
nsim_dev_health_exit(nsim_dev);
858867
nsim_dev_traps_exit(devlink);
@@ -925,8 +934,8 @@ int nsim_dev_port_del(struct nsim_bus_dev *nsim_bus_dev,
925934
int nsim_dev_init(void)
926935
{
927936
nsim_dev_ddir = debugfs_create_dir(DRV_NAME, NULL);
928-
if (IS_ERR_OR_NULL(nsim_dev_ddir))
929-
return -ENOMEM;
937+
if (IS_ERR(nsim_dev_ddir))
938+
return PTR_ERR(nsim_dev_ddir);
930939
return 0;
931940
}
932941

drivers/net/netdevsim/health.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ static int nsim_dev_dummy_fmsg_put(struct devlink_fmsg *fmsg, u32 binary_len)
8282
if (err)
8383
return err;
8484

85-
binary = kmalloc(binary_len, GFP_KERNEL);
85+
binary = kmalloc(binary_len, GFP_KERNEL | __GFP_NOWARN);
8686
if (!binary)
8787
return -ENOMEM;
8888
get_random_bytes(binary, binary_len);
@@ -285,8 +285,8 @@ int nsim_dev_health_init(struct nsim_dev *nsim_dev, struct devlink *devlink)
285285
}
286286

287287
health->ddir = debugfs_create_dir("health", nsim_dev->ddir);
288-
if (IS_ERR_OR_NULL(health->ddir)) {
289-
err = PTR_ERR_OR_ZERO(health->ddir) ?: -EINVAL;
288+
if (IS_ERR(health->ddir)) {
289+
err = PTR_ERR(health->ddir);
290290
goto err_dummy_reporter_destroy;
291291
}
292292

drivers/net/netdevsim/netdevsim.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ struct nsim_dev {
160160
struct nsim_trap_data *trap_data;
161161
struct dentry *ddir;
162162
struct dentry *ports_ddir;
163+
struct dentry *take_snapshot;
163164
struct bpf_offload_dev *bpf_dev;
164165
bool bpf_bind_accept;
165166
u32 bpf_bind_verifier_delay;
@@ -240,6 +241,9 @@ struct nsim_bus_dev {
240241
*/
241242
unsigned int num_vfs;
242243
struct nsim_vf_config *vfconfigs;
244+
/* Lock for devlink->reload_enabled in netdevsim module */
245+
struct mutex nsim_bus_reload_lock;
246+
bool init;
243247
};
244248

245249
int nsim_bus_init(void);

drivers/net/netdevsim/sdev.c

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)