-
Notifications
You must be signed in to change notification settings - Fork 0
ACL Permissions
ModuOS MDFS filesystem implements NTFS-style ACL permissions, providing fine-grained access control similar to Windows file systems. This system goes beyond traditional Unix permissions by supporting:
- Multiple permission types (read, write, execute, delete, ownership)
- Allow and Deny rules (deny always overrides allow)
- User and group-based control
- Supplementary group support
MDFS supports five distinct permission flags:
| Permission | Value | Description |
|---|---|---|
MDFS_PERM_READ |
0x01 | Read file content or list directory |
MDFS_PERM_WRITE |
0x02 | Modify file content |
MDFS_PERM_EXECUTE |
0x04 | Execute file or traverse directory |
MDFS_PERM_DELETE |
0x08 | Delete file or directory |
MDFS_PERM_OWNERSHIP |
0x10 | Change owner, modify ACL |
Each file/directory can have up to 16 ACEs (Access Control Entries). Each ACE is a compact 32-bit structure:
Bit layout: [Reserved:9][IsGroup:1][Type:1][Perms:5][ID:16]
- ID (16 bits): User ID or Group ID
- Perms (5 bits): Permission flags (bitwise OR of permission types)
-
Type (1 bit):
ACE_ALLOW(0) orACE_DENY(1) - IsGroup (1 bit): Whether ID refers to a group (1) or user (0)
When checking permissions, the system:
- Collects all matching ACEs (user ID + all supplementary groups)
- Builds allow mask from all matching ALLOW entries
- Builds deny mask from all matching DENY entries
-
Computes final permissions:
allowed & ~denied - Checks if requested permissions are granted
Important: DENY entries always override ALLOW entries, even if they come later in the ACL.
When a file or directory is created, MDFS automatically creates a default ACL:
- Owner: Full permissions (read, write, execute, delete, ownership)
- Owner's primary group: Read and execute permissions
// Example from the provided code
FS_File secure_file;
// 1. Allow "Developers" (Group 500) Read/Write access
secure_file.acl.aces[0] = ACE_MAKE(500, 1, ACE_ALLOW, PERM_READ | PERM_WRITE);
// 2. DENY "Interns" (Group 600) Write access
secure_file.acl.aces[1] = ACE_MAKE(600, 1, ACE_DENY, PERM_WRITE);
secure_file.acl.ace_count = 2;
// User in both groups (500, 600):
// - ALLOW Read | Write from group 500
// - DENY Write from group 600
// Result: Can READ but cannot WRITE (deny overrides)ModuOS supports supplementary groups in the process structure:
typedef struct process {
uint32_t uid; // Primary user ID
uint32_t gid; // Primary group ID
uint16_t groups[32]; // Supplementary group IDs
uint8_t group_count; // Number of supplementary groups
// ...
} process_t;Permission checks consider:
- User's UID
- Primary GID
- All supplementary groups (up to 32)
- Kernel processes (UID =
KERNEL_UID = 0xFFFFFFFF) have unrestricted access
- User ID 0 (
mdman/root) has unrestricted access - Files owned by UID 0 grant access to all users
If a file has no ACL entries (ace_count == 0), the system falls back to traditional Unix-style permissions:
- Owner: Full access
- Group members: Read + execute
- Others: Read only
// Check permissions
bool mdfs_acl_check_permission(const mdfs_acl_t *acl,
uint16_t uid,
const uint16_t *gids,
int gid_count,
uint8_t requested);
// Initialize empty ACL
void mdfs_acl_init(mdfs_acl_t *acl);
// Add ACE
int mdfs_acl_add_ace(mdfs_acl_t *acl, uint16_t id, bool is_group,
mdfs_ace_type_t type, uint8_t perms);
// Remove ACE by index
int mdfs_acl_remove_ace(mdfs_acl_t *acl, int index);
// Create default ACL
void mdfs_acl_create_default(mdfs_acl_t *acl, uint16_t owner_uid, uint16_t owner_gid);// Get ACL from inode
void mdfs_inode_get_acl(const mdfs_inode_t *ino, mdfs_acl_t *acl);
// Set ACL in inode
void mdfs_inode_set_acl(mdfs_inode_t *ino, const mdfs_acl_t *acl);
// Check inode permissions
bool mdfs_inode_check_permission(const mdfs_inode_t *ino,
uint32_t uid,
uint32_t gid,
const uint16_t *groups,
uint8_t group_count,
uint8_t requested);
// Initialize ACL for new inode
void mdfs_inode_init_acl(mdfs_inode_t *ino, uint32_t owner_uid, uint32_t owner_gid);ACLs are stored directly in the inode structure (68 bytes):
typedef struct __attribute__((packed)) {
// ... other inode fields ...
/* ACL (Access Control List) - 68 bytes */
uint8_t acl_count; /* Number of ACEs (0-16) */
uint8_t acl_reserved[3]; /* Padding for alignment */
uint32_t acl_aces[16]; /* ACE array (64 bytes) */
// ... padding ...
} mdfs_inode_t;The inode size remains 256 bytes with 40 bytes of padding still available for future extensions.
- Zero overhead for simple cases: Empty ACLs fall back to fast traditional permission checks
- Compact storage: 4 bytes per ACE, up to 16 ACEs per file
- In-inode storage: No additional disk seeks required
| Feature | MDFS ACL | Unix | NTFS | ext4 ACL |
|---|---|---|---|---|
| Deny rules | ✓ | ✗ | ✓ | ✗ |
| Per-user ACEs | ✓ | ✗ | ✓ | ✓ |
| Per-group ACEs | ✓ | Limited | ✓ | ✓ |
| In-inode storage | ✓ | N/A | ✗ | ✗ |
| Max ACEs | 16 | N/A | ~1800 | Unlimited |
- Deny takes precedence: Always evaluate deny rules, as they override any allow rules
- Explicit permissions: No permissions granted unless explicitly allowed (and not denied)
- Owner protection: File owners always have full access (unless kernel enforces additional restrictions)
- Audit trail: Consider logging permission denials for security monitoring
Potential future additions:
- Audit ACEs (log access attempts)
- Inherited ACEs (propagate to children)
- Extended permissions (read attributes, write attributes, etc.)
- ACL management utilities (
chmod,setfacl,getfacl)
- MDFS - MDFS filesystem overview
- File Systems - Filesystem comparison
- System Calls - Permission-related syscalls