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_check_permission_real(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);
return 0;
}
+/*
+ * Check permission using real UID/GID for POSIX strict compliance.
+ * Used by access() syscall which must use real IDs, not effective IDs.
+ * want: bitmask of 4 (read), 2 (write), 1 (execute).
+ * Returns 0 if allowed, -EACCES if denied.
+ */
+int vfs_check_permission_real(fs_node_t* node, int want) {
+ if (!current_process) return 0; /* kernel context — allow all */
+ if (current_process->uid == 0) return 0; /* root — allow all */
+
+ uint32_t mode = node->mode;
+ uint32_t perm;
+
+ if (current_process->uid == node->uid) {
+ perm = (mode >> 6) & 7; /* owner bits */
+ } else if (current_process->gid == node->gid) {
+ perm = (mode >> 3) & 7; /* group bits */
+ } else {
+ perm = mode & 7; /* other bits */
+ }
+
+ if ((want & perm) != (uint32_t)want) return -EACCES;
+ return 0;
+}
+
int vfs_link(const char* old_path, const char* new_path) {
if (!old_path || !new_path) return -EINVAL;
sc_ret(regs) = 0;
return;
}
- /* Use vfs_check_permission for R_OK/W_OK/X_OK */
+ /* Use vfs_check_permission_real for R_OK/W_OK/X_OK (POSIX strict: use real IDs) */
int want = 0;
if (mode & 4) want |= 4; /* R_OK = 4 */
if (mode & 2) want |= 2; /* W_OK = 2 */
if (mode & 1) want |= 1; /* X_OK = 1 */
- int perm_rc = vfs_check_permission(node, want);
+ int perm_rc = vfs_check_permission_real(node, want);
if (perm_rc < 0) {
sc_ret(regs) = (uint32_t)perm_rc;
return;