]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
security: Round 6.2 O_NOFOLLOW implementation (K21)
authorTulio A M Mendes <[email protected]>
Mon, 25 May 2026 19:20:33 +0000 (16:20 -0300)
committerTulio A M Mendes <[email protected]>
Wed, 3 Jun 2026 04:02:35 +0000 (01:02 -0300)
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)

include/fs.h
src/kernel/fs.c
src/kernel/syscall.c

index bf2e45acfdede75b733bf8fb89b1b5a531effdbf..deb17b65b97d7d6dee564164dab810dc0e2fae14 100644 (file)
@@ -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);
index d3bc68319543ec7cb2af8ed0ea60c638905ec4fb..57abed424e3f77cb9e96e370cb1f6a77eb040ded 100644 (file)
@@ -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;
         }
     }
index 27b59cc053cf92ca456f9671c78ccf7164c2fb9c..68bfd8e1760021d067ad42d37f424fe49948a372 100644 (file)
@@ -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);