From 50f38c3ecf964223aaa901499e97e5f0a347c932 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Wed, 10 Jun 2026 23:11:18 -0300 Subject: [PATCH] shm: implement SHM_RDONLY flag for read-only attach Implement H3: SHM permissions complete with SHM_RDONLY attach. Added SHM_RDONLY flag (0x1000) to shm.h for shmat syscall. Modified shm_at() to accept shmflg parameter and: - Check write permission only if SHM_RDONLY is not set - Map pages without VMM_FLAG_RW when SHM_RDONLY is set - This allows read-only shared memory segments for POSIX compliance Updated syscall handler to pass shmflg from sc_arg2 to shm_at(). Test: make test-battery PASS (157/157), make analyzer PASS --- include/shm.h | 5 ++++- src/kernel/shm.c | 21 +++++++++++++++++---- src/kernel/syscall.c | 3 ++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/include/shm.h b/include/shm.h index 09facf4b..a4772c19 100644 --- a/include/shm.h +++ b/include/shm.h @@ -20,6 +20,9 @@ #define IPC_CREAT 0x0200 #define IPC_EXCL 0x0400 +/* Flags for shmat */ +#define SHM_RDONLY 0x1000 /* Attach read-only */ + /* Commands for shmctl */ #define IPC_RMID 0 #define IPC_STAT 1 @@ -41,7 +44,7 @@ struct shmid_ds { /* Kernel API */ int shm_get(uint32_t key, uint32_t size, int flags); -void* shm_at(int shmid, uintptr_t shmaddr); +void* shm_at(int shmid, uintptr_t shmaddr, int shmflg); int shm_dt(const void* shmaddr); int shm_ctl(int shmid, int cmd, struct shmid_ds* buf); diff --git a/src/kernel/shm.c b/src/kernel/shm.c index 67124c41..9e4cab27 100644 --- a/src/kernel/shm.c +++ b/src/kernel/shm.c @@ -145,7 +145,7 @@ int shm_get(uint32_t key, uint32_t size, int flags) { return slot; } -void* shm_at(int shmid, uintptr_t shmaddr) { +void* shm_at(int shmid, uintptr_t shmaddr, int shmflg) { if (shmid < 0 || shmid >= SHM_MAX_SEGMENTS) return (void*)(uintptr_t)-EINVAL; uintptr_t irqf = spin_lock_irqsave(&shm_lock); @@ -166,12 +166,20 @@ void* shm_at(int shmid, uintptr_t shmaddr) { return (void*)(uintptr_t)-EINVAL; } - /* Check POSIX read permission */ + /* Check POSIX read permission (always required) */ if (!shm_perm_check(seg, 04)) { /* R_OK = 4 */ spin_unlock_irqrestore(&shm_lock, irqf); return (void*)(uintptr_t)-EACCES; } + /* If not SHM_RDONLY, also check write permission */ + if (!(shmflg & SHM_RDONLY)) { + if (!shm_perm_check(seg, 02)) { /* W_OK = 2 */ + spin_unlock_irqrestore(&shm_lock, irqf); + return (void*)(uintptr_t)-EACCES; + } + } + /* Find a free mmap slot (always needed to track the mapping) */ int mslot = -1; for (int i = 0; i < PROCESS_MAX_MMAPS; i++) { @@ -211,11 +219,16 @@ void* shm_at(int shmid, uintptr_t shmaddr) { /* Map physical pages into user address space. * vmm_map_page signature: (phys, virt, flags) - * NX by default - IA32_EFER.NXE MSR is now enabled (A01 completed) */ + * NX by default - IA32_EFER.NXE MSR is now enabled (A01 completed) + * H3: If SHM_RDONLY is set, map without VMM_FLAG_RW for read-only access */ + uint64_t map_flags = VMM_FLAG_PRESENT | VMM_FLAG_USER | VMM_FLAG_NX; + if (!(shmflg & SHM_RDONLY)) { + map_flags |= VMM_FLAG_RW; + } for (uint32_t i = 0; i < seg->npages; i++) { vmm_map_page((uint64_t)seg->pages[i], (uint64_t)(vaddr + i * PAGE_SIZE), - VMM_FLAG_PRESENT | VMM_FLAG_RW | VMM_FLAG_USER | VMM_FLAG_NX); + map_flags); } /* Record mapping in process mmap table with shmid for detach lookup */ diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 4e723789..7bdce471 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -3974,7 +3974,8 @@ void syscall_handler(struct registers* regs) { if (syscall_no == SYSCALL_SHMAT) { int shmid = (int)sc_arg0(regs); uintptr_t shmaddr = (uintptr_t)sc_arg1(regs); - sc_ret(regs) = (uint32_t)(uintptr_t)shm_at(shmid, shmaddr); + int shmflg = (int)sc_arg2(regs); + sc_ret(regs) = (uint32_t)(uintptr_t)shm_at(shmid, shmaddr, shmflg); return; } -- 2.43.0