Skip to content

Commit f2c6dbd

Browse files
sulixshuahkh
authored andcommitted
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. Further, add a kunit_ variant of strdup_const() and kfree_const(), so we don't need to allocate and manage the string in the majority of cases where it's a constant. However, these are inline functions, and is_kernel_rodata() only works for built-in code. This causes problems in two cases: - If kunit is built as a module, __{start,end}_rodata is not defined. - If a kunit test using these functions is built as a module, it will suffer the same fate. This fixes a KASAN splat with overflow.overflow_allocation_test, when built as a module. Restrict the is_kernel_rodata() case to when KUnit is built as a module, which fixes the first case, at the cost of losing the optimisation. Also, make kunit_{kstrdup,kfree}_const non-inline, so that other modules using them will not accidentally depend on is_kernel_rodata(). If KUnit is built-in, they'll benefit from the optimisation, if KUnit is not, they won't, but the string will be properly duplicated. Fixes: d03c720 ("kunit: Add APIs for managing devices") Reported-by: Nico Pache <[email protected]> Closes: https://groups.google.com/g/kunit-dev/c/81V9b9QYON0 Reviewed-by: Kees Cook <[email protected]> Reviewed-by: Maxime Ripard <[email protected]> Reviewed-by: Rae Moar <[email protected]> Signed-off-by: David Gow <[email protected]> Tested-by: Rae Moar <[email protected]> Signed-off-by: Shuah Khan <[email protected]>
1 parent 8400291 commit f2c6dbd

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed

include/kunit/test.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <linux/types.h>
2929

3030
#include <asm/rwonce.h>
31+
#include <asm/sections.h>
3132

3233
/* Static key: true if any KUnit tests are currently running */
3334
DECLARE_STATIC_KEY_FALSE(kunit_running);
@@ -480,6 +481,53 @@ static inline void *kunit_kcalloc(struct kunit *test, size_t n, size_t size, gfp
480481
return kunit_kmalloc_array(test, n, size, gfp | __GFP_ZERO);
481482
}
482483

484+
485+
/**
486+
* kunit_kfree_const() - conditionally free test managed memory
487+
* @x: pointer to the memory
488+
*
489+
* Calls kunit_kfree() only if @x is not in .rodata section.
490+
* See kunit_kstrdup_const() for more information.
491+
*/
492+
void kunit_kfree_const(struct kunit *test, const void *x);
493+
494+
/**
495+
* kunit_kstrdup() - Duplicates a string into a test managed allocation.
496+
*
497+
* @test: The test context object.
498+
* @str: The NULL-terminated string to duplicate.
499+
* @gfp: flags passed to underlying kmalloc().
500+
*
501+
* See kstrdup() and kunit_kmalloc_array() for more information.
502+
*/
503+
static inline char *kunit_kstrdup(struct kunit *test, const char *str, gfp_t gfp)
504+
{
505+
size_t len;
506+
char *buf;
507+
508+
if (!str)
509+
return NULL;
510+
511+
len = strlen(str) + 1;
512+
buf = kunit_kmalloc(test, len, gfp);
513+
if (buf)
514+
memcpy(buf, str, len);
515+
return buf;
516+
}
517+
518+
/**
519+
* kunit_kstrdup_const() - Conditionally duplicates a string into a test managed allocation.
520+
*
521+
* @test: The test context object.
522+
* @str: The NULL-terminated string to duplicate.
523+
* @gfp: flags passed to underlying kmalloc().
524+
*
525+
* Calls kunit_kstrdup() only if @str is not in the rodata section. Must be freed with
526+
* kunit_kfree_const() -- not kunit_kfree().
527+
* See kstrdup_const() and kunit_kmalloc_array() for more information.
528+
*/
529+
const char *kunit_kstrdup_const(struct kunit *test, const char *str, gfp_t gfp);
530+
483531
/**
484532
* kunit_vm_mmap() - Allocate KUnit-tracked vm_mmap() area
485533
* @test: The test context object.

lib/kunit/device.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ struct device_driver *kunit_driver_create(struct kunit *test, const char *name)
8989
if (!driver)
9090
return ERR_PTR(err);
9191

92-
driver->name = name;
92+
driver->name = kunit_kstrdup_const(test, name, GFP_KERNEL);
9393
driver->bus = &kunit_bus_type;
9494
driver->owner = THIS_MODULE;
9595

@@ -192,8 +192,11 @@ void kunit_device_unregister(struct kunit *test, struct device *dev)
192192
const struct device_driver *driver = to_kunit_device(dev)->driver;
193193

194194
kunit_release_action(test, device_unregister_wrapper, dev);
195-
if (driver)
195+
if (driver) {
196+
const char *driver_name = driver->name;
196197
kunit_release_action(test, driver_unregister_wrapper, (void *)driver);
198+
kunit_kfree_const(test, driver_name);
199+
}
197200
}
198201
EXPORT_SYMBOL_GPL(kunit_device_unregister);
199202

lib/kunit/test.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,25 @@ void kunit_kfree(struct kunit *test, const void *ptr)
874874
}
875875
EXPORT_SYMBOL_GPL(kunit_kfree);
876876

877+
void kunit_kfree_const(struct kunit *test, const void *x)
878+
{
879+
#if !IS_MODULE(CONFIG_KUNIT)
880+
if (!is_kernel_rodata((unsigned long)x))
881+
#endif
882+
kunit_kfree(test, x);
883+
}
884+
EXPORT_SYMBOL_GPL(kunit_kfree_const);
885+
886+
const char *kunit_kstrdup_const(struct kunit *test, const char *str, gfp_t gfp)
887+
{
888+
#if !IS_MODULE(CONFIG_KUNIT)
889+
if (is_kernel_rodata((unsigned long)str))
890+
return str;
891+
#endif
892+
return kunit_kstrdup(test, str, gfp);
893+
}
894+
EXPORT_SYMBOL_GPL(kunit_kstrdup_const);
895+
877896
void kunit_cleanup(struct kunit *test)
878897
{
879898
struct kunit_resource *res;

0 commit comments

Comments
 (0)