From 74925f43eda4b09bfd26c38beaf366481d784505 Mon Sep 17 00:00:00 2001 From: geniusgogo <2041245+geniusgogo@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:16:21 +0800 Subject: [PATCH] fix dfs path name overflow. (#8305) --- bsp/simulator/drivers/dfs_win32.c | 2 +- .../dfs/dfs_v1/filesystems/elmfat/dfs_elm.c | 2 +- .../dfs/dfs_v1/filesystems/nfs/dfs_nfs.c | 2 +- .../dfs/dfs_v1/filesystems/romfs/dfs_romfs.c | 2 +- .../dfs/dfs_v2/filesystems/elmfat/dfs_elm.c | 2 +- .../dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c | 28 +++- components/dfs/dfs_v2/include/dfs.h | 6 +- components/dfs/dfs_v2/src/dfs.c | 13 +- components/dfs/dfs_v2/src/dfs_file.c | 152 +++++++----------- components/finsh/msh_file.c | 10 ++ components/lwp/lwp_syscall.c | 2 +- 11 files changed, 116 insertions(+), 105 deletions(-) diff --git a/bsp/simulator/drivers/dfs_win32.c b/bsp/simulator/drivers/dfs_win32.c index f87b38b38a..1cdc198cc3 100644 --- a/bsp/simulator/drivers/dfs_win32.c +++ b/bsp/simulator/drivers/dfs_win32.c @@ -346,7 +346,7 @@ static int dfs_win32_getdents(struct dfs_file *file, struct dirent *dirp, rt_uin else d->d_type = DT_REG; d->d_namlen = (rt_uint8_t)strlen(wdirp->curr); - strncpy(d->d_name, wdirp->curr, DFS_PATH_MAX); + strncpy(d->d_name, wdirp->curr, DIRENT_NAME_MAX); d->d_reclen = (rt_uint16_t)sizeof(struct dirent); wdirp->curr += (strlen(wdirp->curr) + 1); file->pos = wdirp->curr - wdirp->start + sizeof(struct dirent);//NOTE! diff --git a/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c b/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c index 5adba36f16..50ec5b6a97 100644 --- a/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c +++ b/components/dfs/dfs_v1/filesystems/elmfat/dfs_elm.c @@ -674,7 +674,7 @@ int dfs_elm_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count) d->d_namlen = (rt_uint8_t)rt_strlen(fn); d->d_reclen = (rt_uint16_t)sizeof(struct dirent); - rt_strncpy(d->d_name, fn, DFS_PATH_MAX); + rt_strncpy(d->d_name, fn, DIRENT_NAME_MAX); index ++; if (index * sizeof(struct dirent) >= count) diff --git a/components/dfs/dfs_v1/filesystems/nfs/dfs_nfs.c b/components/dfs/dfs_v1/filesystems/nfs/dfs_nfs.c index 9adc5b6c42..b24e636184 100644 --- a/components/dfs/dfs_v1/filesystems/nfs/dfs_nfs.c +++ b/components/dfs/dfs_v1/filesystems/nfs/dfs_nfs.c @@ -1144,7 +1144,7 @@ int nfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count) d->d_namlen = rt_strlen(name); d->d_reclen = (rt_uint16_t)sizeof(struct dirent); - rt_strncpy(d->d_name, name, DFS_PATH_MAX); + rt_strncpy(d->d_name, name, DIRENT_NAME_MAX); index ++; if (index * sizeof(struct dirent) >= count) diff --git a/components/dfs/dfs_v1/filesystems/romfs/dfs_romfs.c b/components/dfs/dfs_v1/filesystems/romfs/dfs_romfs.c index 9ecb0819c4..1ae48c27ed 100644 --- a/components/dfs/dfs_v1/filesystems/romfs/dfs_romfs.c +++ b/components/dfs/dfs_v1/filesystems/romfs/dfs_romfs.c @@ -337,7 +337,7 @@ int dfs_romfs_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t coun RT_ASSERT(len <= RT_UINT8_MAX); d->d_namlen = (rt_uint8_t)len; d->d_reclen = (rt_uint16_t)sizeof(struct dirent); - rt_strncpy(d->d_name, name, DFS_PATH_MAX); + rt_strncpy(d->d_name, name, DIRENT_NAME_MAX); /* move to next position */ ++ file->pos; diff --git a/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c b/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c index 5766d7cbe7..5ea5140fc1 100644 --- a/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c +++ b/components/dfs/dfs_v2/filesystems/elmfat/dfs_elm.c @@ -742,7 +742,7 @@ int dfs_elm_getdents(struct dfs_file *file, struct dirent *dirp, uint32_t count) d->d_namlen = (rt_uint8_t)rt_strlen(fn); d->d_reclen = (rt_uint16_t)sizeof(struct dirent); - rt_strncpy(d->d_name, fn, DFS_PATH_MAX); + rt_strncpy(d->d_name, fn, DIRENT_NAME_MAX); index ++; if (index * sizeof(struct dirent) >= count) diff --git a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c index 36d1ea692b..f289fc4419 100644 --- a/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c +++ b/components/dfs/dfs_v2/filesystems/tmpfs/dfs_tmpfs.c @@ -589,7 +589,8 @@ static int dfs_tmpfs_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *ne struct tmpfs_file *d_file, *p_file; struct tmpfs_sb *superblock; rt_size_t size; - char parent_path[DFS_PATH_MAX], file_name[TMPFS_NAME_MAX]; + char *parent_path; + char file_name[TMPFS_NAME_MAX]; superblock = (struct tmpfs_sb *)old_dentry->mnt->data; RT_ASSERT(superblock != NULL); @@ -602,10 +603,19 @@ static int dfs_tmpfs_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *ne if (d_file == NULL) return -ENOENT; + parent_path = rt_malloc(DFS_PATH_MAX); + if (!parent_path) + { + return -ENOMEM; + } + /* find parent file */ _path_separate(new_dentry->pathname, parent_path, file_name); if (file_name[0] == '\0') /* it's root dir */ + { + rt_free(parent_path); return -ENOENT; + } /* open parent directory */ p_file = dfs_tmpfs_lookup(superblock, parent_path, &size); RT_ASSERT(p_file != NULL); @@ -620,6 +630,8 @@ static int dfs_tmpfs_rename(struct dfs_dentry *old_dentry, struct dfs_dentry *ne rt_list_insert_after(&(p_file->subdirs), &(d_file->sibling)); rt_spin_unlock(&superblock->lock); + rt_free(parent_path); + return RT_EOK; } @@ -672,7 +684,8 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t rt_size_t size; struct tmpfs_sb *superblock; struct tmpfs_file *d_file, *p_file; - char parent_path[DFS_PATH_MAX], file_name[TMPFS_NAME_MAX]; + char *parent_path; + char file_name[TMPFS_NAME_MAX]; if (dentry == NULL || dentry->mnt == NULL || dentry->mnt->data == NULL) { @@ -682,6 +695,12 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t superblock = (struct tmpfs_sb *)dentry->mnt->data; RT_ASSERT(superblock != NULL); + parent_path = rt_malloc(DFS_PATH_MAX); + if (!parent_path) + { + return NULL; + } + vnode = dfs_vnode_create(); if (vnode) { @@ -689,6 +708,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t _path_separate(dentry->pathname, parent_path, file_name); if (file_name[0] == '\0') /* it's root dir */ { + rt_free(parent_path); dfs_vnode_destroy(vnode); return NULL; } @@ -697,6 +717,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t p_file = dfs_tmpfs_lookup(superblock, parent_path, &size); if (p_file == NULL) { + rt_free(parent_path); dfs_vnode_destroy(vnode); return NULL; } @@ -705,6 +726,7 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t d_file = (struct tmpfs_file *)rt_calloc(1, sizeof(struct tmpfs_file)); if (d_file == NULL) { + rt_free(parent_path); dfs_vnode_destroy(vnode); return NULL; } @@ -743,6 +765,8 @@ static struct dfs_vnode *dfs_tmpfs_create_vnode(struct dfs_dentry *dentry, int t vnode->size = d_file->size; } + rt_free(parent_path); + return vnode; } diff --git a/components/dfs/dfs_v2/include/dfs.h b/components/dfs/dfs_v2/include/dfs.h index 61c78b62a5..aa3bd84f27 100644 --- a/components/dfs/dfs_v2/include/dfs.h +++ b/components/dfs/dfs_v2/include/dfs.h @@ -53,15 +53,15 @@ * skip stdin/stdout/stderr normally */ #ifndef DFS_STDIO_OFFSET -#define DFS_STDIO_OFFSET 3 +#define DFS_STDIO_OFFSET 3 #endif #ifndef DFS_PATH_MAX -#define DFS_PATH_MAX DIRENT_NAME_MAX +#define DFS_PATH_MAX 4096 #endif #ifndef SECTOR_SIZE -#define SECTOR_SIZE 512 +#define SECTOR_SIZE 512 #endif #define DFS_FS_FLAG_DEFAULT 0x00 /* default flag */ diff --git a/components/dfs/dfs_v2/src/dfs.c b/components/dfs/dfs_v2/src/dfs.c index 04f2657d65..06d353c180 100644 --- a/components/dfs/dfs_v2/src/dfs.c +++ b/components/dfs/dfs_v2/src/dfs.c @@ -583,10 +583,19 @@ char *dfs_normalize_path(const char *directory, const char *filename) if (filename[0] != '/') /* it's a absolute path, use it directly */ { - fullpath = (char *)rt_malloc(strlen(directory) + strlen(filename) + 2); + int path_len; - if (fullpath == NULL) + path_len = strlen(directory) + strlen(filename) + 2; + if (path_len > DFS_PATH_MAX) + { return NULL; + } + + fullpath = (char *)rt_malloc(path_len); + if (fullpath == NULL) + { + return NULL; + } /* join path and file name */ rt_snprintf(fullpath, strlen(directory) + strlen(filename) + 2, diff --git a/components/dfs/dfs_v2/src/dfs_file.c b/components/dfs/dfs_v2/src/dfs_file.c index 7e7df1738d..4bb933a32d 100644 --- a/components/dfs/dfs_v2/src/dfs_file.c +++ b/components/dfs/dfs_v2/src/dfs_file.c @@ -27,9 +27,24 @@ #define DBG_LVL DBG_WARNING #include - #define MAX_RW_COUNT 0xfffc0000 +rt_inline int _find_path_node(const char *path) +{ + int i = 0; + + while (path[i] != '\0') + { + if ('/' == path[i++]) + { + break; + } + } + + /* return path-note length */ + return i; +} + /* * rw_verify_area doesn't like huge counts. We limit * them to something that fits in "int" so that others @@ -143,7 +158,7 @@ struct dfs_dentry* dfs_file_follow_link(struct dfs_dentry *dentry) { char *buf = NULL; - buf = (char *) rt_malloc (DFS_PATH_MAX); + buf = (char *)rt_malloc(DFS_PATH_MAX); if (buf) { do @@ -211,130 +226,83 @@ 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}; + char *link_fn; struct dfs_dentry *dentry = RT_NULL; - path = (char *)rt_malloc((DFS_PATH_MAX * 2) + 1); // path + syslink + \0 + path = (char *)rt_malloc((DFS_PATH_MAX * 2) + 2); // path + \0 + link_fn + \0 if (!path) { return path; } + link_fn = path + DFS_PATH_MAX + 1; if (*mnt && fullpath) { int i = 0; char *fp = fullpath; - while (*fp != '\0') + while ((i = _find_path_node(fp)) > 0) { - fp++; - i++; - if (*fp == '/') + if (i + index > DFS_PATH_MAX) { - rt_memcpy(path + index, fp - i, i); - path[index + i] = '\0'; + goto _ERR_RET; + } - dentry = dfs_dentry_lookup(*mnt, path, 0); - if (dentry && dentry->vnode->type == FT_SYMLINK) + rt_memcpy(path + index, fp, i); + path[index + i] = '\0'; + fp += i; + + dentry = dfs_dentry_lookup(*mnt, path, 0); + if (dentry && dentry->vnode->type == FT_SYMLINK) + { + int ret = -1; + + if ((*mnt)->fs_ops->readlink) { - int ret = -1; - - if ((*mnt)->fs_ops->readlink) + if (dfs_is_mounted((*mnt)) == 0) { - if (dfs_is_mounted((*mnt)) == 0) - { - ret = (*mnt)->fs_ops->readlink(dentry, link_fn, DFS_PATH_MAX); - } + ret = (*mnt)->fs_ops->readlink(dentry, link_fn, DFS_PATH_MAX); } + } - if (ret > 0) + if (ret > 0) + { + int len = rt_strlen(link_fn); + + if (link_fn[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); - index += len; - } - path[index] = '\0'; - *mnt = dfs_mnt_lookup(path); + path[index] = '/'; } else { - rt_kprintf("link error: %s\n", path); + index = 0; } + + if (len + index + 1 >= DFS_PATH_MAX) + { + goto _ERR_RET; + } + + rt_memcpy(path + index, link_fn, len); + index += len; + path[index] = '\0'; + *mnt = dfs_mnt_lookup(path); } else { - index += i; + goto _ERR_RET; } - dfs_dentry_unref(dentry); - i = 0; } - } - - if (i) - { - rt_memcpy(path + index, fp - i, i); - path[index + i] = '\0'; - - if (mode) + else { - 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); - 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); + index += i; } + dfs_dentry_unref(dentry); } } else { +_ERR_RET: rt_free(path); path = RT_NULL; } @@ -1837,7 +1805,7 @@ void ls(const char *pathname) DLOG(msg, "dfs", "dfs_file", DLOG_MSG, "dfs_file_open(%s, O_DIRECTORY, 0)", path); if (dfs_file_open(&file, path, O_DIRECTORY, 0) >= 0) { - char *link_fn = (char *) rt_malloc (DFS_PATH_MAX); + char *link_fn = (char *)rt_malloc(DFS_PATH_MAX); if (link_fn) { rt_kprintf("Directory %s:\n", path); diff --git a/components/finsh/msh_file.c b/components/finsh/msh_file.c index a47ae73f05..ce24768bdf 100644 --- a/components/finsh/msh_file.c +++ b/components/finsh/msh_file.c @@ -343,6 +343,11 @@ static void directory_delete_for_msh(const char *pathname, char f, char v) if (rt_strcmp(".", dirent->d_name) != 0 && rt_strcmp("..", dirent->d_name) != 0) { + if (strlen(pathname) + 1 + strlen(dirent->d_name) > DFS_PATH_MAX) + { + rt_kprintf("cannot remove '%s/%s', path too long.\n", pathname, dirent->d_name); + continue; + } rt_sprintf(full_path, "%s/%s", pathname, dirent->d_name); if (dirent->d_type != DT_DIR) { @@ -862,6 +867,11 @@ static void directory_setattr(const char *pathname, struct dfs_attr *attr, char if (rt_strcmp(".", dirent->d_name) != 0 && rt_strcmp("..", dirent->d_name) != 0) { + if (strlen(pathname) + 1 + strlen(dirent->d_name) > DFS_PATH_MAX) + { + rt_kprintf("'%s/%s' setattr failed, path too long.\n", pathname, dirent->d_name); + continue; + } rt_sprintf(full_path, "%s/%s", pathname, dirent->d_name); if (dirent->d_type == DT_REG) { diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index 90d116db5c..d2177539df 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -4874,7 +4874,7 @@ struct libc_dirent { off_t d_off; unsigned short d_reclen; unsigned char d_type; - char d_name[256]; + char d_name[DIRENT_NAME_MAX]; }; sysret_t sys_getdents(int fd, struct libc_dirent *dirp, size_t nbytes)