# Appendix 3.E LSM integration

_Peios / Peios technical reference / PKM / KACS_

> The KACS security blobs, registered Linux Security Module hooks, and direct entry points at patched file-metadata call sites.

KACS registers as the `pkm` Linux Security Module. This appendix is an
implementation inventory for kernel developers: it describes the storage
and call sites behind the contracts in this chapter. These C structures
and callbacks are kernel-private, not userspace layouts or extension APIs.
The exported ABI remains in §3.A.

The inventory comes from `pkm/kacs/lsm.c` (`pkm_blob_sizes` and
`pkm_hooks[]`), the structures in `kacs/lsm_internal.h`, and the callback
implementations listed below. When changing those declarations, update
this inventory with the same change. The hook matrix preserves registration
order; each row names an actual `LSM_HOOK_INIT` entry.

## 3.E.1 Security-blob inventory

`pkm_blob_sizes` requests eight sized blob families. Each `lbs_*` entry
is initialized with `sizeof` the corresponding structure; Linux's LSM
infrastructure assigns its offset in the object's security storage. Byte
sizes and offsets depend on the build and are not fixed by this manual.

| LSM size entry | KACS structure | State carried |
|---|---|---|
| `lbs_cred` | `pkm_kacs_cred_security` | Token reference, shared `process_state`, projected UID/GID, and the pending descriptor used while overlayfs creates or copies up an inode. |
| `lbs_task` | `pkm_kacs_task_security` | Shared `process_state`, usermode-helper and impersonation state, the applied primary-installation epoch and thread-enrollment callback, deferred privilege-audit work, native-open/create requests, write/metadata decisions, and narrowly scoped StrataFS creation, supersede, cleanup and delete-on-close context. |
| `lbs_sock` | `pkm_kacs_socket_security` | Socket descriptor, conveyed peer/listener identities, token-conveyance cache and impersonation limits, binder identity/reuse decision, and the committed socket-owner identity used by network policy. |
| `lbs_ipc` | `pkm_kacs_ipc_security` | Refcounted descriptor and lock for a System V message queue, shared-memory segment or semaphore array. |
| `lbs_file` | `pkm_kacs_file_security` | Cached `granted_access` and `continuous_audit_mask`, copy-up context and phase generation, `managed`, `delete_on_close`, and the referenced token that armed deferred deletion. |
| `lbs_backing_file` | `pkm_kacs_backing_file_security` | Cached `granted_access` and `continuous_audit_mask`, plus `managed` and `inherited`, for the explicit outer-to-backing-file snapshot transfer. |
| `lbs_inode` | `pkm_kacs_inode_security` | Lock and RCU descriptor-cache pointer, delete-on-close lineage and signed-exec pin counters, and the deferred descriptor-persistence state. Test-only members exist under `CONFIG_SECURITY_PKM_KUNIT`. |
| `lbs_superblock` | `pkm_kacs_superblock_security` | Mount-policy lock, template descriptor bytes/length, policy generation and mount policy. |

The additional `lbs_xattr_count = 1` reserves one xattr-initialization
slot. It is not a ninth object blob or a byte-size declaration.

The file blob uses separate `u8 managed` and `u8 delete_on_close`
fields. There is no `flags` member or `KACS_FILE_FACS_MANAGED` constant.
The backing-file blob is distinct from the ordinary file blob: its
`inherited` marker records explicit adoption of the outer description's
cached grants and continuous-audit mask (§3.9.7).

The task blob reaches process-wide state through its `process_state`
pointer. The refcounted `pkm_kacs_process_state` contains `process_guid`,
`pip_type`, `pip_trust`, one `u32 mitigation_bits`, the KMES rate bucket,
the `process_sd` reference and process-scoped privilege-audit bookkeeping.
It also holds `primary_lock`, `desired_primary_token` and `primary_epoch`,
which order primary-token installation across the process's threads
(§3.2.3).
PIP identity and the process descriptor are not inline task-blob fields;
the process mitigations are not nine independent booleans. This shared
state is separate from the effective token used during impersonation.

The credential blob's `pending_create_sd` has the lifetime of an override
credential. Overlayfs uses it to stamp the descriptor computed for the
original object or caller/parent onto the actual created inode; credential
preparation does not inherit it into a derived credential. The task blob's
internal SD read/write depth and operation contexts similarly identify
specific kernel work; they are not caller-settable authorization flags.

## 3.E.2 Registered hook matrix

The current `pkm_hooks[]` table contains 99 registrations. Paths in the
last column are relative to the `pkm` source repository. A callback's
presence here identifies where KACS is called; the operation's access,
privilege and lifetime rules remain specified in the relevant chapter.

| Linux LSM hook | KACS callback | Implementation |
|---|---|---|
| `cred_prepare` | `pkm_kacs_cred_prepare` | `kacs/cred_lifecycle.c` |
| `cred_transfer` | `pkm_kacs_cred_transfer` | `kacs/cred_lifecycle.c` |
| `cred_alloc_blank` | `pkm_kacs_cred_alloc_blank` | `kacs/cred_lifecycle.c` |
| `cred_free` | `pkm_kacs_cred_free` | `kacs/cred_lifecycle.c` |
| `sb_alloc_security` | `pkm_kacs_sb_alloc_security` | `kacs/object_lifecycle.c` |
| `sb_free_security` | `pkm_kacs_sb_free_security` | `kacs/object_lifecycle.c` |
| `sb_kern_mount` | `pkm_kacs_sb_kern_mount` | `kacs/mnt_namespace.c` |
| `inode_alloc_security` | `pkm_kacs_inode_alloc_security` | `kacs/object_lifecycle.c` |
| `inode_free_security_rcu` | `pkm_kacs_inode_free_security_rcu` | `kacs/object_lifecycle.c` |
| `inode_getattr` | `pkm_kacs_inode_getattr` | `kacs/file_metadata.c` |
| `path_notify` | `pkm_kacs_path_notify` | `kacs/namespace.c` |
| `inode_setattr` | `pkm_kacs_inode_setattr` | `kacs/file_metadata.c` |
| `inode_file_getattr` | `pkm_kacs_inode_file_getattr` | `kacs/file_metadata.c` |
| `inode_file_setattr` | `pkm_kacs_inode_file_setattr` | `kacs/file_metadata.c` |
| `inode_xattr_skipcap` | `pkm_kacs_inode_xattr_skipcap` | `kacs/file_metadata.c` |
| `inode_getxattr` | `pkm_kacs_inode_getxattr` | `kacs/file_metadata.c` |
| `inode_setxattr` | `pkm_kacs_inode_setxattr` | `kacs/file_metadata.c` |
| `inode_post_setxattr` | `pkm_kacs_inode_post_setxattr` | `kacs/file_metadata.c` |
| `inode_removexattr` | `pkm_kacs_inode_removexattr` | `kacs/file_metadata.c` |
| `inode_listxattr` | `pkm_kacs_inode_listxattr` | `kacs/file_metadata.c` |
| `inode_copy_up` | `pkm_kacs_inode_copy_up` | `kacs/file_metadata.c` |
| `inode_copy_up_xattr` | `pkm_kacs_inode_copy_up_xattr` | `kacs/file_metadata.c` |
| `inode_follow_link` | `pkm_kacs_inode_follow_link` | `kacs/file_metadata.c` |
| `inode_set_acl` | `pkm_kacs_inode_set_acl` | `kacs/file_metadata.c` |
| `inode_remove_acl` | `pkm_kacs_inode_remove_acl` | `kacs/file_metadata.c` |
| `inode_getsecurity` | `pkm_kacs_inode_getsecurity` | `kacs/file_metadata.c` |
| `inode_permission` | `pkm_kacs_inode_permission` | `kacs/namespace.c` |
| `inode_create` | `pkm_kacs_inode_create` | `kacs/namespace.c` |
| `inode_link` | `pkm_kacs_inode_link` | `kacs/namespace.c` |
| `inode_unlink` | `pkm_kacs_inode_unlink` | `kacs/namespace.c` |
| `inode_symlink` | `pkm_kacs_inode_symlink` | `kacs/namespace.c` |
| `inode_mkdir` | `pkm_kacs_inode_mkdir` | `kacs/namespace.c` |
| `inode_rmdir` | `pkm_kacs_inode_rmdir` | `kacs/namespace.c` |
| `inode_mknod` | `pkm_kacs_inode_mknod` | `kacs/namespace.c` |
| `inode_rename` | `pkm_kacs_inode_rename` | `kacs/namespace.c` |
| `inode_readlink` | `pkm_kacs_inode_readlink` | `kacs/namespace.c` |
| `inode_init_security` | `pkm_kacs_inode_init_security` | `kacs/namespace.c` |
| `inode_post_create_tmpfile` | `pkm_kacs_copy_up_post_create_tmpfile` | `kacs/copy_up.c` |
| `dentry_create_files_as` | `pkm_kacs_dentry_create_files_as` | `kacs/namespace.c` |
| `file_alloc_security` | `pkm_kacs_file_alloc_security` | `kacs/object_lifecycle.c` |
| `backing_file_alloc` | `pkm_kacs_backing_file_alloc` | `kacs/object_lifecycle.c` |
| `file_release` | `pkm_kacs_file_release` | `kacs/object_lifecycle.c` |
| `file_open` | `pkm_kacs_file_open` | `kacs/file_access.c` |
| `file_receive` | `pkm_kacs_file_receive` | `kacs/object_lifecycle.c` |
| `file_permission` | `pkm_kacs_file_permission` | `kacs/file_access.c` |
| `file_ioctl` | `pkm_kacs_file_ioctl` | `kacs/file_access.c` |
| `file_ioctl_compat` | `pkm_kacs_file_ioctl_compat` | `kacs/file_access.c` |
| `file_lock` | `pkm_kacs_file_lock` | `kacs/file_access.c` |
| `file_fcntl` | `pkm_kacs_file_fcntl` | `kacs/file_access.c` |
| `file_truncate` | `pkm_kacs_file_truncate` | `kacs/file_access.c` |
| `kernel_read_file` | `pkm_kacs_kernel_read_file` | `kacs/firmware.c` |
| `kernel_post_read_file` | `pkm_kacs_kernel_post_read_file` | `kacs/firmware.c` |
| `task_alloc` | `pkm_kacs_task_alloc` | `kacs/task_lifecycle.c` |
| `task_free` | `pkm_kacs_task_free` | `kacs/task_lifecycle.c` |
| `sk_alloc_security` | `pkm_kacs_sk_alloc_security` | `kacs/socket.c` |
| `sk_free_security` | `pkm_kacs_sk_free_security` | `kacs/socket.c` |
| `sk_clone_security` | `pkm_kacs_sk_clone_security` | `kacs/socket.c` |
| `socket_post_create` | `pkm_kacs_socket_post_create` | `kacs/socket.c` |
| `socket_bind` | `pkm_kacs_socket_bind` | `kacs/socket.c` |
| `socket_connect` | `pkm_kacs_socket_connect` | `kacs/socket.c` |
| `unix_stream_connect` | `pkm_kacs_unix_stream_connect` | `kacs/socket.c` |
| `unix_may_send` | `pkm_kacs_unix_may_send` | `kacs/socket.c` |
| `socket_listen` | `pkm_kacs_socket_listen` | `kacs/socket.c` |
| `ipc_permission` | `pkm_kacs_ipc_permission` | `kacs/ipc.c` |
| `msg_queue_alloc_security` | `pkm_kacs_ipc_alloc_security` | `kacs/ipc.c` |
| `msg_queue_free_security` | `pkm_kacs_ipc_free_security` | `kacs/ipc.c` |
| `msg_queue_msgctl` | `pkm_kacs_msg_queue_msgctl` | `kacs/ipc.c` |
| `shm_alloc_security` | `pkm_kacs_ipc_alloc_security` | `kacs/ipc.c` |
| `shm_free_security` | `pkm_kacs_ipc_free_security` | `kacs/ipc.c` |
| `shm_shmctl` | `pkm_kacs_shm_shmctl` | `kacs/ipc.c` |
| `sem_alloc_security` | `pkm_kacs_ipc_alloc_security` | `kacs/ipc.c` |
| `sem_free_security` | `pkm_kacs_ipc_free_security` | `kacs/ipc.c` |
| `sem_semctl` | `pkm_kacs_sem_semctl` | `kacs/ipc.c` |
| `task_kill` | `pkm_kacs_task_kill` | `kacs/process_access.c` |
| `ptrace_access_check` | `pkm_kacs_ptrace_access_check` | `kacs/process_access.c` |
| `ptrace_traceme` | `pkm_kacs_ptrace_traceme` | `kacs/process_access.c` |
| `task_setnice` | `pkm_kacs_task_setnice` | `kacs/process_access.c` |
| `task_setscheduler` | `pkm_kacs_task_setscheduler` | `kacs/process_access.c` |
| `task_setioprio` | `pkm_kacs_task_setioprio` | `kacs/process_access.c` |
| `task_setpgid` | `pkm_kacs_task_setpgid` | `kacs/process_access.c` |
| `task_getpgid` | `pkm_kacs_task_getpgid` | `kacs/process_access.c` |
| `task_getsid` | `pkm_kacs_task_getsid` | `kacs/process_access.c` |
| `task_getscheduler` | `pkm_kacs_task_getscheduler` | `kacs/process_access.c` |
| `task_getioprio` | `pkm_kacs_task_getioprio` | `kacs/process_access.c` |
| `task_movememory` | `pkm_kacs_task_movememory` | `kacs/process_access.c` |
| `task_fix_setuid` | `pkm_kacs_task_fix_setuid` | `kacs/cred_projection.c` |
| `task_fix_setgid` | `pkm_kacs_task_fix_setgid` | `kacs/cred_projection.c` |
| `task_fix_setgroups` | `pkm_kacs_task_fix_setgroups` | `kacs/cred_projection.c` |
| `task_prlimit` | `pkm_kacs_task_prlimit` | `kacs/process_access.c` |
| `capable` | `pkm_kacs_capable` | `kacs/capability.c` |
| `capset` | `pkm_kacs_capset` | `kacs/capability.c` |
| `task_prctl` | `pkm_kacs_task_prctl` | `kacs/psb.c` |
| `mmap_file` | `pkm_kacs_mmap_file` | `kacs/psb.c` |
| `mmap_backing_file` | `pkm_kacs_mmap_backing_file` | `kacs/object_lifecycle.c` |
| `file_mprotect` | `pkm_kacs_file_mprotect` | `kacs/psb.c` |
| `bprm_check_security` | `pkm_kacs_bprm_check_security` | `kacs/exec.c` |
| `bprm_creds_from_file` | `pkm_kacs_bprm_creds_from_file` | `kacs/exec.c` |
| `bprm_committing_creds` | `pkm_kacs_bprm_committing_creds` | `kacs/exec.c` |
| `bprm_committed_creds` | `pkm_kacs_bprm_committed_creds` | `kacs/exec.c` |

## 3.E.3 Direct file-metadata entry points

An LSM hook receives the arguments supplied by the Linux hook API. Some
file-descriptor operations also need the particular open file's cached
FACS grant. PKM's patch series therefore calls KACS directly at the
file-descriptor call site, before the later inode-level work. These
functions are declared and called directly under `CONFIG_SECURITY_PKM`;
they are not additional entries in `pkm_hooks[]` and are not dispatched
through another LSM's hook table.

| File-descriptor operation | Direct KACS entry point | Patch in `kernel/patches/fs/` |
|---|---|---|
| Change mode | `pkm_kacs_file_chmod` | `open-fchmod-fchown-gate.patch` |
| Change owner/group | `pkm_kacs_file_chown` | `open-fchmod-fchown-gate.patch` |
| Change timestamps through a file descriptor | `pkm_kacs_file_utimens` | `utimes-gate.patch` |
| Read file attributes through a file descriptor | `pkm_kacs_file_getattr` | `stat-getattr-gate.patch` |
| Read an xattr through a file descriptor | `pkm_kacs_file_sd_xattr_get` | `xattr-raw-sd-guard.patch` |
| Set an xattr through a file descriptor | `pkm_kacs_file_sd_xattr_set` | `xattr-raw-sd-guard.patch` |
| Remove an xattr through a file descriptor | `pkm_kacs_file_sd_xattr_remove` | `xattr-raw-sd-guard.patch` |

All seven implementations are in `kacs/file_metadata.c`. The xattr
functions enforce the file's metadata grant as well as the separate
rules for protected SD attributes; their names do not make raw SD-xattr
access a supported security-descriptor API.

The names `security_file_setattr`, `security_file_getattr`,
`security_file_getxattr` and `security_file_setxattr` do not name hooks
provided by this kernel. In particular, do not confuse them with the
real `inode_file_getattr` and `inode_file_setattr` registrations in the
matrix: those receive a dentry and `struct file_kattr`, not the open file
whose cached grant the direct entry points consult. The metadata decision
record connects the file-level check to the later inode-level operation.
This table covers those file-metadata entry points, not every direct
KACS call in PKM's patch series.

## 3.E.4 Reserved access-mask bits

`RESERVED_ACCESS_MASK_BITS` in
`crates/kacs-core/src/access_mask.rs` is `0x0ce0_0000` (bits 21, 22, 23,
26 and 27, counting from zero). It remains a private evaluator constant,
not a new UAPI definition. §3.8.10 already specifies the public behavior:
reserved bits in a desired mask or any ACE mask reject the check, rather
than being ignored. This inventory records the implementation value
without adding another exported spelling.
