Skip to content

Commit b75a43d

Browse files
committed
[HUST CSE][dfs] fix stack buffer overflow on long path components in devtmpfs
_path_separate() and _get_subdir() copied an unbounded path component into caller-provided buffers, so a single component longer than DIRENT_NAME_MAX (256) bytes overran the 256-byte file_name[]/subdir_name[] stack arrays used by devtmpfs_create_vnode() and devtmpfs_file_lookup(). dentry->pathname can be up to DFS_PATH_MAX - 4 = 4092 bytes because _dentry_create() only strips the mount point prefix, so the overflow length and its contents are attacker controlled. It is reachable from open("/dev/<long name>", O_CREAT) - including from user mode through sys_open() - and from the msh command mkdir /dev/<long name>. On bsp/qemu-vexpress-a9 an over-long single component produced a data abort whose backtrace contained 0x41414141, i.e. the saved return address overwritten with the attacker supplied path bytes. The tmpfs implementation already validates these lengths and returns -ENAMETOOLONG (dfs_tmpfs.c), this brings devtmpfs in line with it: - pass parent_size/file_size to _path_separate() and name_size to _get_subdir(), rejecting oversized components with -ENAMETOOLONG - check the return value at both call sites; create_vnode() and file_lookup() now fail cleanly instead of corrupting the stack [HUST CSE]
1 parent 386b877 commit b75a43d

1 file changed

Lines changed: 48 additions & 8 deletions

File tree

‎components/dfs/dfs_v2/filesystems/devfs/devtmpfs.c‎

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,22 @@ struct devtmpfs_sb
5454

5555
static struct dfs_file_ops _default_fops = { 0 };
5656

57-
static int _path_separate(const char *path, char *parent_path, char *file_name)
57+
static int _path_separate(const char *path, char *parent_path, rt_size_t parent_size,
58+
char *file_name, rt_size_t file_size)
5859
{
5960
const char *path_p, *path_q;
61+
rt_size_t parent_len, file_len;
6062

6163
RT_ASSERT(path[0] == '/');
6264

65+
if (parent_path == RT_NULL || file_name == RT_NULL ||
66+
parent_size < 2 || file_size == 0)
67+
{
68+
return -EINVAL;
69+
}
70+
6371
file_name[0] = '\0';
72+
parent_path[0] = '\0';
6473
path_p = path_q = &path[1];
6574
__next_dir:
6675
while (*path_q != '/' && *path_q != '\0')
@@ -77,10 +86,17 @@ static int _path_separate(const char *path, char *parent_path, char *file_name)
7786
}
7887
else /* Last level dir */
7988
{
80-
rt_memcpy(parent_path, path, path_p - path - 1);
81-
parent_path[path_p - path - 1] = '\0';
82-
rt_memcpy(file_name, path_p, path_q - path_p);
83-
file_name[path_q - path_p] = '\0';
89+
parent_len = path_p - path - 1;
90+
file_len = path_q - path_p;
91+
if (parent_len >= parent_size || file_len >= file_size)
92+
{
93+
return -ENAMETOOLONG;
94+
}
95+
96+
rt_memcpy(parent_path, path, parent_len);
97+
parent_path[parent_len] = '\0';
98+
rt_memcpy(file_name, path_p, file_len);
99+
file_name[file_len] = '\0';
84100
}
85101
}
86102
if (parent_path[0] == 0)
@@ -94,17 +110,31 @@ static int _path_separate(const char *path, char *parent_path, char *file_name)
94110
return 0;
95111
}
96112

97-
static int _get_subdir(const char *path, char *name)
113+
static int _get_subdir(const char *path, char *name, rt_size_t name_size)
98114
{
99115
const char *subpath = path;
116+
rt_size_t name_len = 0;
117+
118+
if (path == RT_NULL || name == RT_NULL || name_size == 0)
119+
{
120+
return -EINVAL;
121+
}
122+
100123
while (*subpath == '/' && *subpath)
101124
subpath ++;
102125
while (*subpath != '/' && *subpath)
103126
{
127+
if (name_len + 1 >= name_size)
128+
{
129+
name[0] = '\0';
130+
return -ENAMETOOLONG;
131+
}
104132
*name = *subpath;
105133
name ++;
106134
subpath ++;
135+
name_len++;
107136
}
137+
*name = '\0';
108138
return 0;
109139
}
110140

@@ -213,7 +243,10 @@ static struct devtmpfs_file *devtmpfs_file_lookup(struct devtmpfs_sb *superblock
213243
subpath ++; /* skip '/' */
214244

215245
memset(subdir_name, 0, DIRENT_NAME_MAX);
216-
_get_subdir(curpath, subdir_name);
246+
if (_get_subdir(curpath, subdir_name, sizeof(subdir_name)) != 0)
247+
{
248+
return NULL;
249+
}
217250

218251
rt_spin_lock(&superblock->lock);
219252

@@ -490,6 +523,7 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
490523
struct devtmpfs_sb *superblock;
491524
struct devtmpfs_file *d_file, *p_file;
492525
char parent_path[DFS_PATH_MAX], file_name[DIRENT_NAME_MAX];
526+
int ret;
493527

494528
if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL)
495529
{
@@ -503,7 +537,13 @@ static struct dfs_vnode *devtmpfs_create_vnode(struct dfs_dentry *dentry, int ty
503537
if (vnode)
504538
{
505539
/* find parent file */
506-
_path_separate(dentry->pathname, parent_path, file_name);
540+
ret = _path_separate(dentry->pathname, parent_path, sizeof(parent_path),
541+
file_name, sizeof(file_name));
542+
if (ret != RT_EOK)
543+
{
544+
dfs_vnode_destroy(vnode);
545+
return NULL;
546+
}
507547
if (file_name[0] == '\0') /* it's root dir */
508548
{
509549
dfs_vnode_destroy(vnode);

0 commit comments

Comments
 (0)