romfs_dev: Replaced the romFS_dir()/romFS_file() macros with funcs which have actual bounds-checking, this fixes crashes/hangs when the romfs tables are corrupted. Updated relevant code to handle this / various improvements, and return ENOENT instead of EEXIST where required.

This commit is contained in:
yellows8 2019-11-11 11:07:46 -05:00
parent cc64ec7236
commit ce570a70f1
No known key found for this signature in database
GPG Key ID: 0AF90DA3F1E60E43

View File

@ -43,12 +43,26 @@ extern int __system_argc;
extern char** __system_argv; extern char** __system_argv;
#define romFS_root(m) ((romfs_dir*)(m)->dirTable) #define romFS_root(m) ((romfs_dir*)(m)->dirTable)
#define romFS_dir(m,x) ((romfs_dir*) ((u8*)(m)->dirTable + (x)))
#define romFS_file(m,x) ((romfs_file*)((u8*)(m)->fileTable + (x)))
#define romFS_none ((u32)~0) #define romFS_none ((u32)~0)
#define romFS_dir_mode (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH) #define romFS_dir_mode (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH)
#define romFS_file_mode (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH) #define romFS_file_mode (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH)
static romfs_dir *romFS_dir(romfs_mount *mount, u32 off)
{
if (off + sizeof(romfs_dir) > mount->header.dirTableSize) return NULL;
romfs_dir* curDir = ((romfs_dir*) ((u8*)mount->dirTable + off));
if (off + sizeof(romfs_dir) + curDir->nameLen > mount->header.dirTableSize) return NULL;
return curDir;
}
static romfs_file *romFS_file(romfs_mount *mount, u32 off)
{
if (off + sizeof(romfs_file) > mount->header.fileTableSize) return NULL;
romfs_file* curFile = ((romfs_file*) ((u8*)mount->fileTable + off));
if (off + sizeof(romfs_file) + curFile->nameLen > mount->header.fileTableSize) return NULL;
return curFile;
}
static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u64 size) static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u64 size)
{ {
u64 pos = mount->offset + offset; u64 pos = mount->offset + offset;
@ -413,38 +427,44 @@ static u32 calcHash(u32 parent, const uint8_t* name, u32 namelen, u32 total)
return hash % total; return hash % total;
} }
static romfs_dir* searchForDir(romfs_mount *mount, romfs_dir* parent, const uint8_t* name, u32 namelen) static int searchForDir(romfs_mount *mount, romfs_dir* parent, const uint8_t* name, u32 namelen, romfs_dir** out)
{ {
u64 parentOff = (uintptr_t)parent - (uintptr_t)mount->dirTable; u64 parentOff = (uintptr_t)parent - (uintptr_t)mount->dirTable;
u32 hash = calcHash(parentOff, name, namelen, mount->header.dirHashTableSize/4); u32 hash = calcHash(parentOff, name, namelen, mount->header.dirHashTableSize/4);
romfs_dir* curDir = NULL; romfs_dir* curDir = NULL;
u32 curOff; u32 curOff;
*out = NULL;
for (curOff = mount->dirHashTable[hash]; curOff != romFS_none; curOff = curDir->nextHash) for (curOff = mount->dirHashTable[hash]; curOff != romFS_none; curOff = curDir->nextHash)
{ {
curDir = romFS_dir(mount, curOff); curDir = romFS_dir(mount, curOff);
if (curDir == NULL) return EFAULT;
if (curDir->parent != parentOff) continue; if (curDir->parent != parentOff) continue;
if (curDir->nameLen != namelen) continue; if (curDir->nameLen != namelen) continue;
if (memcmp(curDir->name, name, namelen) != 0) continue; if (memcmp(curDir->name, name, namelen) != 0) continue;
return curDir; *out = curDir;
return 0;
} }
return NULL; return ENOENT;
} }
static romfs_file* searchForFile(romfs_mount *mount, romfs_dir* parent, const uint8_t* name, u32 namelen) static int searchForFile(romfs_mount *mount, romfs_dir* parent, const uint8_t* name, u32 namelen, romfs_file** out)
{ {
u64 parentOff = (uintptr_t)parent - (uintptr_t)mount->dirTable; u64 parentOff = (uintptr_t)parent - (uintptr_t)mount->dirTable;
u32 hash = calcHash(parentOff, name, namelen, mount->header.fileHashTableSize/4); u32 hash = calcHash(parentOff, name, namelen, mount->header.fileHashTableSize/4);
romfs_file* curFile = NULL; romfs_file* curFile = NULL;
u32 curOff; u32 curOff;
*out = NULL;
for (curOff = mount->fileHashTable[hash]; curOff != romFS_none; curOff = curFile->nextHash) for (curOff = mount->fileHashTable[hash]; curOff != romFS_none; curOff = curFile->nextHash)
{ {
curFile = romFS_file(mount, curOff); curFile = romFS_file(mount, curOff);
if (curFile == NULL) return EFAULT;
if (curFile->parent != parentOff) continue; if (curFile->parent != parentOff) continue;
if (curFile->nameLen != namelen) continue; if (curFile->nameLen != namelen) continue;
if (memcmp(curFile->name, name, namelen) != 0) continue; if (memcmp(curFile->name, name, namelen) != 0) continue;
return curFile; *out = curFile;
return 0;
} }
return NULL; return ENOENT;
} }
static int navigateToDir(romfs_mount *mount, romfs_dir** ppDir, const char** pPath, bool isDir) static int navigateToDir(romfs_mount *mount, romfs_dir** ppDir, const char** pPath, bool isDir)
@ -490,13 +510,15 @@ static int navigateToDir(romfs_mount *mount, romfs_dir** ppDir, const char** pPa
if (component[1]=='.' && !component[2]) if (component[1]=='.' && !component[2])
{ {
*ppDir = romFS_dir(mount, (*ppDir)->parent); *ppDir = romFS_dir(mount, (*ppDir)->parent);
if (!*ppDir)
return EFAULT;
continue; continue;
} }
} }
*ppDir = searchForDir(mount, *ppDir, (uint8_t*)component, strlen(component)); int ret = searchForDir(mount, *ppDir, (uint8_t*)component, strlen(component), ppDir);
if (!*ppDir) if (ret !=0)
return EEXIST; return ret;
} }
if (!isDir && !**pPath) if (!isDir && !**pPath)
@ -523,6 +545,7 @@ static nlink_t dir_nlink(romfs_mount *mount, romfs_dir *dir)
while(offset != romFS_none) while(offset != romFS_none)
{ {
romfs_dir *tmp = romFS_dir(mount, offset); romfs_dir *tmp = romFS_dir(mount, offset);
if (!tmp) break;
++count; ++count;
offset = tmp->sibling; offset = tmp->sibling;
} }
@ -531,6 +554,7 @@ static nlink_t dir_nlink(romfs_mount *mount, romfs_dir *dir)
while(offset != romFS_none) while(offset != romFS_none)
{ {
romfs_file *tmp = romFS_file(mount, offset); romfs_file *tmp = romFS_file(mount, offset);
if (!tmp) break;
++count; ++count;
offset = tmp->sibling; offset = tmp->sibling;
} }
@ -562,13 +586,14 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
if (r->_errno != 0) if (r->_errno != 0)
return -1; return -1;
romfs_file* file = searchForFile(fileobj->mount, curDir, (uint8_t*)path, strlen(path)); romfs_file* file = NULL;
if (!file) int ret = searchForFile(fileobj->mount, curDir, (uint8_t*)path, strlen(path), &file);
if (ret != 0)
{ {
if(flags & O_CREAT) if(ret == ENOENT && (flags & O_CREAT))
r->_errno = EROFS; r->_errno = EROFS;
else else
r->_errno = ENOENT; r->_errno = ret;
return -1; return -1;
} }
else if((flags & O_CREAT) && (flags & O_EXCL)) else if((flags & O_CREAT) && (flags & O_EXCL))
@ -680,8 +705,15 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
if(r->_errno != 0) if(r->_errno != 0)
return -1; return -1;
romfs_dir* dir = searchForDir(mount, curDir, (uint8_t*)path, strlen(path)); romfs_dir* dir = NULL;
if(dir) int ret=0;
ret = searchForDir(mount, curDir, (uint8_t*)path, strlen(path), &dir);
if (ret != 0 && ret != ENOENT)
{
r->_errno = ret;
return -1;
}
if(ret == 0)
{ {
memset(st, 0, sizeof(*st)); memset(st, 0, sizeof(*st));
st->st_ino = dir_inode(mount, dir); st->st_ino = dir_inode(mount, dir);
@ -695,8 +727,14 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
return 0; return 0;
} }
romfs_file* file = searchForFile(mount, curDir, (uint8_t*)path, strlen(path)); romfs_file* file = NULL;
if(file) ret = searchForFile(mount, curDir, (uint8_t*)path, strlen(path), &file);
if (ret != 0 && ret != ENOENT)
{
r->_errno = ret;
return -1;
}
if(ret == 0)
{ {
memset(st, 0, sizeof(*st)); memset(st, 0, sizeof(*st));
st->st_ino = file_inode(mount, file); st->st_ino = file_inode(mount, file);
@ -774,6 +812,11 @@ int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct s
{ {
/* '..' entry */ /* '..' entry */
romfs_dir* dir = romFS_dir(iter->mount, iter->dir->parent); romfs_dir* dir = romFS_dir(iter->mount, iter->dir->parent);
if(!dir)
{
r->_errno = EFAULT;
return -1;
}
memset(filestat, 0, sizeof(*filestat)); memset(filestat, 0, sizeof(*filestat));
filestat->st_ino = dir_inode(iter->mount, dir); filestat->st_ino = dir_inode(iter->mount, dir);
@ -787,6 +830,12 @@ int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct s
if(iter->childDir != romFS_none) if(iter->childDir != romFS_none)
{ {
romfs_dir* dir = romFS_dir(iter->mount, iter->childDir); romfs_dir* dir = romFS_dir(iter->mount, iter->childDir);
if(!dir)
{
r->_errno = EFAULT;
return -1;
}
iter->childDir = dir->sibling; iter->childDir = dir->sibling;
memset(filestat, 0, sizeof(*filestat)); memset(filestat, 0, sizeof(*filestat));
@ -808,6 +857,12 @@ int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct s
else if(iter->childFile != romFS_none) else if(iter->childFile != romFS_none)
{ {
romfs_file* file = romFS_file(iter->mount, iter->childFile); romfs_file* file = romFS_file(iter->mount, iter->childFile);
if(!file)
{
r->_errno = EFAULT;
return -1;
}
iter->childFile = file->sibling; iter->childFile = file->sibling;
memset(filestat, 0, sizeof(*filestat)); memset(filestat, 0, sizeof(*filestat));