huge security fix
This commit is contained in:
@@ -102,16 +102,6 @@ void *nn_fs_unwrapFD(nn_filesystem *fs, nn_size_t fd) {
|
||||
return file;
|
||||
}
|
||||
|
||||
nn_bool_t nn_fs_illegalPath(const char *path) {
|
||||
// absolute disaster
|
||||
const char *illegal = "\"\\:*?<>|";
|
||||
|
||||
for(nn_size_t i = 0; illegal[i] != '\0'; i++) {
|
||||
if(nn_strchr(path, illegal[i]) != NULL) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void nn_fs_readCost(nn_filesystem *fs, nn_size_t bytes, nn_component *component) {
|
||||
nn_filesystemControl control = fs->control;
|
||||
nn_computer *computer = nn_getComputerOfComponent(component);
|
||||
@@ -201,13 +191,14 @@ void nn_fs_size(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
||||
nn_setCError(computer, "bad path (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(path)) {
|
||||
char canonical[NN_MAX_PATH];
|
||||
if(nn_path_canonical(path, canonical)) {
|
||||
nn_setCError(computer, "bad path (illegal path)");
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_size_t byteSize = fs->table.size(fs->table.userdata, path);
|
||||
nn_size_t byteSize = fs->table.size(fs->table.userdata, canonical);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
|
||||
nn_return(computer, nn_values_integer(byteSize));
|
||||
@@ -220,13 +211,14 @@ void nn_fs_remove(nn_filesystem *fs, nn_componentMethod *_, nn_component *compon
|
||||
nn_setCError(computer, "bad path (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(path)) {
|
||||
char canonical[NN_MAX_PATH];
|
||||
if(nn_path_canonical(path, canonical)) {
|
||||
nn_setCError(computer, "bad path (illegal path)");
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_size_t removed = fs->table.remove(fs->table.userdata, path);
|
||||
nn_size_t removed = fs->table.remove(fs->table.userdata, canonical);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_return_boolean(computer, removed > 0);
|
||||
|
||||
@@ -240,13 +232,14 @@ void nn_fs_lastModified(nn_filesystem *fs, nn_componentMethod *_, nn_component *
|
||||
nn_setCError(computer, "bad path (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(path)) {
|
||||
char canonical[NN_MAX_PATH];
|
||||
if(nn_path_canonical(path, canonical)) {
|
||||
nn_setCError(computer, "bad path (illegal path)");
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_size_t t = fs->table.lastModified(fs->table.userdata, path);
|
||||
nn_size_t t = fs->table.lastModified(fs->table.userdata, canonical);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
|
||||
// OpenOS does BULLSHIT with this thing, dividing it by 1000 and expecting it to be
|
||||
@@ -264,7 +257,8 @@ void nn_fs_rename(nn_filesystem *fs, nn_componentMethod *_, nn_component *compon
|
||||
nn_setCError(computer, "bad path #1 (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(from)) {
|
||||
char canonicalFrom[NN_MAX_PATH];
|
||||
if(nn_path_canonical(from, canonicalFrom)) {
|
||||
nn_setCError(computer, "bad path #1 (illegal path)");
|
||||
return;
|
||||
}
|
||||
@@ -275,13 +269,14 @@ void nn_fs_rename(nn_filesystem *fs, nn_componentMethod *_, nn_component *compon
|
||||
nn_setCError(computer, "bad path #2 (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(to)) {
|
||||
char canonicalTo[NN_MAX_PATH];
|
||||
if(nn_path_canonical(to, canonicalTo)) {
|
||||
nn_setCError(computer, "bad path #2 (illegal path)");
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_size_t movedCount = fs->table.rename(fs->table.userdata, from, to);
|
||||
nn_size_t movedCount = fs->table.rename(fs->table.userdata, canonicalFrom, canonicalTo);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_return(computer, nn_values_boolean(movedCount > 0));
|
||||
|
||||
@@ -296,13 +291,14 @@ void nn_fs_exists(nn_filesystem *fs, nn_componentMethod *_, nn_component *compon
|
||||
nn_setCError(computer, "bad path (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(path)) {
|
||||
char canonical[NN_MAX_PATH];
|
||||
if(nn_path_canonical(path, canonical)) {
|
||||
nn_setCError(computer, "bad path (illegal path)");
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_return_boolean(computer, fs->table.exists(fs->table.userdata, path));
|
||||
nn_return_boolean(computer, fs->table.exists(fs->table.userdata, canonical));
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
}
|
||||
|
||||
@@ -313,13 +309,14 @@ void nn_fs_isDirectory(nn_filesystem *fs, nn_componentMethod *_, nn_component *c
|
||||
nn_setCError(computer, "bad path (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(path)) {
|
||||
char canonical[NN_MAX_PATH];
|
||||
if(nn_path_canonical(path, canonical)) {
|
||||
nn_setCError(computer, "bad path (illegal path)");
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_return_boolean(computer, fs->table.isDirectory(fs->table.userdata, path));
|
||||
nn_return_boolean(computer, fs->table.isDirectory(fs->table.userdata, canonical));
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
}
|
||||
|
||||
@@ -330,13 +327,14 @@ void nn_fs_makeDirectory(nn_filesystem *fs, nn_componentMethod *_, nn_component
|
||||
nn_setCError(computer, "bad path (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(path)) {
|
||||
char canonical[NN_MAX_PATH];
|
||||
if(nn_path_canonical(path, canonical)) {
|
||||
nn_setCError(computer, "bad path (illegal path)");
|
||||
return;
|
||||
}
|
||||
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
nn_return_boolean(computer, fs->table.makeDirectory(fs->table.userdata, path));
|
||||
nn_return_boolean(computer, fs->table.makeDirectory(fs->table.userdata, canonical));
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
|
||||
nn_fs_createCost(fs, 1, component);
|
||||
@@ -349,7 +347,8 @@ void nn_fs_list(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
||||
nn_setCError(computer, "bad path (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(path)) {
|
||||
char canonical[NN_MAX_PATH];
|
||||
if(nn_path_canonical(path, canonical)) {
|
||||
nn_setCError(computer, "bad path (illegal path)");
|
||||
return;
|
||||
}
|
||||
@@ -358,7 +357,7 @@ void nn_fs_list(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
||||
|
||||
nn_size_t fileCount = 0;
|
||||
nn_lock(&fs->ctx, fs->lock);
|
||||
char **files = fs->table.list(alloc, fs->table.userdata, path, &fileCount);
|
||||
char **files = fs->table.list(alloc, fs->table.userdata, canonical, &fileCount);
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
|
||||
if(files != NULL) {
|
||||
@@ -380,7 +379,8 @@ void nn_fs_open(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
||||
nn_setCError(computer, "bad path (string expected)");
|
||||
return;
|
||||
}
|
||||
if(nn_fs_illegalPath(path)) {
|
||||
char canonical[NN_MAX_PATH];
|
||||
if(nn_path_canonical(path, canonical)) {
|
||||
nn_setCError(computer, "bad path (illegal path)");
|
||||
return;
|
||||
}
|
||||
@@ -406,7 +406,7 @@ void nn_fs_open(nn_filesystem *fs, nn_componentMethod *_, nn_component *componen
|
||||
return;
|
||||
}
|
||||
}
|
||||
void *file = fs->table.open(fs->table.userdata, path, mode);
|
||||
void *file = fs->table.open(fs->table.userdata, canonical, mode);
|
||||
if(file == NULL) {
|
||||
nn_unlock(&fs->ctx, fs->lock);
|
||||
nn_setCError(computer, "no such file or directory");
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
typedef struct nn_vfnode {
|
||||
struct nn_vfilesystem *fs;
|
||||
struct nn_vfnode *parent;
|
||||
char name[NN_MAX_PATH];
|
||||
struct nn_vfnode *parent;
|
||||
nn_bool_t isDirectory;
|
||||
union {
|
||||
// if directory
|
||||
@@ -57,8 +57,8 @@ nn_vfnode *nn_vf_allocFile(nn_vfilesystem *fs, const char *name) {
|
||||
if(node == NULL) return NULL;
|
||||
*node = (nn_vfnode) {
|
||||
.fs = fs,
|
||||
.parent = NULL,
|
||||
.lastModified = nn_vf_now(fs),
|
||||
.parent = NULL,
|
||||
.isDirectory = false,
|
||||
.data = NULL,
|
||||
.len = 0,
|
||||
@@ -81,8 +81,8 @@ nn_vfnode *nn_vf_allocDirectory(nn_vfilesystem *fs, const char *name) {
|
||||
}
|
||||
*node = (nn_vfnode) {
|
||||
.fs = fs,
|
||||
.parent = NULL,
|
||||
.lastModified = nn_vf_now(fs),
|
||||
.parent = NULL,
|
||||
.isDirectory = false,
|
||||
.entries = buffer,
|
||||
.len = 0,
|
||||
@@ -121,6 +121,44 @@ nn_size_t nn_vf_spaceUsedByNode(nn_vfnode *node) {
|
||||
}
|
||||
}
|
||||
|
||||
nn_vfnode *nn_vf_find(nn_vfnode *parent, const char *name) {
|
||||
if(parent->isDirectory) return NULL;
|
||||
for(nn_size_t i = 0; i < parent->len; i++) {
|
||||
nn_vfnode *entry = parent->entries[i];
|
||||
|
||||
if(nn_strcmp(entry->name, name) == 0) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nn_bool_t nn_vf_ensureFileCapacity(nn_vfnode *file, nn_size_t capacity) {
|
||||
if(file->isDirectory) return false;
|
||||
nn_Alloc *alloc = &file->fs->ctx.allocator;
|
||||
|
||||
if(file->cap >= capacity) return true; // already at that point
|
||||
|
||||
char *newData = nn_resize(alloc, file->data, file->cap, capacity);
|
||||
if(newData == NULL) {
|
||||
return false; // OOM
|
||||
}
|
||||
file->data = newData;
|
||||
file->cap = capacity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// this is used to compute exponential backoff
|
||||
// TODO: add an option to select either a slower growth rate or
|
||||
// linear backoff to reduce memory usage at the cost of speed
|
||||
nn_size_t nn_vf_getIdealCapacity(nn_vfnode *file, nn_size_t spaceNeeded) {
|
||||
nn_size_t cap = file->cap;
|
||||
if(cap == 0) cap = 1;
|
||||
while(cap < spaceNeeded) cap *= 2; // this would mean a file with 1,048,577 bytes takes up 2,097,152 bytes, potentially wasting 1,048,575 bytes
|
||||
return cap;
|
||||
}
|
||||
|
||||
// methods
|
||||
|
||||
void nn_vfs_deinit(nn_vfilesystem *fs) {
|
||||
|
||||
Reference in New Issue
Block a user