From: Tulio A M Mendes Date: Mon, 25 May 2026 19:20:33 +0000 (-0300) Subject: security: Round 6.2 O_NOFOLLOW implementation (K21) X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=8836f4a94ea6b6191d83cebf5b6721c8ee776068;p=AdrOS.git security: Round 6.2 O_NOFOLLOW implementation (K21) K21: Implement O_NOFOLLOW flag in open/openat - Added LOOKUP_FOLLOW and LOOKUP_NOFOLLOW flags to vfs_lookup_depth - Added vfs_lookup_nofollow() function for O_NOFOLLOW path - Modified syscall_open_impl to use vfs_lookup_nofollow when O_NOFOLLOW is set - When O_NOFOLLOW is set, symlinks are not followed - returned as-is Tests: 119/119 PASS (smoke test, SMP=4) --- diff --git a/include/fs.h b/include/fs.h index bf2e45ac..deb17b65 100644 --- a/include/fs.h +++ b/include/fs.h @@ -110,6 +110,9 @@ void vfs_close(fs_node_t* node); fs_node_t* vfs_lookup(const char* path); +/* K21: Lookup without following symlinks (for O_NOFOLLOW) */ +fs_node_t* vfs_lookup_nofollow(const char* path); + /* Lookup from the saved initrd root (immune to pivot_root). */ void vfs_set_initrd_root(fs_node_t* root); fs_node_t* vfs_lookup_initrd(const char* path); diff --git a/src/kernel/fs.c b/src/kernel/fs.c index d3bc6831..57abed42 100644 --- a/src/kernel/fs.c +++ b/src/kernel/fs.c @@ -340,10 +340,18 @@ void vfs_close(fs_node_t* node) { node->f_ops->close(node); } -static fs_node_t* vfs_lookup_depth(const char* path, int depth); +static fs_node_t* vfs_lookup_depth(const char* path, int depth, int lookup_flags); + +#define LOOKUP_FOLLOW 0x01 +#define LOOKUP_NOFOLLOW 0x02 + +/* K21: Export for use in syscall.c */ +fs_node_t* vfs_lookup_nofollow(const char* path) { + return vfs_lookup_depth(path, 0, LOOKUP_NOFOLLOW); +} fs_node_t* vfs_lookup(const char* path) { - return vfs_lookup_depth(path, 0); + return vfs_lookup_depth(path, 0, LOOKUP_FOLLOW); } void vfs_set_initrd_root(fs_node_t* root) { @@ -381,7 +389,7 @@ fs_node_t* vfs_lookup_initrd(const char* path) { return cur; } -static fs_node_t* vfs_lookup_depth(const char* path, int depth) { +static fs_node_t* vfs_lookup_depth(const char* path, int depth, int lookup_flags) { if (!path) return NULL; if (depth > 8) return NULL; @@ -440,8 +448,13 @@ static fs_node_t* vfs_lookup_depth(const char* path, int depth) { cur = fn_finddir(cur, part); if (!cur) return NULL; + /* K21: Only follow symlinks if LOOKUP_FOLLOW is set */ if (cur->flags == FS_SYMLINK && cur->symlink_target[0]) { - cur = vfs_lookup_depth(cur->symlink_target, depth + 1); + if (lookup_flags & LOOKUP_NOFOLLOW) { + /* Don't follow the symlink - return it as-is */ + return cur; + } + cur = vfs_lookup_depth(cur->symlink_target, depth + 1, lookup_flags); if (!cur) return NULL; } } diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 27b59cc0..68bfd8e1 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -2333,7 +2333,13 @@ static int syscall_open_impl(const char* user_path, uint32_t flags) { return -EACCES; } - fs_node_t* node = vfs_lookup(path); + /* K21: Use vfs_lookup_nofollow when O_NOFOLLOW is set */ + fs_node_t* node; + if (flags & 0x20000) { /* O_NOFOLLOW */ + node = vfs_lookup_nofollow(path); + } else { + node = vfs_lookup(path); + } if (!node && (flags & 0x40U) != 0U) { /* O_CREAT: create file through VFS */ int rc = vfs_require_writable_path(path);