From 11dd5b2a511fc0617bc06a3db99a7ea51ea209bd Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Tue, 26 May 2026 02:09:59 -0300 Subject: [PATCH] security: add complete POSIX permissions for SHM (Fase 2) --- include/shm.h | 6 ++++++ src/kernel/shm.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/include/shm.h b/include/shm.h index 971c136d..09facf4b 100644 --- a/include/shm.h +++ b/include/shm.h @@ -23,14 +23,20 @@ /* Commands for shmctl */ #define IPC_RMID 0 #define IPC_STAT 1 +#define IPC_SET 2 /* Private key — always creates a new segment */ #define IPC_PRIVATE 0 +struct ipc_perm { + uint32_t mode; /* permission mode */ +}; + struct shmid_ds { uint32_t shm_segsz; /* segment size in bytes */ uint32_t shm_nattch; /* number of current attaches */ uint32_t shm_key; /* key */ + struct ipc_perm shm_perm; /* permission structure */ }; /* Kernel API */ diff --git a/src/kernel/shm.c b/src/kernel/shm.c index 42ccda5a..67124c41 100644 --- a/src/kernel/shm.c +++ b/src/kernel/shm.c @@ -55,6 +55,29 @@ static void shm_destroy(struct shm_segment* seg) { memset(seg, 0, sizeof(*seg)); } +/* Check POSIX permission for SHM segment */ +static int shm_perm_check(struct shm_segment* seg, int perm) { + if (!current_process) return 0; + if (current_process->euid == 0) return 1; /* Root can do anything */ + + uint32_t mode = seg->mode; + uint32_t uid = seg->uid; + uint32_t gid = seg->gid; + + /* Owner permissions */ + if (current_process->uid == uid || current_process->euid == uid) { + return (mode & (perm << 6)) != 0; + } + + /* Group permissions */ + if (current_process->gid == gid || current_process->egid == gid) { + return (mode & (perm << 3)) != 0; + } + + /* Other permissions */ + return (mode & perm) != 0; +} + int shm_get(uint32_t key, uint32_t size, int flags) { if (size == 0) return -EINVAL; @@ -143,8 +166,8 @@ void* shm_at(int shmid, uintptr_t shmaddr) { return (void*)(uintptr_t)-EINVAL; } - /* K14: Check permission - owner or root only */ - if (seg->uid != current_process->uid && current_process->uid != 0) { + /* Check POSIX read permission */ + if (!shm_perm_check(seg, 04)) { /* R_OK = 4 */ spin_unlock_irqrestore(&shm_lock, irqf); return (void*)(uintptr_t)-EACCES; } @@ -264,6 +287,11 @@ int shm_ctl(int shmid, int cmd, struct shmid_ds* buf) { } if (cmd == IPC_STAT) { + /* Check read permission */ + if (!shm_perm_check(seg, 04)) { + spin_unlock_irqrestore(&shm_lock, irqf); + return -EACCES; + } /* Copy to local struct first, then release lock before * writing to userspace to avoid deadlock on page fault. */ struct shmid_ds local; @@ -280,6 +308,11 @@ int shm_ctl(int shmid, int cmd, struct shmid_ds* buf) { } if (cmd == IPC_RMID) { + /* Only owner or root can remove */ + if (seg->uid != current_process->uid && current_process->euid != 0) { + spin_unlock_irqrestore(&shm_lock, irqf); + return -EPERM; + } if (seg->nattch == 0) { shm_destroy(seg); } else { @@ -289,6 +322,25 @@ int shm_ctl(int shmid, int cmd, struct shmid_ds* buf) { return 0; } + if (cmd == IPC_SET) { + /* Only owner or root can change permissions */ + if (seg->uid != current_process->uid && current_process->euid != 0) { + spin_unlock_irqrestore(&shm_lock, irqf); + return -EPERM; + } + if (buf) { + struct shmid_ds local; + if (copy_from_user(&local, buf, sizeof(local)) < 0) { + spin_unlock_irqrestore(&shm_lock, irqf); + return -EFAULT; + } + /* Update mode from IPC_SET */ + seg->mode = local.shm_perm.mode & 0777; + } + spin_unlock_irqrestore(&shm_lock, irqf); + return 0; + } + spin_unlock_irqrestore(&shm_lock, irqf); return -EINVAL; } -- 2.43.0