RT-Thread / RT-Thread/rt-thread

[Bug] Multiple Bug Report When Running the System

Open
#9,875 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C
Stars
12.2k
Forks
5.4k
Avg merge
4d 12h
Merged PRs (30d)
40

Description

RT-Thread Version

2f55990

Hardware Type/Architectures

QEMU/arm32

Develop Toolchain

GCC

Describe the bug

Hi, when I test the RTthread with our fuzzing tool, we encounter several crashes in kernel.

Step to reproduce

To reproduce, modify the rtthread/rt-thread/bsp/qemu-vexpress-a9.
run scons . and run with qemu-nographic.sh for each crash at a time can observe the crash.

The following are the reproducer program

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <rtthread.h>
long syz_event_recv(volatile int event, volatile int set, volatile int option, volatile int timeout, volatile int recved) {
    rt_uint32_t recv;
    rt_err_t result = rt_event_recv((rt_event_t)event, (rt_uint32_t)set, (rt_uint8_t)option, (rt_int32_t)timeout, &recv);
    if (result != RT_EOK) {
        //rt_kprintf("Failed to receive event: %d\n", result);
        return -1;
    }
    *(rt_uint32_t *)recved = recv;
    return 0;
}
void syz_traverse_object_list() {
    rt_object_t obj = RT_NULL;
    rt_list_t *node = RT_NULL;

    //rt_kprintf("Traversing object list:\n");
    rt_list_for_each(node, &(obj_info.object_list)) {
        obj = rt_list_entry(node, struct rt_object, list);
        //rt_kprintf("Object name: %s\n", obj->name);
    }
}
long syz_mp_complex_usage(volatile int mp_handle) {
    // Attempt to allocate multiple blocks
    void *blocks[10];
    for (int i = 0; i < 10; i++) {
        blocks[i] = rt_mp_alloc((rt_mp_t)mp_handle, RT_WAITING_NO);
        if (blocks[i] == RT_NULL) {
            //rt_kprintf("Failed to allocate block at index %d.\n", i);
            // Attempt to free all allocated blocks so far
            for (int j = 0; j < i; j++) {
                rt_mp_free(blocks[j]);
            }
            return -1; // Failure
        }
    }
  
    for (int i = 0; i < 10; i++) {
        rt_mp_free(blocks[i]);
    }
    return 0; // Success
}
void syz_object_init_update_info() {
    rt_object_init(&obj_example, RT_Object_Class_Thread, "et");
    obj_info.type = RT_Object_Class_Thread;
    rt_list_insert_after(&(obj_info.object_list), &(obj_example.list));
    obj_info.object_size = sizeof(obj_example);
}
void syz_system_heap_init() {
    void *begin_addr = malloc(1024 * 1024);
    void *end_addr = begin_addr + 1024 * 1024;
    rt_system_heap_init(begin_addr, end_addr);
}
long syz_event_send(volatile int event, volatile int set) {
    rt_err_t result = rt_event_send((rt_event_t)event, (rt_uint32_t)set);
    if (result != RT_EOK) {
        //rt_kprintf("Failed to send event: %d\n", result);
        return -1;
    }
    return 0;
}
int main(void)
{
    executor_check_ints();
    rt_kprintf("Hello RT-Thread!\n");
    rt_kprintf("Starting executor.\n");
//  crash 1
    syz_event_recv (0x4, 0x0, 0x2, 0x0, 0xa000);
//  crash 2
    syz_traverse_object_list();
//  crash 3
    syz_mp_complex_usage (0xc4);
//  crash 4
    syz_object_init_update_info();
//  crash 5
    syz_system_heap_init();
//  crash 6
    syz_event_send (0x7fff, 0x0);
    rt_kprintf("Finish executor.\n");
    return 0;
}

System Logs:

crash 1:

it end up in

rt_uint8_t rt_object_get_type(rt_object_t object)
{
    /* object check */
    RT_ASSERT(object != RT_NULL);
    return object->type & ~RT_Object_Class_Static;
}

where failed to check the validity of object->type & ~RT_Object_Class_Static; cause the crash.

crash 2:

It ends up in

rt_inline int rt_list_isempty(const rt_list_t *l)
{
    return l->next == l;
}

My guess is there might be a illegal memory access in return l->next == l;, but I failed to analyze the actual case here.

crash 3:

The program crashed at thread = rt_thread_self();, but I failed to debug deeper, as it directly crashed at rt_thread_self.

void *rt_mp_alloc(rt_mp_t mp, rt_int32_t time)
{
    rt_uint8_t *block_ptr;
    rt_base_t level;
    struct rt_thread *thread;
    rt_uint32_t before_sleep = 0;

    /* parameter check */
    RT_ASSERT(mp != RT_NULL);

    /* get current thread */
    thread = rt_thread_self();
crash 4:

The program crashed at type = (enum rt_object_class_type)(type & ~RT_Object_Class_Static);, similar to crash 1, where it seems to fail to check the vadaility of a certain value and trigger this error.

struct rt_object_information *
rt_object_get_information(enum rt_object_class_type type)
{
    int index;

    type = (enum rt_object_class_type)(type & ~RT_Object_Class_Static);

    for (index = 0; index < RT_Object_Info_Unknown; index ++)
        if (_object_container[index].type == type) return &_object_container[index];

    return RT_NULL;
}
crash 5:

It ends up in _heap_lock, where seems rt_spin_lock_irqsave triggers an illegal memory access.

rt_inline rt_base_t _heap_lock(void)
{
#if defined(RT_USING_HEAP_ISR)
    return rt_spin_lock_irqsave(&_heap_spinlock);
#elif defined(RT_USING_MUTEX)
    if (rt_thread_self())
        return rt_mutex_take(&_lock, RT_WAITING_FOREVER);
crash 6:

It crashed at rt_event_send, where seems failed to check the validity of event.

long syz_event_send(volatile int event, volatile int set) {
    rt_err_t result = rt_event_send((rt_event_t)event, (rt_uint32_t)set);
    if (result != RT_EOK) {
        //rt_kprintf("Failed to send event: %d\n", result);
        return -1;
    }
    return 0;
}

It would be so nice of you to review this bug report. Thank you again for taking the time. Any suggestions or feedback you can provide would be very helpful.

Best regards,

Other additional context

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in bsp/qemu-vexpress-a9, build with scons ., and run qemu-nographic.sh separately for each reproducer. Trace the listed entry points, including rt_event_recv, rt_list_isempty, rt_mp_alloc, rt_object_get_information, _heap_lock, and rt_event_send, then determine which crashes are reproducible kernel defects versus invalid inputs. Done means each reported crash has a documented disposition and confirmed regression coverage where applicable.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
embedded-iot, operating-systems, testing-qa
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.