[starnix][selinux] Create a clearer layout for the LSM/SELinux impl

The kernel's "selinux" subdirectory is renamed "security" to reflect
that the hooks and data structures it provides are in principle generic,
not tied to a specific choice of Linux Security Module.

Within the "security" directory a subdirectory holds the SELinux-specific
integration for the various hooks; since SELinux is the only LSM built
into Starnix some aspects are currently (re)published from the "security"
module.

The SELinux and procattr filesystems remain in the "security" directory
for now; the latter will be migrated to interface to SELinux via hooks,
similar to other parts of the kernel, and moved into the kernel's "fs"
module.

Bug: 335397745
Change-Id: Ia6ac8d0d794da5c2aed56d8f1b06d49235ba0d32
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1030212
Reviewed-by: Mark Dittmer <markdittmer@google.com>
Fuchsia-Auto-Submit: Wez <wez@google.com>
Reviewed-by: James Robinson <jamesr@google.com>
Commit-Queue: Wez <wez@google.com>
diff --git a/src/starnix/kernel/BUILD.gn b/src/starnix/kernel/BUILD.gn
index f5707a2..f113830 100644
--- a/src/starnix/kernel/BUILD.gn
+++ b/src/starnix/kernel/BUILD.gn
@@ -175,11 +175,10 @@
     "power/suspend_stats.rs",
     "power/sync_on_suspend.rs",
     "power/wakeup_count.rs",
-    "selinux/fs.rs",
-    "selinux/hooks/current_task_hooks.rs",
-    "selinux/hooks/mod.rs",
-    "selinux/hooks/thread_group_hooks.rs",
-    "selinux/mod.rs",
+    "security/fs.rs",
+    "security/hooks.rs",
+    "security/mod.rs",
+    "security/selinux_hooks/mod.rs",
     "signals/mod.rs",
     "signals/signal_handling.rs",
     "signals/signalfd.rs",
diff --git a/src/starnix/kernel/device/binder.rs b/src/starnix/kernel/device/binder.rs
index 1368f95..4188c05 100644
--- a/src/starnix/kernel/device/binder.rs
+++ b/src/starnix/kernel/device/binder.rs
@@ -12,6 +12,7 @@
         MemoryAccessorExt, ProtectionFlags,
     },
     mutable_state::Guard,
+    security,
     task::{
         CurrentTask, EventHandler, Kernel, SchedulerPolicy, SimpleWaiter, Task, WaitCanceler,
         WaitQueue, Waiter,
@@ -3504,15 +3505,10 @@
                 let target_task = weak_task.upgrade().ok_or_else(|| TransactionError::Dead)?;
                 let security_context: Option<FsString> =
                     if object.flags.contains(BinderObjectFlags::TXN_SECURITY_CTX) {
-                        let security_server = target_task
-                            .kernel()
-                            .security_server
-                            .as_ref()
-                            .expect("SELinux is not enabled");
-                        let sid = target_task.thread_group.read().selinux_state.current_sid.clone();
-                        let mut security_context = security_server
-                            .sid_to_security_context(sid)
-                            .map_or(FsString::default(), FsString::from);
+                        let mut security_context = FsString::from(
+                            security::get_task_context(&current_task, &target_task)
+                                .unwrap_or_default(),
+                        );
                         security_context.push(b'\0');
                         Some(security_context)
                     } else {
diff --git a/src/starnix/kernel/fs/proc/pid_directory.rs b/src/starnix/kernel/fs/proc/pid_directory.rs
index c79c249..d534c90 100644
--- a/src/starnix/kernel/fs/proc/pid_directory.rs
+++ b/src/starnix/kernel/fs/proc/pid_directory.rs
@@ -4,7 +4,7 @@
 
 use crate::{
     mm::{MemoryAccessor, MemoryAccessorExt, ProcMapsFile, ProcSmapsFile, PAGE_SIZE},
-    selinux::fs::selinux_proc_attrs,
+    security::fs::selinux_proc_attrs,
     task::{CurrentTask, Task, TaskPersistentInfo, TaskStateCode, ThreadGroup},
     vfs::{
         buffers::{InputBuffer, OutputBuffer},
@@ -276,6 +276,7 @@
         // owned by the effective user and effective group ID of the process."
         dir.entry_creds(task.creds().euid_as_fscred());
         dir.dir_creds(task.creds().euid_as_fscred());
+        // TODO(b/322850635): Add get/set_procattr hooks and move procattr impl here.
         selinux_proc_attrs(current_task, task, dir);
     });
     dir.entry(current_task, "ns", NsDirectory { task: task.into() }, mode!(IFDIR, 0o777));
diff --git a/src/starnix/kernel/lib.rs b/src/starnix/kernel/lib.rs
index bb328a8..5446dace 100644
--- a/src/starnix/kernel/lib.rs
+++ b/src/starnix/kernel/lib.rs
@@ -15,7 +15,7 @@
 pub mod mm;
 pub mod mutable_state;
 pub mod power;
-pub mod selinux;
+pub mod security;
 pub mod signals;
 pub mod syscalls;
 pub mod task;
diff --git a/src/starnix/kernel/loader.rs b/src/starnix/kernel/loader.rs
index 7965427..b143bfe2 100644
--- a/src/starnix/kernel/loader.rs
+++ b/src/starnix/kernel/loader.rs
@@ -7,7 +7,7 @@
         vmo::round_up_to_system_page_size, DesiredAddress, MappingName, MappingOptions,
         MemoryAccessor, MemoryManager, ProtectionFlags, PAGE_SIZE, VMEX_RESOURCE,
     },
-    selinux::hooks::thread_group_hooks::SeLinuxResolvedElfState,
+    security,
     task::CurrentTask,
     vfs::{FileHandle, FileWriteGuardMode, FileWriteGuardRef},
 };
@@ -249,7 +249,7 @@
     /// The environment to initialize for the new process.
     pub environ: Vec<CString>,
     /// The SELinux state for the new process. None if SELinux is disabled.
-    pub selinux_state: Option<SeLinuxResolvedElfState>,
+    pub security_state: Option<security::ResolvedElfState>,
     /// Exec/write lock.
     pub file_write_guard: FileWriteGuardRef,
 }
@@ -278,13 +278,13 @@
     path: CString,
     argv: Vec<CString>,
     environ: Vec<CString>,
-    selinux_state: Option<SeLinuxResolvedElfState>,
+    security_state: Option<security::ResolvedElfState>,
 ) -> Result<ResolvedElf, Errno>
 where
     L: LockBefore<FileOpsCore>,
     L: LockBefore<DeviceOpen>,
 {
-    resolve_executable_impl(locked, current_task, file, path, argv, environ, 0, selinux_state)
+    resolve_executable_impl(locked, current_task, file, path, argv, environ, 0, security_state)
 }
 
 /// Resolves a file into a validated executable ELF, following script interpreters to a fixed
@@ -297,7 +297,7 @@
     argv: Vec<CString>,
     environ: Vec<CString>,
     recursion_depth: usize,
-    selinux_state: Option<SeLinuxResolvedElfState>,
+    security_state: Option<security::ResolvedElfState>,
 ) -> Result<ResolvedElf, Errno>
 where
     L: LockBefore<FileOpsCore>,
@@ -324,10 +324,10 @@
             argv,
             environ,
             recursion_depth,
-            selinux_state,
+            security_state,
         )
     } else {
-        resolve_elf(locked, current_task, file, vmo, argv, environ, selinux_state)
+        resolve_elf(locked, current_task, file, vmo, argv, environ, security_state)
     }
 }
 
@@ -340,7 +340,7 @@
     argv: Vec<CString>,
     environ: Vec<CString>,
     recursion_depth: usize,
-    selinux_state: Option<SeLinuxResolvedElfState>,
+    security_state: Option<security::ResolvedElfState>,
 ) -> Result<ResolvedElf, Errno>
 where
     L: LockBefore<FileOpsCore>,
@@ -374,7 +374,7 @@
         args,
         environ,
         recursion_depth + 1,
-        selinux_state,
+        security_state,
     )
 }
 
@@ -424,7 +424,7 @@
     vmo: Arc<zx::Vmo>,
     argv: Vec<CString>,
     environ: Vec<CString>,
-    selinux_state: Option<SeLinuxResolvedElfState>,
+    security_state: Option<security::ResolvedElfState>,
 ) -> Result<ResolvedElf, Errno>
 where
     L: LockBefore<FileOpsCore>,
@@ -456,7 +456,7 @@
     };
     let file_write_guard =
         file.name.entry.node.create_write_guard(FileWriteGuardMode::Exec)?.into_ref();
-    Ok(ResolvedElf { file, vmo, interp, argv, environ, selinux_state, file_write_guard })
+    Ok(ResolvedElf { file, vmo, interp, argv, environ, security_state, file_write_guard })
 }
 
 /// Loads a resolved ELF into memory, along with an interpreter if one is defined, and initializes
diff --git a/src/starnix/kernel/selinux/OWNERS b/src/starnix/kernel/security/OWNERS
similarity index 100%
rename from src/starnix/kernel/selinux/OWNERS
rename to src/starnix/kernel/security/OWNERS
diff --git a/src/starnix/kernel/selinux/fs.rs b/src/starnix/kernel/security/fs.rs
similarity index 96%
rename from src/starnix/kernel/selinux/fs.rs
rename to src/starnix/kernel/security/fs.rs
index 117af40..9daaba9 100644
--- a/src/starnix/kernel/selinux/fs.rs
+++ b/src/starnix/kernel/security/fs.rs
@@ -663,20 +663,20 @@
             }
         };
 
-        // SELinux is enabled, so the task must have `selinux_state`. Lock it for writing
+        // SELinux is enabled, so the task must have `security_state`. Lock it for writing
         // and update it.
         let mut tg = task.thread_group.write();
 
         use SeProcAttrNodeType::*;
         match self.attr {
-            Current => tg.selinux_state.current_sid = sid.ok_or(errno!(EINVAL))?,
-            Exec => tg.selinux_state.exec_sid = sid,
-            FsCreate => tg.selinux_state.fscreate_sid = sid,
-            KeyCreate => tg.selinux_state.keycreate_sid = sid,
+            Current => tg.security_state.0.current_sid = sid.ok_or(errno!(EINVAL))?,
+            Exec => tg.security_state.0.exec_sid = sid,
+            FsCreate => tg.security_state.0.fscreate_sid = sid,
+            KeyCreate => tg.security_state.0.keycreate_sid = sid,
             Previous => {
                 return error!(EINVAL);
             }
-            SockCreate => tg.selinux_state.sockcreate_sid = sid,
+            SockCreate => tg.security_state.0.sockcreate_sid = sid,
         };
 
         Ok(())
@@ -693,12 +693,12 @@
                 let sid = {
                     let tg = task.thread_group.read();
                     match self.attr {
-                        Current => Some(tg.selinux_state.current_sid),
-                        Exec => tg.selinux_state.exec_sid,
-                        FsCreate => tg.selinux_state.fscreate_sid,
-                        KeyCreate => tg.selinux_state.keycreate_sid,
-                        Previous => Some(tg.selinux_state.previous_sid),
-                        SockCreate => tg.selinux_state.sockcreate_sid,
+                        Current => Some(tg.security_state.0.current_sid),
+                        Exec => tg.security_state.0.exec_sid,
+                        FsCreate => tg.security_state.0.fscreate_sid,
+                        KeyCreate => tg.security_state.0.keycreate_sid,
+                        Previous => Some(tg.security_state.0.previous_sid),
+                        SockCreate => tg.security_state.0.sockcreate_sid,
                     }
                 };
 
diff --git a/src/starnix/kernel/selinux/hooks/current_task_hooks.rs b/src/starnix/kernel/security/hooks.rs
similarity index 86%
rename from src/starnix/kernel/selinux/hooks/current_task_hooks.rs
rename to src/starnix/kernel/security/hooks.rs
index 73b7f18f..ff0f54c 100644
--- a/src/starnix/kernel/selinux/hooks/current_task_hooks.rs
+++ b/src/starnix/kernel/security/hooks.rs
@@ -2,19 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use std::sync::Arc;
-
-use super::thread_group_hooks::{self, SeLinuxResolvedElfState};
+use super::{selinux_hooks, ResolvedElfState, ThreadGroupState};
 use crate::{
-    task::{CurrentTask, Task, ThreadGroup},
+    task::{CurrentTask, Kernel, Task, ThreadGroup},
     vfs::{FsNode, FsNodeHandle, FsStr, ValueOrSize},
 };
 
-use selinux::{
-    security_server::{SecurityServer, SecurityServerStatus},
-    InitialSid, SecurityId,
+use {
+    selinux::{
+        security_server::{SecurityServer, SecurityServerStatus},
+        InitialSid, SecurityId,
+    },
+    starnix_uapi::{error, errors::Errno, signals::Signal},
+    std::sync::Arc,
 };
-use starnix_uapi::{errors::Errno, signals::Signal};
 
 /// Maximum supported size for the `"security.selinux"` value used to store SELinux security
 /// contexts in a filesystem node extended attributes.
@@ -73,11 +74,38 @@
     })
 }
 
+/// Returns an `ThreadGroupState` instance for a new task.
+pub fn alloc_security(kernel: &Kernel, parent: Option<&ThreadGroupState>) -> ThreadGroupState {
+    ThreadGroupState(if kernel.security_server.is_none() {
+        selinux_hooks::ThreadGroupState::for_selinux_disabled()
+    } else {
+        selinux_hooks::alloc_security(parent.map(|tgs| &tgs.0))
+    })
+}
+
+fn get_current_sid(thread_group: &Arc<ThreadGroup>) -> SecurityId {
+    thread_group.read().security_state.0.current_sid
+}
+
+/// Returns the serialized Security Context associated with the specified task.
+/// If the task's current SID cannot be resolved then an empty string is returned.
+/// This combines the `task_getsecid()` and `secid_to_secctx()` hooks, in effect.
+pub fn get_task_context(current_task: &CurrentTask, target: &Task) -> Result<Vec<u8>, Errno> {
+    run_if_selinux_else(
+        current_task,
+        |security_server| {
+            let sid = get_current_sid(&target.thread_group);
+            Ok(security_server.sid_to_security_context(sid).unwrap_or_default())
+        },
+        || error!(ENOTSUP),
+    )
+}
+
 /// Check if creating a task is allowed.
 pub fn check_task_create_access(current_task: &CurrentTask) -> Result<(), Errno> {
     check_if_selinux(current_task, |security_server| {
-        let sid = current_task.get_current_sid();
-        thread_group_hooks::check_task_create_access(&security_server.as_permission_check(), sid)
+        let sid = get_current_sid(&current_task.thread_group);
+        selinux_hooks::check_task_create_access(&security_server.as_permission_check(), sid)
     })
 }
 
@@ -85,28 +113,29 @@
 pub fn check_exec_access(
     current_task: &CurrentTask,
     executable_node: &FsNodeHandle,
-) -> Result<Option<SeLinuxResolvedElfState>, Errno> {
+) -> Result<Option<ResolvedElfState>, Errno> {
     check_if_selinux(current_task, |security_server| {
         let executable_sid = executable_node.effective_sid(current_task);
         let group_state = current_task.thread_group.read();
-        thread_group_hooks::check_exec_access(
+        selinux_hooks::check_exec_access(
             &security_server,
-            &group_state.selinux_state,
+            &group_state.security_state.0,
             executable_sid,
         )
+        .map(|s| s.map(|s| ResolvedElfState(s)))
     })
 }
 
 /// Updates the SELinux thread group state on exec.
 pub fn update_state_on_exec(
     current_task: &mut CurrentTask,
-    elf_selinux_state: &Option<SeLinuxResolvedElfState>,
+    elf_security_state: &Option<ResolvedElfState>,
 ) {
     run_if_selinux(current_task, |_| {
         let mut thread_group_state = current_task.thread_group.write();
-        thread_group_hooks::update_state_on_exec(
-            &mut thread_group_state.selinux_state,
-            elf_selinux_state,
+        selinux_hooks::update_state_on_exec(
+            &mut thread_group_state.security_state.0,
+            elf_security_state.as_ref().map(|s| s.0),
         );
     });
 }
@@ -116,9 +145,9 @@
     check_if_selinux(source, |security_server| {
         // TODO(b/323856891): Consider holding `source.thread_group` and `target.thread_group`
         // read locks for duration of access check.
-        let source_sid = source.get_current_sid();
-        let target_sid = target.get_current_sid();
-        thread_group_hooks::check_getsched_access(
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_getsched_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -129,9 +158,9 @@
 /// Checks if setsched is allowed.
 pub fn check_setsched_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
     check_if_selinux(source, |security_server| {
-        let source_sid = source.get_current_sid();
-        let target_sid = target.get_current_sid();
-        thread_group_hooks::check_setsched_access(
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_setsched_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -140,11 +169,11 @@
 }
 
 /// Checks if getpgid is allowed.
-pub fn check_getpgid_access(source_task: &CurrentTask, target_task: &Task) -> Result<(), Errno> {
-    check_if_selinux(source_task, |security_server| {
-        let source_sid = source_task.get_current_sid();
-        let target_sid = target_task.get_current_sid();
-        thread_group_hooks::check_getpgid_access(
+pub fn check_getpgid_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
+    check_if_selinux(source, |security_server| {
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_getpgid_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -153,11 +182,11 @@
 }
 
 /// Checks if setpgid is allowed.
-pub fn check_setpgid_access(source_task: &CurrentTask, target_task: &Task) -> Result<(), Errno> {
-    check_if_selinux(source_task, |security_server| {
-        let source_sid = source_task.get_current_sid();
-        let target_sid = target_task.get_current_sid();
-        thread_group_hooks::check_setpgid_access(
+pub fn check_setpgid_access(source: &CurrentTask, target: &Task) -> Result<(), Errno> {
+    check_if_selinux(source, |security_server| {
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_setpgid_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -167,14 +196,14 @@
 
 /// Checks if sending a signal is allowed.
 pub fn check_signal_access(
-    source_task: &CurrentTask,
-    target_task: &Task,
+    source: &CurrentTask,
+    target: &Task,
     signal: Signal,
 ) -> Result<(), Errno> {
-    check_if_selinux(source_task, |security_server| {
-        let source_sid = source_task.get_current_sid();
-        let target_sid = target_task.get_current_sid();
-        thread_group_hooks::check_signal_access(
+    check_if_selinux(source, |security_server| {
+        let source_sid = get_current_sid(&source.thread_group);
+        let target_sid = get_current_sid(&target.thread_group);
+        selinux_hooks::check_signal_access(
             &security_server.as_permission_check(),
             source_sid,
             target_sid,
@@ -190,12 +219,12 @@
     current_task: &CurrentTask,
 ) -> Result<(), Errno> {
     check_if_selinux(current_task, |security_server| {
-        let tracer_sid = parent.get_current_sid();
+        let tracer_sid = get_current_sid(parent);
         let mut thread_group_state = current_task.thread_group.write();
-        thread_group_hooks::check_ptrace_access_and_update_state(
+        selinux_hooks::check_ptrace_access_and_update_state(
             &security_server.as_permission_check(),
             tracer_sid,
-            &mut thread_group_state.selinux_state,
+            &mut thread_group_state.security_state.0,
         )
     })
 }
@@ -207,12 +236,12 @@
     tracee_task: &Task,
 ) -> Result<(), Errno> {
     check_if_selinux(current_task, |security_server| {
-        let tracer_sid = current_task.get_current_sid();
+        let tracer_sid = get_current_sid(&current_task.thread_group);
         let mut thread_group_state = tracee_task.thread_group.write();
-        thread_group_hooks::check_ptrace_access_and_update_state(
+        selinux_hooks::check_ptrace_access_and_update_state(
             &security_server.as_permission_check(),
             tracer_sid,
-            &mut thread_group_state.selinux_state,
+            &mut thread_group_state.security_state.0,
         )
     })
 }
@@ -221,7 +250,7 @@
 pub fn clear_ptracer_sid(tracee_task: &Task) {
     run_if_selinux(tracee_task, |_| {
         let mut thread_group_state = tracee_task.thread_group.write();
-        thread_group_state.selinux_state.ptracer_sid = None;
+        thread_group_state.security_state.0.ptracer_sid = None;
     });
 }
 
@@ -308,13 +337,12 @@
     use selinux::security_server::Mode;
     use starnix_sync::{Locked, Unlocked};
     use starnix_uapi::{device_type::DeviceType, error, file_mode::FileMode, signals::SIGTERM};
-    use tests::thread_group_hooks::SeLinuxThreadGroupState;
 
     const VALID_SECURITY_CONTEXT: &'static str = "u:object_r:test_valid_t:s0";
     const DIFFERENT_VALID_SECURITY_CONTEXT: &'static str = "u:object_r:test_different_valid_t:s0";
 
     const HOOKS_TESTS_BINARY_POLICY: &[u8] =
-        include_bytes!("../../../lib/selinux/testdata/micro_policies/hooks_tests_policy.pp");
+        include_bytes!("../../lib/selinux/testdata/micro_policies/hooks_tests_policy.pp");
 
     fn security_server_with_policy(mode: Mode) -> Arc<SecurityServer> {
         let policy_bytes = HOOKS_TESTS_BINARY_POLICY.to_vec();
@@ -415,6 +443,13 @@
         assert_eq!(run_else_result, TestHookResult::WasRun);
     }
 
+    #[fuchsia::test]
+    async fn alloc_security_selinux_disabled() {
+        let (kernel, _current_task) = create_kernel_and_task();
+
+        alloc_security(&kernel, None);
+    }
+
     fn failing_hook(_: &Arc<SecurityServer>) -> Result<(), Errno> {
         error!(EINVAL)
     }
@@ -506,13 +541,13 @@
         // Without SELinux enabled and a policy loaded, only `InitialSid` values exist
         // in the system.
         let kernel_sid = SecurityId::initial(InitialSid::Kernel);
-        let elf_state = SeLinuxResolvedElfState { sid: kernel_sid };
+        let elf_state = ResolvedElfState(kernel_sid);
 
-        assert!(task.thread_group.read().selinux_state.current_sid != kernel_sid);
+        assert!(task.thread_group.read().security_state.0.current_sid != kernel_sid);
 
-        let before_hook_sid = task.thread_group.read().selinux_state.current_sid;
+        let before_hook_sid = task.thread_group.read().security_state.0.current_sid;
         update_state_on_exec(&mut task, &Some(elf_state));
-        assert_eq!(task.thread_group.read().selinux_state.current_sid, before_hook_sid);
+        assert_eq!(task.thread_group.read().security_state.0.current_sid, before_hook_sid);
     }
 
     #[fuchsia::test]
@@ -523,21 +558,21 @@
 
         // Without SELinux enabled and a policy loaded, only `InitialSid` values exist
         // in the system.
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
+        let initial_state = selinux_hooks::ThreadGroupState::for_kernel();
         let elf_sid = SecurityId::initial(InitialSid::Unlabeled);
-        let elf_state = SeLinuxResolvedElfState { sid: elf_sid };
+        let elf_state = ResolvedElfState(elf_sid);
         assert_ne!(elf_sid, initial_state.current_sid);
         update_state_on_exec(&mut task, &Some(elf_state));
-        assert_eq!(task.thread_group.read().selinux_state, initial_state);
+        assert_eq!(task.thread_group.read().security_state.0, initial_state);
     }
 
     #[fuchsia::test]
     async fn state_update_for_fake_mode() {
         let security_server = security_server_with_policy(Mode::Fake);
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
+        let initial_state = selinux_hooks::ThreadGroupState::for_kernel();
         let (kernel, task) = create_kernel_and_task_with_selinux(security_server);
         let mut task = task;
-        task.thread_group.write().selinux_state = initial_state.clone();
+        task.thread_group.write().security_state.0 = initial_state.clone();
 
         let elf_sid = kernel
             .security_server
@@ -545,30 +580,30 @@
             .expect("missing security server")
             .security_context_to_sid(b"u:object_r:fork_no_t:s0")
             .expect("invalid security context");
-        let elf_state = SeLinuxResolvedElfState { sid: elf_sid };
+        let elf_state = ResolvedElfState(elf_sid);
         assert_ne!(elf_sid, initial_state.current_sid);
         update_state_on_exec(&mut task, &Some(elf_state));
-        assert_eq!(task.thread_group.read().selinux_state.current_sid, elf_sid);
+        assert_eq!(task.thread_group.read().security_state.0.current_sid, elf_sid);
     }
 
     #[fuchsia::test]
     async fn state_update_for_permissive_mode() {
         let security_server = security_server_with_policy(Mode::Enable);
         security_server.set_enforcing(false);
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
+        let initial_state = selinux_hooks::ThreadGroupState::for_kernel();
         let (kernel, task) = create_kernel_and_task_with_selinux(security_server);
         let mut task = task;
-        task.thread_group.write().selinux_state = initial_state.clone();
+        task.thread_group.write().security_state.0 = initial_state.clone();
         let elf_sid = kernel
             .security_server
             .as_ref()
             .expect("missing security server")
             .security_context_to_sid(b"u:object_r:fork_no_t:s0")
             .expect("invalid security context");
-        let elf_state = SeLinuxResolvedElfState { sid: elf_sid };
+        let elf_state = ResolvedElfState(elf_sid);
         assert_ne!(elf_sid, initial_state.current_sid);
         update_state_on_exec(&mut task, &Some(elf_state));
-        assert_eq!(task.thread_group.read().selinux_state.current_sid, elf_sid);
+        assert_eq!(task.thread_group.read().security_state.0.current_sid, elf_sid);
     }
 
     #[fuchsia::test]
@@ -711,11 +746,11 @@
         let security_server = security_server_with_policy(Mode::Enable);
         security_server.set_enforcing(true);
         let (_kernel, tracee_task) = create_kernel_and_task_with_selinux(security_server);
-        tracee_task.thread_group.write().selinux_state.ptracer_sid =
+        tracee_task.thread_group.write().security_state.0.ptracer_sid =
             Some(SecurityId::initial(InitialSid::Unlabeled));
 
         clear_ptracer_sid(tracee_task.as_ref());
-        assert!(tracee_task.thread_group.read().selinux_state.ptracer_sid.is_none());
+        assert!(tracee_task.thread_group.read().security_state.0.ptracer_sid.is_none());
     }
 
     #[fuchsia::test]
diff --git a/src/starnix/kernel/security/mod.rs b/src/starnix/kernel/security/mod.rs
new file mode 100644
index 0000000..7c106c9
--- /dev/null
+++ b/src/starnix/kernel/security/mod.rs
@@ -0,0 +1,32 @@
+// Copyright 2024 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/// This module provides types and hook APIs supporting Linux Security Modules
+/// functionality in Starnix.  LSM provides a generic set of hooks, and opaque
+/// types, used to decouple the rest of the kernel from the details of any
+/// specific security enforcement subsystem (e.g. SELinux, POSIX.1e, etc).
+///
+/// Although this module is hard-wired to the SELinux implementation, callers
+/// should treat the types as opaque; hook implementations necessarily have access
+/// to kernel structures, but not the other way around.
+use selinux::SecurityId;
+
+/// SELinux implementations called by the LSM hooks.
+mod selinux_hooks;
+
+/// Linux Security Modules hooks for use within the Starnix kernel.
+mod hooks;
+pub use hooks::*;
+
+/// Opaque structure encapsulating security state for a `ThreadGroup`.
+#[derive(Debug)]
+pub struct ThreadGroupState(selinux_hooks::ThreadGroupState);
+
+/// Opaque structure holding security state associated with a `ResolvedElf` instance.
+#[derive(Debug, PartialEq)]
+pub struct ResolvedElfState(SecurityId);
+
+// TODO(b/322850635): Create a clean separation between the procattr filesystem, and LSM hooks.
+// TODO(b/335397745): Move the SELinux filesystem bits under the selinux directory.
+pub mod fs;
diff --git a/src/starnix/kernel/selinux/hooks/thread_group_hooks.rs b/src/starnix/kernel/security/selinux_hooks/mod.rs
similarity index 84%
rename from src/starnix/kernel/selinux/hooks/thread_group_hooks.rs
rename to src/starnix/kernel/security/selinux_hooks/mod.rs
index f65df7c..840bf64 100644
--- a/src/starnix/kernel/selinux/hooks/thread_group_hooks.rs
+++ b/src/starnix/kernel/security/selinux_hooks/mod.rs
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-use crate::task::Kernel;
-
 use selinux::{
     permission_check::PermissionCheck, security_server::SecurityServer, InitialSid, SecurityId,
 };
@@ -17,7 +15,7 @@
 use std::sync::Arc;
 
 /// Checks if creating a task is allowed.
-pub(crate) fn check_task_create_access(
+pub(super) fn check_task_create_access(
     permission_check: &impl PermissionCheck,
     task_sid: SecurityId,
 ) -> Result<(), Errno> {
@@ -29,13 +27,13 @@
 
 /// Checks the SELinux permissions required for exec. Returns the SELinux state of a resolved
 /// elf if all required permissions are allowed.
-pub(crate) fn check_exec_access(
+pub(super) fn check_exec_access(
     security_server: &Arc<SecurityServer>,
-    selinux_state: &SeLinuxThreadGroupState,
+    security_state: &ThreadGroupState,
     executable_sid: SecurityId,
-) -> Result<Option<SeLinuxResolvedElfState>, Errno> {
-    let current_sid = selinux_state.current_sid;
-    let new_sid = if let Some(exec_sid) = selinux_state.exec_sid {
+) -> Result<Option<SecurityId>, Errno> {
+    let current_sid = security_state.current_sid;
+    let new_sid = if let Some(exec_sid) = security_state.exec_sid {
         // Use the proc exec SID if set.
         exec_sid
     } else {
@@ -67,32 +65,32 @@
             log_debug!("entrypoint permission is denied, ignoring.");
         }
         // Check that ptrace permission is allowed if the process is traced.
-        if let Some(ptracer_sid) = selinux_state.ptracer_sid {
+        if let Some(ptracer_sid) = security_state.ptracer_sid {
             if !security_server.has_permission(ptracer_sid, new_sid, ProcessPermission::Ptrace) {
                 return error!(EACCES);
             }
         }
     }
-    Ok(Some(SeLinuxResolvedElfState { sid: new_sid }))
+    Ok(Some(new_sid))
 }
 
 /// Updates the SELinux thread group state on exec, using the security ID associated with the
 /// resolved elf.
-pub(crate) fn update_state_on_exec(
-    selinux_state: &mut SeLinuxThreadGroupState,
-    elf_selinux_state: &Option<SeLinuxResolvedElfState>,
+pub(super) fn update_state_on_exec(
+    security_state: &mut ThreadGroupState,
+    elf_security_state: Option<SecurityId>,
 ) {
     // TODO(http://b/316181721): check if the previous state needs to be updated regardless.
-    if let Some(elf_selinux_state) = elf_selinux_state {
-        selinux_state.previous_sid = selinux_state.current_sid;
-        selinux_state.current_sid = elf_selinux_state.sid;
+    if let Some(elf_security_state) = elf_security_state {
+        security_state.previous_sid = security_state.current_sid;
+        security_state.current_sid = elf_security_state;
     }
 }
 
 /// Checks if source with `source_sid` may exercise the "getsched" permission on target with
 /// `target_sid` according to SELinux server status `status` and permission checker
 /// `permission`.
-pub fn check_getsched_access(
+pub(super) fn check_getsched_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -102,7 +100,7 @@
 
 /// Checks if the task with `source_sid` is allowed to set scheduling parameters for the task with
 /// `target_sid`.
-pub(crate) fn check_setsched_access(
+pub(super) fn check_setsched_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -112,7 +110,7 @@
 
 /// Checks if the task with `source_sid` is allowed to get the process group ID of the task with
 /// `target_sid`.
-pub(crate) fn check_getpgid_access(
+pub(super) fn check_getpgid_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -122,7 +120,7 @@
 
 /// Checks if the task with `source_sid` is allowed to set the process group ID of the task with
 /// `target_sid`.
-pub(crate) fn check_setpgid_access(
+pub(super) fn check_setpgid_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -131,7 +129,7 @@
 }
 
 /// Checks if the task with `source_sid` is allowed to send `signal` to the task with `target_sid`.
-pub(crate) fn check_signal_access(
+pub(super) fn check_signal_access(
     permission_check: &impl PermissionCheck,
     source_sid: SecurityId,
     target_sid: SecurityId,
@@ -157,20 +155,20 @@
 }
 
 /// Checks if the task with `source_sid` is allowed to trace the task with `target_sid`.
-pub(crate) fn check_ptrace_access_and_update_state(
+pub(super) fn check_ptrace_access_and_update_state(
     permission_check: &impl PermissionCheck,
     tracer_sid: SecurityId,
-    tracee_selinux_state: &mut SeLinuxThreadGroupState,
+    tracee_security_state: &mut ThreadGroupState,
 ) -> Result<(), Errno> {
     check_permission(
         permission_check,
         tracer_sid,
-        tracee_selinux_state.current_sid,
+        tracee_security_state.current_sid,
         ProcessPermission::Ptrace,
     )
     .and_then(|_| {
         // If tracing is allowed, set the `ptracer_sid` of the tracee with the tracer's SID.
-        tracee_selinux_state.ptracer_sid = Some(tracer_sid);
+        tracee_security_state.ptracer_sid = Some(tracer_sid);
         Ok(())
     })
 }
@@ -188,23 +186,17 @@
     }
 }
 
-/// Returns an `SeLinuxThreadGroupState` instance for a new task.
-pub fn alloc_security(
-    kernel: &Kernel,
-    parent: Option<&SeLinuxThreadGroupState>,
-) -> SeLinuxThreadGroupState {
-    if kernel.security_server.is_none() {
-        return SeLinuxThreadGroupState::for_selinux_disabled();
-    };
+/// Returns a `ThreadGroupState` instance for a new task.
+pub(super) fn alloc_security(parent: Option<&ThreadGroupState>) -> ThreadGroupState {
     match parent {
         Some(parent) => parent.clone(),
-        None => SeLinuxThreadGroupState::for_kernel(),
+        None => ThreadGroupState::for_kernel(),
     }
 }
 
 /// The SELinux security structure for `ThreadGroup`.
 #[derive(Clone, Debug, PartialEq)]
-pub struct SeLinuxThreadGroupState {
+pub(super) struct ThreadGroupState {
     /// Current SID for the task.
     pub current_sid: SecurityId,
 
@@ -227,9 +219,9 @@
     pub ptracer_sid: Option<SecurityId>,
 }
 
-impl SeLinuxThreadGroupState {
+impl ThreadGroupState {
     /// Returns initial state for the kernel's root thread group.
-    pub(crate) fn for_kernel() -> Self {
+    pub(super) fn for_kernel() -> Self {
         Self {
             current_sid: SecurityId::initial(InitialSid::Kernel),
             previous_sid: SecurityId::initial(InitialSid::Kernel),
@@ -242,7 +234,7 @@
     }
 
     /// Returns placeholder state for use when SELinux is not enabled.
-    fn for_selinux_disabled() -> Self {
+    pub(super) fn for_selinux_disabled() -> Self {
         Self {
             current_sid: SecurityId::initial(InitialSid::Unlabeled),
             previous_sid: SecurityId::initial(InitialSid::Unlabeled),
@@ -255,17 +247,9 @@
     }
 }
 
-/// The SELinux security structure for `ResolvedElf`.
-#[derive(Clone, Eq, PartialEq, Debug)]
-pub struct SeLinuxResolvedElfState {
-    /// Security ID for the transformed process.
-    pub sid: SecurityId,
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::testing::{create_kernel_and_task, create_kernel_and_task_with_selinux};
     use selinux::security_server::Mode;
     use starnix_uapi::signals::SIGTERM;
 
@@ -315,7 +299,7 @@
         let executable_sid = security_server
             .security_context_to_sid(b"u:object_r:executable_file_trans_t:s0")
             .expect("invalid security context");
-        let selinux_state = SeLinuxThreadGroupState {
+        let security_state = ThreadGroupState {
             current_sid: current_sid,
             exec_sid: Some(exec_sid),
             fscreate_sid: None,
@@ -326,8 +310,8 @@
         };
 
         assert_eq!(
-            check_exec_access(&security_server, &selinux_state, executable_sid),
-            Ok(Some(SeLinuxResolvedElfState { sid: exec_sid }))
+            check_exec_access(&security_server, &security_state, executable_sid),
+            Ok(Some(exec_sid))
         );
     }
 
@@ -343,7 +327,7 @@
         let executable_sid = security_server
             .security_context_to_sid(b"u:object_r:executable_file_trans_t:s0")
             .expect("invalid security context");
-        let selinux_state = SeLinuxThreadGroupState {
+        let security_state = ThreadGroupState {
             current_sid: current_sid,
             exec_sid: Some(exec_sid),
             fscreate_sid: None,
@@ -354,7 +338,7 @@
         };
 
         assert_eq!(
-            check_exec_access(&security_server, &selinux_state, executable_sid),
+            check_exec_access(&security_server, &security_state, executable_sid),
             error!(EACCES)
         );
     }
@@ -373,7 +357,7 @@
         let executable_sid = security_server
             .security_context_to_sid(b"u:object_r:executable_file_trans_no_entrypoint_t:s0")
             .expect("invalid security context");
-        let selinux_state = SeLinuxThreadGroupState {
+        let security_state = ThreadGroupState {
             current_sid: current_sid,
             exec_sid: Some(exec_sid),
             fscreate_sid: None,
@@ -384,7 +368,7 @@
         };
 
         assert_eq!(
-            check_exec_access(&security_server, &selinux_state, executable_sid),
+            check_exec_access(&security_server, &security_state, executable_sid),
             error!(EACCES)
         );
     }
@@ -399,7 +383,7 @@
         let executable_sid = security_server
             .security_context_to_sid(b"u:object_r:executable_file_no_trans_t:s0")
             .expect("invalid security context");
-        let selinux_state = SeLinuxThreadGroupState {
+        let security_state = ThreadGroupState {
             current_sid: current_sid,
             exec_sid: None,
             fscreate_sid: None,
@@ -410,8 +394,8 @@
         };
 
         assert_eq!(
-            check_exec_access(&security_server, &selinux_state, executable_sid),
-            Ok(Some(SeLinuxResolvedElfState { sid: current_sid }))
+            check_exec_access(&security_server, &security_state, executable_sid),
+            Ok(Some(current_sid))
         );
     }
 
@@ -426,7 +410,7 @@
         let executable_sid = security_server
             .security_context_to_sid(b"u:object_r:executable_file_no_trans_t:s0")
             .expect("invalid security context");
-        let selinux_state = SeLinuxThreadGroupState {
+        let security_state = ThreadGroupState {
             current_sid: current_sid,
             exec_sid: None,
             fscreate_sid: None,
@@ -439,34 +423,33 @@
         // There is no `execute_no_trans` allow statement from `current_sid` to `executable_sid`,
         // expect access denied.
         assert_eq!(
-            check_exec_access(&security_server, &selinux_state, executable_sid),
+            check_exec_access(&security_server, &security_state, executable_sid),
             error!(EACCES)
         );
     }
 
     #[fuchsia::test]
     fn no_state_update_if_no_elf_state() {
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
-        let mut selinux_state = initial_state.clone();
-        update_state_on_exec(&mut selinux_state, &None);
-        assert_eq!(selinux_state, initial_state);
+        let initial_state = ThreadGroupState::for_kernel();
+        let mut security_state = initial_state.clone();
+        update_state_on_exec(&mut security_state, None);
+        assert_eq!(security_state, initial_state);
     }
 
     #[fuchsia::test]
     fn state_is_updated_on_exec() {
         let security_server = security_server_with_policy();
-        let initial_state = SeLinuxThreadGroupState::for_kernel();
-        let mut selinux_state = initial_state.clone();
+        let initial_state = ThreadGroupState::for_kernel();
+        let mut security_state = initial_state.clone();
 
         let elf_sid = security_server
             .security_context_to_sid(b"u:object_r:test_valid_t:s0")
             .expect("invalid security context");
-        let elf_state = SeLinuxResolvedElfState { sid: elf_sid };
         assert_ne!(elf_sid, initial_state.current_sid);
-        update_state_on_exec(&mut selinux_state, &Some(elf_state));
+        update_state_on_exec(&mut security_state, Some(elf_sid));
         assert_eq!(
-            selinux_state,
-            SeLinuxThreadGroupState {
+            security_state,
+            ThreadGroupState {
                 current_sid: elf_sid,
                 exec_sid: initial_state.exec_sid,
                 fscreate_sid: initial_state.fscreate_sid,
@@ -692,7 +675,7 @@
         let tracee_sid = security_server
             .security_context_to_sid(b"u:object_r:test_ptrace_traced_t:s0")
             .expect("invalid security context");
-        let initial_state = SeLinuxThreadGroupState {
+        let initial_state = ThreadGroupState {
             current_sid: tracee_sid.clone(),
             exec_sid: None,
             fscreate_sid: None,
@@ -713,7 +696,7 @@
         );
         assert_eq!(
             tracee_state,
-            SeLinuxThreadGroupState {
+            ThreadGroupState {
                 current_sid: initial_state.current_sid,
                 exec_sid: initial_state.exec_sid,
                 fscreate_sid: initial_state.fscreate_sid,
@@ -734,7 +717,7 @@
         let tracee_sid = security_server
             .security_context_to_sid(b"u:object_r:test_ptrace_traced_t:s0")
             .expect("invalid security context");
-        let initial_state = SeLinuxThreadGroupState {
+        let initial_state = ThreadGroupState {
             current_sid: tracee_sid.clone(),
             exec_sid: None,
             fscreate_sid: None,
@@ -757,20 +740,11 @@
     }
 
     #[fuchsia::test]
-    async fn alloc_security_selinux_disabled() {
-        let (kernel, _current_task) = create_kernel_and_task();
-
-        alloc_security(&kernel, None);
-    }
-
-    #[fuchsia::test]
     async fn alloc_security_no_parent() {
-        let security_server = SecurityServer::new(Mode::Fake);
-        let (kernel, _current_task) = create_kernel_and_task_with_selinux(security_server);
-        let selinux_state = alloc_security(&kernel, None);
+        let security_state = alloc_security(None);
         assert_eq!(
-            selinux_state,
-            SeLinuxThreadGroupState {
+            security_state,
+            ThreadGroupState {
                 current_sid: SecurityId::initial(InitialSid::Kernel),
                 previous_sid: SecurityId::initial(InitialSid::Kernel),
                 exec_sid: None,
@@ -784,18 +758,15 @@
 
     #[fuchsia::test]
     async fn alloc_security_from_parent() {
-        let security_server = SecurityServer::new(Mode::Fake);
-        let (kernel, _current_task) = create_kernel_and_task_with_selinux(security_server);
-
         // Create a fake parent state, with values for some fields, to check for.
-        let mut parent_selinux_state = alloc_security(&kernel, None);
-        parent_selinux_state.current_sid = SecurityId::initial(InitialSid::Unlabeled);
-        parent_selinux_state.exec_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
-        parent_selinux_state.fscreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
-        parent_selinux_state.keycreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
-        parent_selinux_state.sockcreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
+        let mut parent_security_state = alloc_security(None);
+        parent_security_state.current_sid = SecurityId::initial(InitialSid::Unlabeled);
+        parent_security_state.exec_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
+        parent_security_state.fscreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
+        parent_security_state.keycreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
+        parent_security_state.sockcreate_sid = Some(SecurityId::initial(InitialSid::Unlabeled));
 
-        let selinux_state = alloc_security(&kernel, Some(&parent_selinux_state));
-        assert_eq!(selinux_state, parent_selinux_state);
+        let security_state = alloc_security(Some(&parent_security_state));
+        assert_eq!(security_state, parent_security_state);
     }
 }
diff --git a/src/starnix/kernel/selinux/hooks/mod.rs b/src/starnix/kernel/selinux/hooks/mod.rs
deleted file mode 100644
index e8cfdfe..0000000
--- a/src/starnix/kernel/selinux/hooks/mod.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright 2024 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// The hooks modules implement SELinux hooks to control and enforce access decisions, and define
-// SELinux security structs associated to objects in the system, holding state information used
-// by hooks to make access decisions.
-
-pub mod current_task_hooks;
-pub mod thread_group_hooks;
diff --git a/src/starnix/kernel/selinux/mod.rs b/src/starnix/kernel/selinux/mod.rs
deleted file mode 100644
index d71555f..0000000
--- a/src/starnix/kernel/selinux/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright 2023 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-pub mod fs;
-pub mod hooks;
diff --git a/src/starnix/kernel/signals/syscalls.rs b/src/starnix/kernel/signals/syscalls.rs
index 8f15f46..b9a8fa6 100644
--- a/src/starnix/kernel/signals/syscalls.rs
+++ b/src/starnix/kernel/signals/syscalls.rs
@@ -6,7 +6,7 @@
 use super::signalfd::SignalFd;
 use crate::{
     mm::{MemoryAccessor, MemoryAccessorExt},
-    selinux::hooks::current_task_hooks as selinux_hooks,
+    security,
     signals::{
         restore_from_signal_handler, send_signal, SignalDetail, SignalInfo, SignalInfoHeader,
         SI_HEADER_SIZE,
@@ -338,7 +338,7 @@
     }
 
     let signal = Signal::try_from(unchecked_signal)?;
-    selinux_hooks::check_signal_access(current_task, &target, signal)?;
+    security::check_signal_access(current_task, &target, signal)?;
 
     send_signal(
         target,
@@ -371,7 +371,7 @@
     }
 
     let signal = Signal::try_from(unchecked_signal)?;
-    selinux_hooks::check_signal_access(current_task, &target, signal)?;
+    security::check_signal_access(current_task, &target, signal)?;
 
     let siginfo = read_siginfo(current_task, signal, siginfo_ref)?;
     if target.get_pid() != current_task.get_pid() && (siginfo.code >= 0 || siginfo.code == SI_TKILL)
diff --git a/src/starnix/kernel/task/current_task.rs b/src/starnix/kernel/task/current_task.rs
index 3bd6eda..33ffe3a 100644
--- a/src/starnix/kernel/task/current_task.rs
+++ b/src/starnix/kernel/task/current_task.rs
@@ -11,7 +11,7 @@
     fs::proc::pid_directory::TaskDirectory,
     loader::{load_executable, resolve_executable, ResolvedElf},
     mm::{MemoryAccessor, MemoryAccessorExt, MemoryManager, TaskMemoryAccessor},
-    selinux::hooks::current_task_hooks as selinux_hooks,
+    security,
     signals::{send_signal_first, send_standard_signal, RunState, SignalActions, SignalInfo},
     task::{
         ExitStatus, Kernel, PidTable, ProcessGroup, PtraceCoreState, PtraceEvent, PtraceEventData,
@@ -831,7 +831,7 @@
         // used in the `open` call.
         executable.name.check_access(self, Access::EXEC)?;
 
-        let elf_selinux_state = selinux_hooks::check_exec_access(self, executable.node())?;
+        let elf_security_state = security::check_exec_access(self, executable.node())?;
 
         let resolved_elf = resolve_executable(
             locked,
@@ -840,7 +840,7 @@
             path.clone(),
             argv,
             environ,
-            elf_selinux_state,
+            elf_security_state,
         )?;
 
         if self.thread_group.read().tasks_count() > 1 {
@@ -878,7 +878,7 @@
             .map_err(|status| from_status_like_fdio!(status))?;
 
         // Update the SELinux state, if enabled.
-        selinux_hooks::update_state_on_exec(self, &resolved_elf.selinux_state);
+        security::update_state_on_exec(self, &resolved_elf.security_state);
 
         let start_info = load_executable(self, resolved_elf, &path)?;
         let regs: zx_thread_state_general_regs_t = start_info.into();
diff --git a/src/starnix/kernel/task/ptrace.rs b/src/starnix/kernel/task/ptrace.rs
index 3a19af7..4268557 100644
--- a/src/starnix/kernel/task/ptrace.rs
+++ b/src/starnix/kernel/task/ptrace.rs
@@ -5,7 +5,7 @@
 use crate::{
     arch::execution::new_syscall_from_state,
     mm::{DumpPolicy, MemoryAccessor, MemoryAccessorExt},
-    selinux::hooks::current_task_hooks as selinux_hooks,
+    security,
     signals::{
         send_signal_first, send_standard_signal, syscalls::WaitingOptions, SignalDetail,
         SignalInfo, SignalInfoHeader, SI_HEADER_SIZE,
@@ -703,7 +703,7 @@
     if let Err(x) = ptrace_cont(&tracee, &data, true) {
         return Err(x);
     }
-    selinux_hooks::clear_ptracer_sid(tracee);
+    security::clear_ptracer_sid(tracee);
     let tid = tracee.get_tid();
     thread_group.ptracees.lock().remove(&tid);
     thread_group.write().zombie_ptracees.retain(&mut |zombie: &ZombieProcess| zombie.pid != tid);
@@ -1038,7 +1038,7 @@
 
     let parent = current_task.thread_group.read().parent.clone();
     if let Some(parent) = parent {
-        selinux_hooks::check_ptrace_traceme_access_and_update_state(&parent, current_task)?;
+        security::check_ptrace_traceme_access_and_update_state(&parent, current_task)?;
         let task_ref = OwnedRef::temp(&current_task.task);
         do_attach(&parent, (&task_ref).into(), PtraceAttachType::Attach, PtraceOptions::empty())?;
         Ok(starnix_syscalls::SUCCESS)
@@ -1062,7 +1062,7 @@
 
     let weak_task = current_task.kernel().pids.read().get_task(pid);
     let tracee = weak_task.upgrade().ok_or_else(|| errno!(ESRCH))?;
-    selinux_hooks::check_ptrace_attach_access_and_update_state(&current_task, &tracee)?;
+    security::check_ptrace_attach_access_and_update_state(&current_task, &tracee)?;
 
     if tracee.thread_group == current_task.thread_group {
         return error!(EPERM);
diff --git a/src/starnix/kernel/task/syscalls.rs b/src/starnix/kernel/task/syscalls.rs
index 7148b4c..59f5dfd 100644
--- a/src/starnix/kernel/task/syscalls.rs
+++ b/src/starnix/kernel/task/syscalls.rs
@@ -12,7 +12,7 @@
 use crate::{
     execution::execute_task,
     mm::{DumpPolicy, MemoryAccessor, MemoryAccessorExt, PAGE_SIZE},
-    selinux::hooks::current_task_hooks as selinux_hooks,
+    security,
     task::{
         max_priority_for_sched_policy, min_priority_for_sched_policy, ptrace_attach,
         ptrace_dispatch, ptrace_traceme, CurrentTask, ExitStatus, PtraceAllowedPtracers,
@@ -73,7 +73,7 @@
     L: LockBefore<MmDumpable>,
     L: LockBefore<TaskRelease>,
 {
-    selinux_hooks::check_task_create_access(current_task)?;
+    security::check_task_create_access(current_task)?;
 
     let child_exit_signal = if args.exit_signal == 0 {
         None
@@ -394,7 +394,7 @@
     let weak = get_task_or_current(current_task, pid);
     let task = Task::from_weak(&weak)?;
 
-    selinux_hooks::check_getpgid_access(current_task, &task)?;
+    security::check_getpgid_access(current_task, &task)?;
     let pgid = task.thread_group.read().process_group.leader;
     Ok(pgid)
 }
@@ -408,7 +408,7 @@
     let weak = get_task_or_current(current_task, pid);
     let task = Task::from_weak(&weak)?;
 
-    selinux_hooks::check_setpgid_access(current_task, &task)?;
+    security::check_setpgid_access(current_task, &task)?;
     current_task.thread_group.setpgid(locked, &task, pgid)?;
     Ok(())
 }
@@ -734,7 +734,7 @@
 
     let weak = get_task_or_current(current_task, pid);
     let target_task = Task::from_weak(&weak)?;
-    selinux_hooks::check_getsched_access(current_task, target_task.as_ref())?;
+    security::check_getsched_access(current_task, target_task.as_ref())?;
     let current_policy = target_task.read().scheduler_policy;
     Ok(current_policy.raw_policy())
 }
@@ -754,7 +754,7 @@
     let target_task = Task::from_weak(&weak)?;
     let rlimit = target_task.thread_group.get_rlimit(Resource::RTPRIO);
 
-    selinux_hooks::check_setsched_access(current_task, &target_task)?;
+    security::check_setsched_access(current_task, &target_task)?;
     let param: sched_param = current_task.read_object(param.into())?;
     let policy = SchedulerPolicy::from_sched_params(policy, param, rlimit)?;
     target_task.set_scheduler_policy(policy)?;
diff --git a/src/starnix/kernel/task/task.rs b/src/starnix/kernel/task/task.rs
index 915a7cc..ebe5a5d 100644
--- a/src/starnix/kernel/task/task.rs
+++ b/src/starnix/kernel/task/task.rs
@@ -21,7 +21,6 @@
 };
 use macro_rules_attribute::apply;
 use once_cell::sync::OnceCell;
-use selinux::SecurityId;
 use starnix_logging::{log_debug, log_warn, set_zx_name};
 use starnix_sync::{LockBefore, Locked, MmDumpable, Mutex, RwLock, TaskRelease};
 use starnix_uapi::{
@@ -1265,11 +1264,6 @@
         logging_span.clone()
     }
 
-    /// Get the SELinux security ID of the current task, or `None` if not set.
-    pub fn get_current_sid(&self) -> SecurityId {
-        self.thread_group.read().selinux_state.current_sid
-    }
-
     fn update_logging_span(&self, debug_info: &starnix_logging::TaskDebugInfo) {
         let logging_span =
             self.logging_span.get_or_init(|| starnix_logging::Span::new(&debug_info));
diff --git a/src/starnix/kernel/task/thread_group.rs b/src/starnix/kernel/task/thread_group.rs
index 3a0a618..71dc4bd 100644
--- a/src/starnix/kernel/task/thread_group.rs
+++ b/src/starnix/kernel/task/thread_group.rs
@@ -5,7 +5,7 @@
 use crate::{
     device::terminal::{ControllingSession, Terminal},
     mutable_state::{state_accessor, state_implementation},
-    selinux::hooks::thread_group_hooks,
+    security,
     signals::{
         send_signal, send_standard_signal, syscalls::WaitingOptions, SignalActions, SignalDetail,
         SignalInfo,
@@ -22,7 +22,6 @@
 use fuchsia_zircon as zx;
 use itertools::Itertools;
 use macro_rules_attribute::apply;
-use selinux::SecurityId;
 use starnix_lifecycle::{AtomicU64Counter, DropNotifier};
 use starnix_logging::{log_error, log_warn, track_stub};
 use starnix_sync::{LockBefore, Locked, Mutex, MutexGuard, ProcessGroupState, RwLock};
@@ -112,8 +111,8 @@
 
     pub terminating: bool,
 
-    /// The SELinux operations for this thread group.
-    pub selinux_state: thread_group_hooks::SeLinuxThreadGroupState,
+    /// The Linux Security Modules state for this thread group.
+    pub security_state: security::ThreadGroupState,
 
     /// Time statistics accumulated from the children.
     pub children_time_stats: TaskTimeStats,
@@ -376,8 +375,8 @@
     {
         let timers = TimerTable::new();
         let itimer_real_id = timers.create(CLOCK_REALTIME as ClockId, None).unwrap();
-        let selinux_state =
-            thread_group_hooks::alloc_security(&kernel, parent.as_ref().map(|p| &p.selinux_state));
+        let security_state =
+            security::alloc_security(&kernel, parent.as_ref().map(|p| &p.security_state));
         let mut thread_group = ThreadGroup {
             kernel,
             process,
@@ -409,7 +408,7 @@
                 last_signal: None,
                 leader_exit_info: None,
                 terminating: false,
-                selinux_state,
+                security_state,
                 children_time_stats: Default::default(),
                 personality: parent.as_ref().map(|p| p.personality).unwrap_or(Default::default()),
                 allowed_ptracers: PtraceAllowedPtracers::None,
@@ -1294,15 +1293,6 @@
         }
         None
     }
-
-    /// Get the SELinux security ID of the thread group.
-    /// Returns a placeholder value if SELinux is not enabled.
-    pub fn get_current_sid(&self) -> SecurityId {
-        // TODO(http://b/316181721): to avoid TOCTOU issues, once initial security contexts are
-        // propagated to tasks in the system, in some cases using this API will need to be replaced
-        // with call sites holding the state lock while making updates.
-        self.mutable_state.read().selinux_state.current_sid
-    }
 }
 
 #[apply(state_implementation!)]
diff --git a/src/starnix/kernel/vfs/fs_node.rs b/src/starnix/kernel/vfs/fs_node.rs
index acd2c4b..16a6093 100644
--- a/src/starnix/kernel/vfs/fs_node.rs
+++ b/src/starnix/kernel/vfs/fs_node.rs
@@ -5,7 +5,7 @@
 use crate::{
     device::DeviceMode,
     mm::PAGE_SIZE,
-    selinux::hooks::current_task_hooks::{get_fs_node_security_id, post_setxattr},
+    security::{get_fs_node_security_id, post_setxattr},
     signals::{send_standard_signal, SignalInfo},
     task::{CurrentTask, Kernel, WaitQueue, Waiter},
     time::utc,
diff --git a/src/starnix/kernel/vfs/namespace.rs b/src/starnix/kernel/vfs/namespace.rs
index a95c3ac..069148f 100644
--- a/src/starnix/kernel/vfs/namespace.rs
+++ b/src/starnix/kernel/vfs/namespace.rs
@@ -10,7 +10,7 @@
         overlayfs::OverlayFs, proc::proc_fs, sysfs::sys_fs, tmpfs::TmpFs, tracefs::trace_fs,
     },
     mutable_state::{state_accessor, state_implementation},
-    selinux::fs::selinux_fs,
+    security::fs::selinux_fs,
     task::{CurrentTask, EventHandler, Kernel, Task, WaitCanceler, Waiter},
     time::utc,
     vfs::{