- A07: vfs_check_permission moved to fs.c, vfs_check_parent_permission now validates real permissions
- A05: initrd parser validation:
- Minimum size checks for magic (4 bytes), LZ4 frame header (10 bytes), LZ4B header (12 bytes)
- Update size variable after decompression to reflect decompressed size
- TAR file size limit (256MB max)
- Removed overly strict buffer overflow check that rejected valid TAR
Tests: 119/119 PASS (smoke test, SMP=4)
int vfs_truncate(const char* path, uint32_t length);
int vfs_truncate_node(struct fs_node* node, uint32_t length);
int vfs_check_parent_permission(const char* path, int perm);
+int vfs_check_permission(struct fs_node* node, int want);
int vfs_link(const char* old_path, const char* new_path);
int vfs_mount(const char* mountpoint, fs_node_t* root);
const uint8_t* raw = (const uint8_t*)(uintptr_t)location;
uint8_t* decomp_buf = NULL;
+ /* A05: Validate minimum size for magic check */
+ if (size < 4) {
+ kprintf("[INITRD] Invalid size: %u (min 4)\n", size);
+ return NULL;
+ }
+
/* Detect LZ4-compressed initrd */
uint32_t magic32 = (uint32_t)raw[0] | ((uint32_t)raw[1] << 8) |
((uint32_t)raw[2] << 16) | ((uint32_t)raw[3] << 24);
if (magic32 == LZ4_FRAME_MAGIC) {
+ /* A05: Validate minimum LZ4 frame header size */
+ if (size < 10) {
+ kprintf("[INITRD] LZ4 frame too small: %u (min 10)\n", size);
+ return NULL;
+ }
+
/* Official LZ4 Frame format — extract content size from header */
uint8_t flg = raw[4];
uint32_t orig_sz = 0;
kprintf("[INITRD] LZ4: %u -> %d bytes\n", size, ret);
location = (uint32_t)(uintptr_t)decomp_buf;
+ size = (uint32_t)ret; /* A05: Update size to decompressed size */
} else if (magic32 == LZ4B_MAGIC_U32) {
+ /* A05: Validate minimum LZ4B header size */
+ if (size < 12) {
+ kprintf("[INITRD] LZ4B header too small: %u (min 12)\n", size);
+ return NULL;
+ }
+
/* Legacy LZ4B format (backward compatibility) */
uint32_t orig_sz = (uint32_t)raw[4] | ((uint32_t)raw[5] << 8) |
((uint32_t)raw[6] << 16) | ((uint32_t)raw[7] << 24);
kprintf("[INITRD] LZ4: %u -> %u bytes\n", comp_sz, orig_sz);
location = (uint32_t)(uintptr_t)decomp_buf;
+ size = orig_sz; /* A05: Update size to decompressed size */
}
initrd_location_base = location;
char tf = h->typeflag;
if (tf == 0) tf = '0';
+ /* A05: Validate rec_len (TAR block alignment) */
+ if (size > 256 * 1024 * 1024) { /* Reasonable limit: 256MB */
+ kprintf("[INITRD] TAR: size too large: %u\n", size);
+ return NULL;
+ }
+
// Normalize: strip leading './'
if (name[0] == '.' && name[1] == '/') {
size_t l = strlen(name);
#include "spinlock.h"
#include "console.h"
#include "heap.h"
+#include "process.h"
#include <string.h>
if (!parent_node) return -ENOENT;
if (!(parent_node->flags & FS_DIRECTORY)) return -ENOTDIR;
- /* A07: For now, allow all - single-user root system */
- /* TODO: Implement proper permission check using current_process */
- (void)parent_node;
- (void)perm;
+ /* Check permission on parent */
+ return vfs_check_permission(parent_node, perm);
+}
+
+/*
+ * Check if the current process has the requested access to a file node.
+ * want: bitmask of 4 (read), 2 (write), 1 (execute).
+ * Returns 0 if allowed, -EACCES if denied.
+ * A07: Moved from syscall.c to fs.c for use by vfs_check_parent_permission
+ */
+extern struct process* current_process; /* From process.h */
+
+int vfs_check_permission(fs_node_t* node, int want) {
+ if (!current_process) return 0; /* kernel context — allow all */
+ if (current_process->euid == 0) return 0; /* root — allow all */
+ if (node->mode == 0) return 0; /* mode not set — permissive */
+
+ uint32_t mode = node->mode;
+ uint32_t perm;
+
+ if (current_process->euid == node->uid) {
+ perm = (mode >> 6) & 7; /* owner bits */
+ } else if (current_process->egid == node->gid) {
+ perm = (mode >> 3) & 7; /* group bits */
+ } else {
+ perm = mode & 7; /* other bits */
+ }
+
+ if ((want & perm) != (uint32_t)want) return -EACCES;
return 0;
}
return (int)f->offset;
}
-/*
- * Check if the current process has the requested access to a file node.
- * want: bitmask of 4 (read), 2 (write), 1 (execute).
- * Returns 0 if allowed, -EACCES if denied.
- */
-static int vfs_check_permission(fs_node_t* node, int want) {
- if (!current_process) return 0; /* kernel context — allow all */
- if (current_process->euid == 0) return 0; /* root — allow all */
- if (node->mode == 0) return 0; /* mode not set — permissive */
-
- uint32_t mode = node->mode;
- uint32_t perm;
-
- if (current_process->euid == node->uid) {
- perm = (mode >> 6) & 7; /* owner bits */
- } else if (current_process->egid == node->gid) {
- perm = (mode >> 3) & 7; /* group bits */
- } else {
- perm = mode & 7; /* other bits */
- }
-
- if ((want & perm) != (uint32_t)want) return -EACCES;
- return 0;
-}
-
static int syscall_open_impl(const char* user_path, uint32_t flags) {
if (!user_path) return -EFAULT;