fs_node_t* vfs_lookup(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);
+
// Resolve path to (parent_dir, basename). Returns parent node or NULL.
fs_node_t* vfs_lookup_parent(const char* path, char* name_out, size_t name_sz);
* Returns 0 on success, fills *loaded_end with highest mapped address. */
static int elf32_load_shared_lib_at(const char* path, uintptr_t as,
uintptr_t base, uintptr_t* loaded_end) {
- fs_node_t* node = vfs_lookup(path);
+ fs_node_t* node = vfs_lookup_initrd(path);
+ if (!node) node = vfs_lookup(path);
if (!node) return -ENOENT;
uint32_t flen = node->length;
uintptr_t* interp_entry, uintptr_t* interp_base_out) {
if (!interp_path || !interp_entry) return -EINVAL;
- fs_node_t* node = vfs_lookup(interp_path);
+ fs_node_t* node = vfs_lookup_initrd(interp_path);
+ if (!node) node = vfs_lookup(interp_path);
if (!node) {
kprintf("[ELF] interp not found: %s\n", interp_path);
return -ENOENT;
uintptr_t old_as = hal_cpu_get_address_space();
- fs_node_t* node = vfs_lookup(filename);
+ /* Use vfs_lookup_initrd so that pivot_root (which changes the global
+ * fs_root and the "/" mount entry) does not break execve lookups. */
+ fs_node_t* node = vfs_lookup_initrd(filename);
+ if (!node) node = vfs_lookup(filename);
if (!node) {
kprintf("[ELF] file not found: %s\n", filename);
vmm_as_destroy(new_as);
#include "errno.h"
fs_node_t* fs_root = NULL;
+static fs_node_t* g_initrd_root = NULL;
struct vfs_mount {
char mountpoint[128];
return vfs_lookup_depth(path, 0);
}
+void vfs_set_initrd_root(fs_node_t* root) {
+ g_initrd_root = root;
+}
+
+fs_node_t* vfs_lookup_initrd(const char* path) {
+ if (!path || !g_initrd_root) return NULL;
+
+ /* Direct finddir traversal from the saved initrd root.
+ * Bypasses the VFS mount table so that pivot_root (which changes
+ * fs_root and the "/" mount entry) does not break execve lookups. */
+ const char* p = path;
+ while (*p == '/') p++;
+ if (*p == 0) return g_initrd_root;
+
+ fs_node_t* cur = g_initrd_root;
+ char part[128];
+ while (*p != 0) {
+ size_t i = 0;
+ while (*p != 0 && *p != '/') {
+ if (i + 1 < sizeof(part)) part[i++] = *p;
+ p++;
+ }
+ part[i] = 0;
+ while (*p == '/') p++;
+ if (part[0] == 0) continue;
+ if (!cur) return NULL;
+ fs_node_t* (*fn_finddir)(fs_node_t*, const char*) = NULL;
+ if (cur->i_ops && cur->i_ops->lookup) fn_finddir = cur->i_ops->lookup;
+ if (!fn_finddir) return NULL;
+ cur = fn_finddir(cur, part);
+ if (!cur) return NULL;
+ }
+ return cur;
+}
+
static fs_node_t* vfs_lookup_depth(const char* path, int depth) {
if (!path || !fs_root) return NULL;
if (depth > 8) return NULL;
fs_node_t* ovl = overlayfs_create_root(fs_root, upper);
if (ovl) {
(void)vfs_mount("/", ovl);
+ vfs_set_initrd_root(ovl);
}
}
}
}
// Distinguish ENOENT early.
- fs_node_t* node = vfs_lookup(path);
+ fs_node_t* node = vfs_lookup_initrd(path);
+ if (!node) node = vfs_lookup(path);
if (!node) { ret = -ENOENT; goto out; }
uintptr_t entry = 0;
(uint32_t)(sizeof("[test] pivot_root OK\n") - 1));
}
- (void)sys_write(1, "[test] execve(/bin/echo)\n",
- (uint32_t)(sizeof("[test] execve(/bin/echo)\n") - 1));
- static const char* const argv[] = {"echo", "[echo]", "hello", "from", "echo", 0};
- static const char* const envp[] = {"FOO=bar", "HELLO=world", 0};
- (void)sys_execve("/bin/echo", argv, envp);
- (void)sys_write(1, "[test] execve returned (unexpected)\n",
- (uint32_t)(sizeof("[test] execve returned (unexpected)\n") - 1));
- sys_exit(1);
+ // execve — fork a child that replaces itself with /bin/echo
+ {
+ int pid = sys_fork();
+ if (pid < 0) {
+ sys_write(1, "[test] execve fork failed\n",
+ (uint32_t)(sizeof("[test] execve fork failed\n") - 1));
+ sys_exit(1);
+ }
+ if (pid == 0) {
+ static const char* const ev_argv[] = {"echo", "[echo]", "hello", "from", "echo", 0};
+ static const char* const ev_envp[] = {"FOO=bar", "HELLO=world", 0};
+ (void)sys_execve("/bin/echo", ev_argv, ev_envp);
+ sys_exit(1); /* execve should not return */
+ }
+ int st = 0;
+ sys_waitpid(pid, &st, 0);
+ if (st != 0) {
+ sys_write(1, "[test] execve child failed\n",
+ (uint32_t)(sizeof("[test] execve child failed\n") - 1));
+ sys_exit(1);
+ }
+ }
sys_exit(0);
}