Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 29b6e4e

Browse files
maheshsalgregkh
authored andcommitted
powerpc/powernv/elog: Fix race while processing OPAL error log event.
commit aea948b upstream. Every error log reported by OPAL is exported to userspace through a sysfs interface and notified using kobject_uevent(). The userspace daemon (opal_errd) then reads the error log and acknowledges the error log 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 elog entries when a new sysfs elog 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 elog_ack_store->kobject_put() and kobject_uevent which can lead to use-after-free of a kernfs object resulting in a kernel crash. eg: BUG: Unable to handle kernel data access on read at 0x6b6b6b6b6b6b6bfb Faulting instruction address: 0xc0000000008ff2a0 Oops: Kernel access of bad area, sig: 11 [#1] LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA PowerNV CPU: 27 PID: 805 Comm: irq/29-opal-elo Not tainted 5.9.0-rc2-gcc-8.2.0-00214-g6f56a67bcbb5-dirty torvalds#363 ... NIP kobject_uevent_env+0xa0/0x910 LR elog_event+0x1f4/0x2d0 Call Trace: 0x5deadbeef0000122 (unreliable) elog_event+0x1f4/0x2d0 irq_thread_fn+0x4c/0xc0 irq_thread+0x1c0/0x2b0 kthread+0x1c4/0x1d0 ret_from_kernel_thread+0x5c/0x6c 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_elog_obj() returns the elog object which if used by caller function will end up in use-after-free problem again. However, the return value of create_elog_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: 774fea1 ("powerpc/powernv: Read OPAL error log and export it through sysfs") Cc: [email protected] # v3.15+ Reported-by: Oliver O'Halloran <[email protected]> Signed-off-by: Mahesh Salgaonkar <[email protected]> Signed-off-by: Aneesh Kumar K.V <[email protected]> Reviewed-by: Oliver O'Halloran <[email protected]> Reviewed-by: Vasant Hegde <[email protected]> [mpe: Rework the logic to use a single return, reword comments, add oops] Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 45f0ea7 commit 29b6e4e

File tree

1 file changed

+26
-7
lines changed

1 file changed

+26
-7
lines changed

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

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,14 @@ static ssize_t raw_attr_read(struct file *filep, struct kobject *kobj,
183183
return count;
184184
}
185185

186-
static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
186+
static void create_elog_obj(uint64_t id, size_t size, uint64_t type)
187187
{
188188
struct elog_obj *elog;
189189
int rc;
190190

191191
elog = kzalloc(sizeof(*elog), GFP_KERNEL);
192192
if (!elog)
193-
return NULL;
193+
return;
194194

195195
elog->kobj.kset = elog_kset;
196196

@@ -223,18 +223,37 @@ static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
223223
rc = kobject_add(&elog->kobj, NULL, "0x%llx", id);
224224
if (rc) {
225225
kobject_put(&elog->kobj);
226-
return NULL;
226+
return;
227227
}
228228

229+
/*
230+
* As soon as the sysfs file for this elog is created/activated there is
231+
* a chance the opal_errd daemon (or any userspace) might read and
232+
* acknowledge the elog before kobject_uevent() is called. If that
233+
* happens then there is a potential race between
234+
* elog_ack_store->kobject_put() and kobject_uevent() which leads to a
235+
* use-after-free of a kernfs object resulting in a kernel crash.
236+
*
237+
* To avoid that, we need to take a reference on behalf of the bin file,
238+
* so that our reference remains valid while we call kobject_uevent().
239+
* We then drop our reference before exiting the function, leaving the
240+
* bin file to drop the last reference (if it hasn't already).
241+
*/
242+
243+
/* Take a reference for the bin file */
244+
kobject_get(&elog->kobj);
229245
rc = sysfs_create_bin_file(&elog->kobj, &elog->raw_attr);
230-
if (rc) {
246+
if (rc == 0) {
247+
kobject_uevent(&elog->kobj, KOBJ_ADD);
248+
} else {
249+
/* Drop the reference taken for the bin file */
231250
kobject_put(&elog->kobj);
232-
return NULL;
233251
}
234252

235-
kobject_uevent(&elog->kobj, KOBJ_ADD);
253+
/* Drop our reference */
254+
kobject_put(&elog->kobj);
236255

237-
return elog;
256+
return;
238257
}
239258

240259
static irqreturn_t elog_event(int irq, void *data)

0 commit comments

Comments
 (0)