Browse Source

kernel/testcase: fixed buffer overflow vulnerability in object

kurisaw 1 week ago
parent
commit
ece19e961a

+ 4 - 0
examples/utest/testcases/kernel/Kconfig

@@ -1,5 +1,9 @@
 menu "Kernel Testcase"
 menu "Kernel Testcase"
 
 
+config UTEST_OBJECT_TC
+    bool "object test"
+    default y
+
 config UTEST_MEMHEAP_TC
 config UTEST_MEMHEAP_TC
     bool "memheap stability test"
     bool "memheap stability test"
     default y
     default y

+ 3 - 0
examples/utest/testcases/kernel/SConscript

@@ -5,6 +5,9 @@ cwd     = GetCurrentDir()
 src     = []
 src     = []
 CPPPATH = [cwd]
 CPPPATH = [cwd]
 
 
+if GetDepend(['UTEST_OBJECT_TC']):
+    src += ['object_tc.c']
+
 if GetDepend(['UTEST_MEMHEAP_TC']):
 if GetDepend(['UTEST_MEMHEAP_TC']):
     src += ['memheap_tc.c']
     src += ['memheap_tc.c']
 
 

+ 97 - 0
examples/utest/testcases/kernel/object_tc.c

@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006-2025, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2025-07-18     kurisaW      First commit
+ */
+
+#include <utest.h>
+#include <rtthread.h>
+#include <string.h>
+
+/**
+ * @brief   Test case for verifying object name handling functionality
+ *
+ * @note    This test suite validates:
+ *          1. Proper truncation of long object names
+ *          2. Correct NULL name handling
+ *          3. Exact length name preservation
+ *          4. Both static and dynamic object initialization
+ *          5. Memory safety and boundary conditions
+ */
+
+static void test_object_name_handling(void)
+{
+    struct rt_object static_obj1;
+    struct rt_object static_obj2;
+    struct rt_object static_obj3;
+    rt_object_t dyn_obj = RT_NULL;
+    char test_name[RT_NAME_MAX + 5];
+
+    for (int i = 0; i < sizeof(test_name) - 1; i++)
+    {
+        test_name[i] = 'A' + (i % 26);
+    }
+    test_name[sizeof(test_name) - 1] = '\0';
+
+    /* Test 1: Static Object Initialization - Extra Long Name */
+    rt_object_init(&static_obj1, RT_Object_Class_Thread, test_name);
+    uassert_true(rt_strlen(static_obj1.name) <= RT_NAME_MAX - 1);
+    uassert_true(static_obj1.name[RT_NAME_MAX - 1] == '\0');
+
+    /* Test 2: Dynamic Object Allocation */
+    dyn_obj = rt_object_allocate(RT_Object_Class_Thread, test_name);
+    uassert_not_null(dyn_obj);
+    if (dyn_obj)
+    {
+        uassert_true(rt_strlen(dyn_obj->name) <= RT_NAME_MAX - 1);
+        uassert_true(dyn_obj->name[RT_NAME_MAX - 1] == '\0');
+        rt_object_delete(dyn_obj);
+        dyn_obj = RT_NULL;
+    }
+
+    /* Test 3: NULL Name Handling - Using New Static Object */
+    rt_object_init(&static_obj2, RT_Object_Class_Thread, NULL);
+    uassert_true(static_obj2.name[0] == '\0');
+
+    /* Test 4: Dynamic Object with NULL Name */
+    dyn_obj = rt_object_allocate(RT_Object_Class_Thread, NULL);
+    uassert_not_null(dyn_obj);
+    if (dyn_obj)
+    {
+        uassert_true(dyn_obj->name[0] == '\0');
+        rt_object_delete(dyn_obj);
+        dyn_obj = RT_NULL;
+    }
+
+    /* Test 5: Fixed-Length Name - Using Third Static Object */
+    char exact_name[RT_NAME_MAX];
+    rt_memset(exact_name, 'B', RT_NAME_MAX - 1);
+    exact_name[RT_NAME_MAX - 1] = '\0';
+
+    rt_object_init(&static_obj3, RT_Object_Class_Thread, exact_name);
+    uassert_str_equal(static_obj3.name, exact_name);
+
+    rt_object_detach(&static_obj1);
+    rt_object_detach(&static_obj2);
+    rt_object_detach(&static_obj3);
+}
+
+static rt_err_t testcase_init(void)
+{
+    return RT_EOK;
+}
+
+static rt_err_t testcase_cleanup(void)
+{
+    return RT_EOK;
+}
+
+static void test_object_suite(void)
+{
+    UTEST_UNIT_RUN(test_object_name_handling);
+}
+UTEST_TC_EXPORT(test_object_suite, "testcases.kernel.object_test", testcase_init, testcase_cleanup, 10);

+ 26 - 4
src/object.c

@@ -355,6 +355,7 @@ void rt_object_init(struct rt_object         *object,
                     const char               *name)
                     const char               *name)
 {
 {
     rt_base_t level;
     rt_base_t level;
+    rt_size_t len;
 #ifdef RT_DEBUGING_ASSERT
 #ifdef RT_DEBUGING_ASSERT
     struct rt_list_node *node = RT_NULL;
     struct rt_list_node *node = RT_NULL;
 #endif /* RT_DEBUGING_ASSERT */
 #endif /* RT_DEBUGING_ASSERT */
@@ -390,10 +391,20 @@ void rt_object_init(struct rt_object         *object,
     /* set object type to static */
     /* set object type to static */
     object->type = type | RT_Object_Class_Static;
     object->type = type | RT_Object_Class_Static;
 #if RT_NAME_MAX > 0
 #if RT_NAME_MAX > 0
-    rt_strncpy(object->name, name, RT_NAME_MAX);  /* copy name */
+    if (name)
+    {
+        len = rt_strlen(name);
+        len = len > RT_NAME_MAX - 1 ? RT_NAME_MAX - 1 : len;
+        rt_memcpy(object->name, name, len);
+        object->name[len] = '\0';
+    }
+    else
+    {
+        object->name[0] = '\0';
+    }
 #else
 #else
     object->name = name;
     object->name = name;
-#endif /* RT_NAME_MAX > 0 */
+#endif
 
 
     RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
     RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
 
 
@@ -461,6 +472,7 @@ rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
 {
 {
     struct rt_object *object;
     struct rt_object *object;
     rt_base_t level;
     rt_base_t level;
+    rt_size_t len;
     struct rt_object_information *information;
     struct rt_object_information *information;
 #ifdef RT_USING_MODULE
 #ifdef RT_USING_MODULE
     struct rt_dlmodule *module = dlmodule_self();
     struct rt_dlmodule *module = dlmodule_self();
@@ -491,10 +503,20 @@ rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
     object->flag = 0;
     object->flag = 0;
 
 
 #if RT_NAME_MAX > 0
 #if RT_NAME_MAX > 0
-    rt_strncpy(object->name, name, RT_NAME_MAX - 1); /* copy name */
+    if (name)
+    {
+        len = rt_strlen(name);
+        len = len > RT_NAME_MAX - 1 ? RT_NAME_MAX - 1 : len;
+        rt_memcpy(object->name, name, len);
+        object->name[len] = '\0';
+    }
+    else
+    {
+        object->name[0] = '\0';
+    }
 #else
 #else
     object->name = name;
     object->name = name;
-#endif /* RT_NAME_MAX > 0 */
+#endif
 
 
     RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));
     RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));