On Tue, 23 Jul 2024 at 13:52, Nico Pache <
npa...@redhat.com> wrote:
>
> Hi Kees and David,
>
> The overflow kunit test started failing in Fedora recently. The change
> that seems to be causing the issue is 837018388e18 ("overflow: Replace
> fake root_device with kunit_device"). Before this the test was
> passing. I've managed to capture a KASAN splat relating to this issue.
>
> It seems like before the $commit, the device would do its own
> unregistering. Now that the kunit framework is handling the device
> cleanup it borks somewhere along the way. I tried tracking down the
> issue, but couldn't spot the issue.
>
> My guess is that we need to properly hold a reference to the driver
> resource, until the device is cleaned up, or vice versa. But i'm sure
> David has a better idea of what might be happening here.
>
> The splat below is from a RHEL kernel, but we're seeing this issue on
> the latest upstream kernel as well.
>
> --Nico
>
Thanks, Nico. It took a while to reproduce this (it only seems to
happen here when the test is built as a module), but I think I've
worked it out.
The problem is the driver name (which for KUnit-managed drivers is the
same as the device name). For the overflow test, this seems to be on
the stack, so it's no-longer valid by the time the test has finished
and cleanup is occurring.
I think the correct solution here is to update the KUnit device
wrappers to strdup() the name and manage it themselves, rather than
forcing it to be statically allocated (or leaked).
The following patch seems to fix it here:
---
From 0e1d041ee95f4503927091d70c613cc3ad032034 Mon Sep 17 00:00:00 2001
From: David Gow <
davi...@google.com>
Date: Sat, 27 Jul 2024 14:40:46 +0800
Subject: [RFC PATCH] kunit: Device wrappers should also manage driver name
kunit_driver_create() accepts a name for the driver, but does not copy
it, so if that name is either on the stack, or otherwise freed, we end
up with a use-after-free when the driver is cleaned up.
Instead, strdup() the name, and manage it as another KUnit allocation.
As there was no existing kunit_kstrdup(), we add one.
This fixes a KASAN splat with overflow.overflow_allocation_test, when
built as a module.
Fixes: d03c720e03bd ("kunit: Add APIs for managing devices")
Reported-by: Nico Pache <
npa...@redhat.com>
Closes:
https://groups.google.com/g/kunit-dev/c/81V9b9QYON0
Signed-off-by: David Gow <
davi...@google.com>
---
include/kunit/test.h | 24 ++++++++++++++++++++++++
lib/kunit/device.c | 7 +++++--
2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/include/kunit/test.h b/include/kunit/test.h
index e2a1f0928e8b..ddbff1f4ed1d 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -480,6 +480,30 @@ static inline void *kunit_kcalloc(struct kunit
*test, size_t n, size_t size, gfp
return kunit_kmalloc_array(test, n, size, gfp | __GFP_ZERO);
}
+/**
+ * kunit_kstrdup() - Duplicates a string into a test managed allocation.
+ *
+ * @test: The test context object.
+ * @str: The NULL-terminated string to duplicate.
+ * @gfp: flags passed to underlying kmalloc().
+ *
+ * See kstrdup() and kunit_kmalloc_array() for mor information.
+ */
+static inline void *kunit_kstrdup(struct kunit *test, const char
*str, gfp_t gfp)
+{
+ size_t len;
+ char *buf;
+
+ if (!str)
+ return NULL;
+
+ len = strlen(str) + 1;
+ buf = kunit_kmalloc(test, len, gfp);
+ if (buf)
+ memcpy(buf, str, len);
+ return buf;
+}
+
/**
* kunit_vm_mmap() - Allocate KUnit-tracked vm_mmap() area
* @test: The test context object.
diff --git a/lib/kunit/device.c b/lib/kunit/device.c
index 25c81ed465fb..54fac5873672 100644
--- a/lib/kunit/device.c
+++ b/lib/kunit/device.c
@@ -89,7 +89,7 @@ struct device_driver *kunit_driver_create(struct
kunit *test, const char *name)
if (!driver)
return ERR_PTR(err);
- driver->name = name;
+ driver->name = kunit_kstrdup(test, name, GFP_KERNEL);
driver->bus = &kunit_bus_type;
driver->owner = THIS_MODULE;
@@ -192,8 +192,11 @@ void kunit_device_unregister(struct kunit *test,
struct device *dev)
const struct device_driver *driver = to_kunit_device(dev)->driver;
kunit_release_action(test, device_unregister_wrapper, dev);
- if (driver)
+ if (driver) {
+ const char *driver_name = driver->name;
kunit_release_action(test, driver_unregister_wrapper, (void *)driver);
+ kunit_kfree(test, driver_name);
+ }
}
EXPORT_SYMBOL_GPL(kunit_device_unregister);
--
2.46.0.rc1.232.g9752f9e123-goog
---
(Let me know if gmail has broken the formatting there...)
I may try to do something akin to kstrdup_const() to optimize this for
the common name-is-constant case.
Cheers,
-- David