Skip to content

Commit 0250019

Browse files
Vasant Hegdesmb49
authored andcommitted
powerpc/powernv/dump: Fix race while processing OPAL dump
BugLink: https://bugs.launchpad.net/bugs/1902137 [ Upstream commit 0a43ae3 ] Every dump reported by OPAL is exported to userspace through a sysfs interface and notified using kobject_uevent(). The userspace daemon (opal_errd) then reads the dump and acknowledges that the dump is saved safely to disk. Once acknowledged the kernel removes the respective sysfs file entry causing respective resources to be released including kobject. However it's possible the userspace daemon may already be scanning dump entries when a new sysfs dump entry is created by the kernel. User daemon may read this new entry and ack it even before kernel can notify userspace about it through kobject_uevent() call. If that happens then we have a potential race between dump_ack_store->kobject_put() and kobject_uevent which can lead to use-after-free of a kernfs object resulting in a kernel crash. This patch fixes this race by protecting the sysfs file creation/notification by holding a reference count on kobject until we safely send kobject_uevent(). The function create_dump_obj() returns the dump object which if used by caller function will end up in use-after-free problem again. However, the return value of create_dump_obj() function isn't being used today and there is no need as well. Hence change it to return void to make this fix complete. Fixes: c7e64b9 ("powerpc/powernv Platform dump interface") Signed-off-by: Vasant Hegde <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Kamal Mostafa <[email protected]> Signed-off-by: Ian May <[email protected]>
1 parent 9363558 commit 0250019

File tree

1 file changed

+29
-12
lines changed

1 file changed

+29
-12
lines changed

arch/powerpc/platforms/powernv/opal-dump.c

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -318,15 +318,14 @@ static ssize_t dump_attr_read(struct file *filep, struct kobject *kobj,
318318
return count;
319319
}
320320

321-
static struct dump_obj *create_dump_obj(uint32_t id, size_t size,
322-
uint32_t type)
321+
static void create_dump_obj(uint32_t id, size_t size, uint32_t type)
323322
{
324323
struct dump_obj *dump;
325324
int rc;
326325

327326
dump = kzalloc(sizeof(*dump), GFP_KERNEL);
328327
if (!dump)
329-
return NULL;
328+
return;
330329

331330
dump->kobj.kset = dump_kset;
332331

@@ -346,21 +345,39 @@ static struct dump_obj *create_dump_obj(uint32_t id, size_t size,
346345
rc = kobject_add(&dump->kobj, NULL, "0x%x-0x%x", type, id);
347346
if (rc) {
348347
kobject_put(&dump->kobj);
349-
return NULL;
348+
return;
350349
}
351350

351+
/*
352+
* As soon as the sysfs file for this dump is created/activated there is
353+
* a chance the opal_errd daemon (or any userspace) might read and
354+
* acknowledge the dump before kobject_uevent() is called. If that
355+
* happens then there is a potential race between
356+
* dump_ack_store->kobject_put() and kobject_uevent() which leads to a
357+
* use-after-free of a kernfs object resulting in a kernel crash.
358+
*
359+
* To avoid that, we need to take a reference on behalf of the bin file,
360+
* so that our reference remains valid while we call kobject_uevent().
361+
* We then drop our reference before exiting the function, leaving the
362+
* bin file to drop the last reference (if it hasn't already).
363+
*/
364+
365+
/* Take a reference for the bin file */
366+
kobject_get(&dump->kobj);
352367
rc = sysfs_create_bin_file(&dump->kobj, &dump->dump_attr);
353-
if (rc) {
368+
if (rc == 0) {
369+
kobject_uevent(&dump->kobj, KOBJ_ADD);
370+
371+
pr_info("%s: New platform dump. ID = 0x%x Size %u\n",
372+
__func__, dump->id, dump->size);
373+
} else {
374+
/* Drop reference count taken for bin file */
354375
kobject_put(&dump->kobj);
355-
return NULL;
356376
}
357377

358-
pr_info("%s: New platform dump. ID = 0x%x Size %u\n",
359-
__func__, dump->id, dump->size);
360-
361-
kobject_uevent(&dump->kobj, KOBJ_ADD);
362-
363-
return dump;
378+
/* Drop our reference */
379+
kobject_put(&dump->kobj);
380+
return;
364381
}
365382

366383
static irqreturn_t process_dump(int irq, void *data)

0 commit comments

Comments
 (0)