Skip to content

Commit c83d7f2

Browse files
TaeheeYoogregkh
authored andcommitted
netdevsim: fix using uninitialized resources
commit f5cd216 upstream. When module is being initialized, __init() calls bus_register() and driver_register(). These functions internally create various resources and sysfs files. The sysfs files are used for basic operations(add/del device). /sys/bus/netdevsim/new_device /sys/bus/netdevsim/del_device These sysfs files use netdevsim resources, they are mostly allocated and initialized in ->probe() function, which is nsim_dev_probe(). But, sysfs files could be executed before ->probe() is finished. So, accessing uninitialized data would occur. Another problem is very similar. /sys/bus/netdevsim/new_device internally creates sysfs files. /sys/devices/netdevsim<id>/new_port /sys/devices/netdevsim<id>/del_port These sysfs files also use netdevsim resources, they are mostly allocated and initialized in creating device routine, which is nsim_bus_dev_new(). But they also could be executed before nsim_bus_dev_new() is finished. So, accessing uninitialized data would occur. To fix these problems, this patch adds flags, which means whether the operation is finished or not. The flag variable 'nsim_bus_enable' means whether netdevsim bus was initialized or not. This is protected by nsim_bus_dev_list_lock. The flag variable 'nsim_bus_dev->init' means whether nsim_bus_dev was initialized or not. This could be used in {new/del}_port_store() with no lock. Test commands: #SHELL1 modprobe netdevsim while : do echo "1 1" > /sys/bus/netdevsim/new_device echo "1 1" > /sys/bus/netdevsim/del_device done #SHELL2 while : do echo 1 > /sys/devices/netdevsim1/new_port echo 1 > /sys/devices/netdevsim1/del_port done Splat looks like: [ 47.508954][ T1008] general protection fault, probably for non-canonical address 0xdffffc0000000021: 0000 I [ 47.510793][ T1008] KASAN: null-ptr-deref in range [0x0000000000000108-0x000000000000010f] [ 47.511963][ T1008] CPU: 2 PID: 1008 Comm: bash Not tainted 5.5.0+ #322 [ 47.512823][ T1008] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 47.514041][ T1008] RIP: 0010:__mutex_lock+0x10a/0x14b0 [ 47.514699][ T1008] Code: 08 84 d2 0f 85 7f 12 00 00 44 8b 0d 10 23 65 02 45 85 c9 75 29 49 8d 7f 68 48 b8 00 00 00 0f [ 47.517163][ T1008] RSP: 0018:ffff888059b4fbb0 EFLAGS: 00010206 [ 47.517802][ T1008] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: 0000000000000000 [ 47.518941][ T1008] RDX: 0000000000000021 RSI: ffffffff85926440 RDI: 0000000000000108 [ 47.519732][ T1008] RBP: ffff888059b4fd30 R08: ffffffffc073fad0 R09: 0000000000000000 [ 47.520729][ T1008] R10: ffff888059b4fd50 R11: ffff88804bb38040 R12: 0000000000000000 [ 47.521702][ T1008] R13: dffffc0000000000 R14: ffffffff871976c0 R15: 00000000000000a0 [ 47.522760][ T1008] FS: 00007fd4be05a740(0000) GS:ffff88806c800000(0000) knlGS:0000000000000000 [ 47.523877][ T1008] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 47.524627][ T1008] CR2: 0000561c82b69cf0 CR3: 0000000065dd6004 CR4: 00000000000606e0 [ 47.527662][ T1008] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 47.528604][ T1008] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 47.529531][ T1008] Call Trace: [ 47.529874][ T1008] ? nsim_dev_port_add+0x50/0x150 [netdevsim] [ 47.530470][ T1008] ? mutex_lock_io_nested+0x1380/0x1380 [ 47.531018][ T1008] ? _kstrtoull+0x76/0x160 [ 47.531449][ T1008] ? _parse_integer+0xf0/0xf0 [ 47.531874][ T1008] ? kernfs_fop_write+0x1cf/0x410 [ 47.532330][ T1008] ? sysfs_file_ops+0x160/0x160 [ 47.532773][ T1008] ? kstrtouint+0x86/0x110 [ 47.533168][ T1008] ? nsim_dev_port_add+0x50/0x150 [netdevsim] [ 47.533721][ T1008] nsim_dev_port_add+0x50/0x150 [netdevsim] [ 47.534336][ T1008] ? sysfs_file_ops+0x160/0x160 [ 47.534858][ T1008] new_port_store+0x99/0xb0 [netdevsim] [ 47.535439][ T1008] ? del_port_store+0xb0/0xb0 [netdevsim] [ 47.536035][ T1008] ? sysfs_file_ops+0x112/0x160 [ 47.536544][ T1008] ? sysfs_kf_write+0x3b/0x180 [ 47.537029][ T1008] kernfs_fop_write+0x276/0x410 [ 47.537548][ T1008] ? __sb_start_write+0x215/0x2e0 [ 47.538110][ T1008] vfs_write+0x197/0x4a0 [ ... ] Fixes: f9d9db4 ("netdevsim: add bus attributes to add new and delete devices") Fixes: 794b2c0 ("netdevsim: extend device attrs to support port addition and deletion") Signed-off-by: Taehee Yoo <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 89ff861 commit c83d7f2

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

drivers/net/netdevsim/bus.c

Lines changed: 40 additions & 3 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
{
@@ -99,6 +100,9 @@ new_port_store(struct device *dev, struct device_attribute *attr,
99100
unsigned int port_index;
100101
int ret;
101102

103+
/* Prevent to use nsim_bus_dev before initialization. */
104+
if (!smp_load_acquire(&nsim_bus_dev->init))
105+
return -EBUSY;
102106
ret = kstrtouint(buf, 0, &port_index);
103107
if (ret)
104108
return ret;
@@ -116,6 +120,9 @@ del_port_store(struct device *dev, struct device_attribute *attr,
116120
unsigned int port_index;
117121
int ret;
118122

123+
/* Prevent to use nsim_bus_dev before initialization. */
124+
if (!smp_load_acquire(&nsim_bus_dev->init))
125+
return -EBUSY;
119126
ret = kstrtouint(buf, 0, &port_index);
120127
if (ret)
121128
return ret;
@@ -179,15 +186,30 @@ new_device_store(struct bus_type *bus, const char *buf, size_t count)
179186
pr_err("Format for adding new device is \"id port_count\" (uint uint).\n");
180187
return -EINVAL;
181188
}
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);
185189

186190
mutex_lock(&nsim_bus_dev_list_lock);
191+
/* Prevent to use resource before initialization. */
192+
if (!smp_load_acquire(&nsim_bus_enable)) {
193+
err = -EBUSY;
194+
goto err;
195+
}
196+
197+
nsim_bus_dev = nsim_bus_dev_new(id, port_count);
198+
if (IS_ERR(nsim_bus_dev)) {
199+
err = PTR_ERR(nsim_bus_dev);
200+
goto err;
201+
}
202+
203+
/* Allow using nsim_bus_dev */
204+
smp_store_release(&nsim_bus_dev->init, true);
205+
187206
list_add_tail(&nsim_bus_dev->list, &nsim_bus_dev_list);
188207
mutex_unlock(&nsim_bus_dev_list_lock);
189208

190209
return count;
210+
err:
211+
mutex_unlock(&nsim_bus_dev_list_lock);
212+
return err;
191213
}
192214
static BUS_ATTR_WO(new_device);
193215

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

216238
err = -ENOENT;
217239
mutex_lock(&nsim_bus_dev_list_lock);
240+
/* Prevent to use resource before initialization. */
241+
if (!smp_load_acquire(&nsim_bus_enable)) {
242+
mutex_unlock(&nsim_bus_dev_list_lock);
243+
return -EBUSY;
244+
}
218245
list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) {
219246
if (nsim_bus_dev->dev.id != id)
220247
continue;
@@ -284,6 +311,8 @@ nsim_bus_dev_new(unsigned int id, unsigned int port_count)
284311
nsim_bus_dev->dev.type = &nsim_bus_dev_type;
285312
nsim_bus_dev->port_count = port_count;
286313
nsim_bus_dev->initial_net = current->nsproxy->net_ns;
314+
/* Disallow using nsim_bus_dev */
315+
smp_store_release(&nsim_bus_dev->init, false);
287316

288317
err = device_register(&nsim_bus_dev->dev);
289318
if (err)
@@ -299,6 +328,8 @@ nsim_bus_dev_new(unsigned int id, unsigned int port_count)
299328

300329
static void nsim_bus_dev_del(struct nsim_bus_dev *nsim_bus_dev)
301330
{
331+
/* Disallow using nsim_bus_dev */
332+
smp_store_release(&nsim_bus_dev->init, false);
302333
device_unregister(&nsim_bus_dev->dev);
303334
ida_free(&nsim_bus_dev_ids, nsim_bus_dev->dev.id);
304335
kfree(nsim_bus_dev);
@@ -320,6 +351,8 @@ int nsim_bus_init(void)
320351
err = driver_register(&nsim_driver);
321352
if (err)
322353
goto err_bus_unregister;
354+
/* Allow using resources */
355+
smp_store_release(&nsim_bus_enable, true);
323356
return 0;
324357

325358
err_bus_unregister:
@@ -331,12 +364,16 @@ void nsim_bus_exit(void)
331364
{
332365
struct nsim_bus_dev *nsim_bus_dev, *tmp;
333366

367+
/* Disallow using resources */
368+
smp_store_release(&nsim_bus_enable, false);
369+
334370
mutex_lock(&nsim_bus_dev_list_lock);
335371
list_for_each_entry_safe(nsim_bus_dev, tmp, &nsim_bus_dev_list, list) {
336372
list_del(&nsim_bus_dev->list);
337373
nsim_bus_dev_del(nsim_bus_dev);
338374
}
339375
mutex_unlock(&nsim_bus_dev_list_lock);
376+
340377
driver_unregister(&nsim_driver);
341378
bus_unregister(&nsim_bus);
342379
}

drivers/net/netdevsim/netdevsim.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ struct nsim_bus_dev {
240240
*/
241241
unsigned int num_vfs;
242242
struct nsim_vf_config *vfconfigs;
243+
bool init;
243244
};
244245

245246
int nsim_bus_init(void);

0 commit comments

Comments
 (0)