3.11.1 Objects and Their Descriptors

System V IPC — message queues (msgget), shared memory segments (shmget) and semaphore arrays (semget) — predates file descriptors and paths: an object is named by an integer key, identified by an integer id, and persists in the kernel until removed or reboot. Linux protects each with a nine-bit mode in struct ipc_perm, checked by ipcperms() against the caller's UID and GID.

On Peios that mode is inert. CAP_IPC_OWNER is in KACS's always-allow set (§3.10.2), so ipcperms() never denies on the mode and always reaches security_ipc_permission(); there KACS decides, against a security descriptor the object carries.

3.11.1.1 The descriptor #

Each object gets a descriptor when it is created, built from the creator's effective token: owner and group from the token; the creator's user SID, BUILTIN\Administrators and SYSTEM at GENERIC_ALL. It is held on the object's LSM blob for the object's life — persisting with the object across the creator's exit, as SysV objects do — and released when the object is removed.

The rights are those of <pkm/ipc.h>:

RightGrants
KACS_IPC_READmsgrcv; shmat read-only; semop without alter; GETVAL, GETPID, GETNCNT, GETZCNT, GETALL
KACS_IPC_WRITEmsgsnd; shmat read-write; semop with alter; SETVAL, SETALL
KACS_IPC_QUERY_INFORMATIONIPC_STAT and the SHM_STAT, MSG_STAT, SEM_STAT families
KACS_IPC_SET_INFORMATIONSHM_LOCK, SHM_UNLOCK
DELETEIPC_RMID
WRITE_DAC and WRITE_OWNERIPC_SET — one command carries mode, uid and gid, so it needs both
READ_CONTROLreading the descriptor with kacs_get_sd

The generic mapping: GENERIC_READ is read plus query and READ_CONTROL; GENERIC_WRITE is write plus set-information and READ_CONTROL; GENERIC_EXECUTE is query and READ_CONTROL; GENERIC_ALL is everything above.

3.11.1.2 Where the checks run #

ipcperms() runs for every data operation with the mode bits the operation would have needed — read, write or both — and security_ipc_permission() maps them to KACS_IPC_READ and KACS_IPC_WRITE and runs AccessCheck for the caller's effective token, under the caller's PIP context, against the object's descriptor. The *get path with an existing key goes through the same check with the requested mode. The control operations go through the per-object shmctl, msgctl and semctl hooks, which map the command to the right in the table above; commands that address no object (IPC_INFO, SHM_INFO, MSG_INFO, SEM_INFO) need nothing.

Linux's own ownership check on IPC_SET and IPC_RMID — that the caller's effective UID matches the object's creator or owner, or holds CAP_SYS_ADMIN — still runs first, on the projected UID, and cannot be relaxed by the descriptor: the hooks only ever further restrict. So an administrator who is not the object's creator needs both the descriptor's DELETE (which the default grants Administrators) and SeTcbPrivilege (what CAP_SYS_ADMIN maps to) to remove it. The uid, gid and mode that IPC_SET writes remain as Linux stores them and are what ipcs and IPC_STAT report; they are informational, as file mode bits are under FACS.

3.11.1.3 Reading and changing a descriptor #

A SysV object has no fd and no path, so kacs_get_sd and kacs_set_sd address it by kind and id: one of KACS_SD_AT_SYSV_SHM, KACS_SD_AT_SYSV_MSG or KACS_SD_AT_SYSV_SEM in flags, the object id in dirfd, and a NULL path. The object is looked up in the caller's IPC namespace; an unknown id is EINVAL and a removed one EIDRM. Reading needs the rights the requested SECURITY_INFORMATION implies (READ_CONTROL for owner, group and DACL; ACCESS_SYSTEM_SECURITY for the SACL), changing needs WRITE_DAC or WRITE_OWNER as for any object, and the new descriptor is merged into the existing one component by component, as for a process descriptor (§3.3.3).

3.11.1.4 Names #

The key namespace is claim-on-create: whoever calls *get with IPC_CREAT on a free key owns the object, and nothing prevents a process from claiming a key another program expected to create — the same shape as the abstract socket namespace and /dev/shm. The descriptor protects the object once it exists; it cannot protect the name. A program that needs a specific key uses IPC_EXCL and treats a failure as a signal, and a program that needs identity-carrying messaging uses an AF_UNIX socket (§3.5): a message queue conveys no sender identity, and msgrcv returns bytes and a type, nothing more.

Edit this page