RT-Thread / RT-Thread/rt-thread

Out-of-bounds static array access in RT-Thread var_export utility

Open
#8,290 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

Hi,

I would like to report another potential vulnerability in the current version of RT-Thread. Please let me know if you plan to ask for a CVE ID in case the vulnerability is confirmed. I'm available if you need further clarifications.

Potential out-of-bounds static array access in RT-Thread var_export utility

Summary

I spotted a potential out-of-bounds static array access at the following location in the RT-Thread var_export utility source code:
https://github.com/RT-Thread/rt-thread/blob/master/components/utilities/var_export/var_export.c#L97-L122

Details

Improper size check due to the use of RT_ASSERT() in the var_export_init() function at the marked line, which if compiled out in production code could lead to multiple out-of-bounds ve_exporter_tab static array accesses in the next lines:

int var_export_init(void)
{
    /* initialize the var export table.*/
#if defined(__ARMCC_VERSION)                        /* for ARM C Compiler */
    ve_exporter_table = &__ve_table_start + 1;
    ve_exporter_num = &__ve_table_end - &__ve_table_start;
#elif defined (__IAR_SYSTEMS_ICC__)                 /* for IAR Compiler */
    ve_exporter_table = &__ve_table_start + 1;
    ve_exporter_num = &__ve_table_end - &__ve_table_start - 1;
#elif defined (__GNUC__)                            /* for GCC Compiler */
    extern const int __ve_table_start;
    extern const int __ve_table_end;
    ve_exporter_table = (const ve_exporter_t *)&__ve_table_start;
    ve_exporter_num = (const ve_exporter_t *)&__ve_table_end - ve_exporter_table;
#elif defined (_MSC_VER)                            /* for MS VC++ compiler */
    unsigned int *ptr_begin = (unsigned int *)&__ve_table_start;
    unsigned int *ptr_end = (unsigned int *)&__ve_table_end;
    static ve_exporter_t ve_exporter_tab[2048];
    static char __vexp_strbuf1[1024];
    static char __vexp_strbuf2[1024];
    ve_exporter_t ve_exporter_temp;
    rt_size_t index_i, index_j;

    /* past the three members in first ptr_begin */
    ptr_begin += (sizeof(struct ve_exporter) / sizeof(unsigned int));
    while (*ptr_begin == 0) ptr_begin++;
    do ptr_end--; while (*ptr_end == 0);

    /* Find var objects in custom segments to solve the problem of holes in objects in different files */
    ve_exporter_num = ve_init_find_obj(ptr_begin, ptr_end, ve_exporter_tab);

    /* check if the ve_exporter_num is out of bounds */
    RT_ASSERT(ve_exporter_num < (sizeof(ve_exporter_tab) / sizeof(ve_exporter_t))); /* VULN: size check is implemented via assertion */

    /* bubble sort algorithms */
    for (index_i = 0; index_i < (ve_exporter_num - 1); index_i++)
    {
        for (index_j = 0; index_j < ((ve_exporter_num - 1) - index_i); index_j++)
        {
            /* splice ve_exporter's module and ve_exporter's identifier into a complete string */
            rt_snprintf(__vexp_strbuf1,
                        sizeof(__vexp_strbuf1),
                        "%s%s",
                        ve_exporter_tab[index_j].module,
                        ve_exporter_tab[index_j].identifier);
            rt_snprintf(__vexp_strbuf2,
                        sizeof(__vexp_strbuf2),
                        "%s%s",
                        ve_exporter_tab[index_j + 1].module,
                        ve_exporter_tab[index_j + 1].identifier);
            if (rt_strcmp(__vexp_strbuf1, __vexp_strbuf2) > 0)
            {
                ve_exporter_temp = ve_exporter_tab[index_j];
                ve_exporter_tab[index_j] = ve_exporter_tab[index_j + 1];
                ve_exporter_tab[index_j + 1] = ve_exporter_temp;
            }
        }
    }

    ve_exporter_table = ve_exporter_tab;
#endif /* __ARMCC_VERSION */

    return ve_exporter_num;
}
Impact

If the unchecked input above is confirmed to be attacker-controlled and crossing a security boundary, the impact of the reported buffer overflow vulnerability could range from denial of service to arbitrary code execution.

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 with components/utilities/var_export/var_export.c, especially var_export_init() and the MSVC branch around lines 97-122. Review how ve_init_find_obj() sets ve_exporter_num, whether the RT_ASSERT() check is sufficient in production builds, and whether the subsequent table accesses remain bounded; done means the reported condition is confirmed or safely addressed and its behavior is verified.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
embedded-iot, operating-systems, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.