mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
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:
parent
cc64ec7236
commit
ce570a70f1
@ -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));
|
||||||
|
Loading…
Reference in New Issue
Block a user