huge security fix

This commit is contained in:
2025-07-16 14:47:08 +02:00
parent 4a5562549c
commit 59eb01b890
5 changed files with 114 additions and 44 deletions

View File

@@ -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");

View File

@@ -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) {