Skip to content

Heap buffer overflows in RT-Thread dfs_v2 dfs_file #8282

Open
@0xdea

Description

@0xdea

Hi,

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

Potential heap buffer overflows in RT-Thread dfs_v2 dfs_file

Summary

I spotted some potential heap buffer overflow vulnerabilities at the following locations in the RT-Thread dfs_v2 dfs_file source code:
https://github.com/RT-Thread/rt-thread/blob/master/components/dfs/dfs_v2/src/dfs_file.c#L234
https://github.com/RT-Thread/rt-thread/blob/master/components/dfs/dfs_v2/src/dfs_file.c#L262
https://github.com/RT-Thread/rt-thread/blob/master/components/dfs/dfs_v2/src/dfs_file.c#L284
https://github.com/RT-Thread/rt-thread/blob/master/components/dfs/dfs_v2/src/dfs_file.c#L314

Details

Lack of length check in the the dfs_nolink_path() function could lead to heap buffer overflows at the marked lines:

static char *dfs_nolink_path(struct dfs_mnt **mnt, char *fullpath, int mode)
{
    int index = 0;
    char *path = RT_NULL;
    char link_fn[DFS_PATH_MAX] = {0};
    struct dfs_dentry *dentry = RT_NULL;

    path = (char *)rt_malloc((DFS_PATH_MAX * 2) + 1); // path + syslink + \0
    if (!path)
    {
        return path;
    }

    if (*mnt && fullpath)
    {
        int i = 0;
        char *fp = fullpath;

        while (*fp != '\0')
        {
            fp++;
            i++;
            if (*fp == '/')
            {
                rt_memcpy(path + index, fp - i, i); /* VULN: if fullpath has components large enough so that i+index becomes larger than DFS_PATH_MAX*2+1, we could overflow past the path buffer */
                path[index + i] = '\0';

                dentry = dfs_dentry_lookup(*mnt, path, 0);
                if (dentry && dentry->vnode->type == FT_SYMLINK)
                {
                    int ret = -1;

                    if ((*mnt)->fs_ops->readlink)
                    {
                        if (dfs_is_mounted((*mnt)) == 0)
                        {
                            ret = (*mnt)->fs_ops->readlink(dentry, link_fn, DFS_PATH_MAX);
                        }
                    }

                    if (ret > 0)
                    {
                        int len = rt_strlen(link_fn);
                        if (link_fn[0] == '/')
                        {
                            rt_memcpy(path, link_fn, len);
                            index = len;
                        }
                        else
                        {
                            path[index] = '/';
                            index++;
                            rt_memcpy(path + index, link_fn, len); /* VULN: len can be DFS_PATH_MAX; if index can become larger than DFS_PATH_MAX+1, we can overflow past the path buffer */
                            index += len;
                        }
                        path[index] = '\0';
                        *mnt = dfs_mnt_lookup(path);
                    }
                    else
                    {
                        rt_kprintf("link error: %s\n", path);
                    }
                }
                else
                {
                    index += i;
                }
                dfs_dentry_unref(dentry);
                i = 0;
            }
        }

        if (i)
        {
            rt_memcpy(path + index, fp - i, i); /* VULN: if fullpath has components large enough so that i+index becomes larger than DFS_PATH_MAX*2+1, we could overflow past the path buffer */
            path[index + i] = '\0';

            if (mode)
            {
                dentry = dfs_dentry_lookup(*mnt, path, 0);
                if (dentry && dentry->vnode->type == FT_SYMLINK)
                {
                    int ret = -1;

                    if ((*mnt)->fs_ops->readlink)
                    {
                        if (dfs_is_mounted((*mnt)) == 0)
                        {
                            ret = (*mnt)->fs_ops->readlink(dentry, link_fn, DFS_PATH_MAX);
                        }
                    }

                    if (ret > 0)
                    {
                        int len = rt_strlen(link_fn);
                        if (link_fn[0] == '/')
                        {
                            rt_memcpy(path, link_fn, len);
                            index = len;
                        }
                        else
                        {
                            path[index] = '/';
                            index++;
                            rt_memcpy(path + index, link_fn, len); /* VULN: len can be DFS_PATH_MAX; if index can become larger than DFS_PATH_MAX+1, we can overflow past the path buffer */
                            index += len;
                        }
                        path[index] = '\0';
                        *mnt = dfs_mnt_lookup(path);
                    }
                    else
                    {
                        rt_kprintf("link error: %s\n", path);
                    }

                    char *_fullpath = dfs_normalize_path(RT_NULL, path);
                    if (_fullpath)
                    {
                        strncpy(path, _fullpath, DFS_PATH_MAX);
                        rt_free(_fullpath);
                    }
                }
                dfs_dentry_unref(dentry);
            }
        }
    }
    else
    {
        rt_free(path);
        path = RT_NULL;
    }

    //rt_kprintf("%s: %s => %s\n", __FUNCTION__, fullpath, path);

    return path;
}

Impact

If an attacker is able to control fullpath above and craft it as required to trigger the reported heap buffer overflow vulnerabilities, their impact could range from denial of service to arbitrary code execution.

Metadata

Metadata

Assignees

Labels

bugThis PR/issue is a bug in the current code.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions