> +/* > + * With writable hooks, we setup a structure like this: > + * +------+ +-----------+ +-----------+ +-----------+ > +--------------+ > + * | | | | | | | | | > | > + * | HEAD +---> Immutable +---> Immutable +---> Null hook +---> Mutable Hook > | > + * | | | Hook 1 | | Hook 2 | | | | > | > + * +------+ +-----------+ +-----------+ +-----------+ > +--------------+ > + * | | | > + * v v v > + * Callback Callback Callback > + * > + * The hooks before to null hook are marked only after kernel initialization. > + * The null hook, as well as the hooks succeeding it are not marked read > only, > + * therefore allowing them be (un)loaded after initialization time. > + * > + * Since the null hook doesn't have a callback, we need to check if a hook > + * is the null hook prior to invoking it. > + */
Do we need to use null hook as hook == NULL? Why not overwrite null hook's hook field? #define call_void_hook(FUNC, ...) \ do { \ struct security_hook_list *P; \ int srcu_idx = lock_lsm(); \ for (P = &security_hook_heads.FUNC; P->hook.FUNC; P = P->next) \ P->hook.FUNC(__VA_ARGS__); \ unlock_lsm(srcu_idx); } while (0) "struct hlist_head security_hook_heads[SECURITY_HOOK_COUNT]" is marked as __ro_after_init. Built-in LSM module's "struct security_hook_list[]" is also marked as __ro_after_init. Dynamic LSM module's "struct security_hook_list[]" is not marked as __initdata. Hook registration function appends to tail of security_hook_heads.FUNC. But, before __ro_after_init is applied, initial "struct security_hook_list dynamic_hook_list[SECURITY_HOOK_COUNT]" is appended to tail of security_hook_heads. That is, only "struct security_hook_list" at initial dynamic_hook_list[] and later are writable. Dynamic hook registration function overwrites current dynamic_hook_list[] with supplied dynamic module's "struct security_hook_list[]". Then, dynamic hook registration function allocates memory for next dynamic_hook_list[] and appends to tail of security_hook_heads.FUNC (note that the tail element is writable because it is guaranteed to be initial dynamic_hook_list[] or later. Before registering first built-in immutable LSM module. r/w * +------+ * | | * | HEAD + * | | * +------+ * * * Before registering second built-in immutable LSM module. r/w r/w * +------+ +-----------+ * | | | | * | HEAD +---> Immutable + * | | | Hook 1 | * +------+ +-----------+ * | * v * Callback Before registering initial dynamic_hook_list[]. r/w r/w r/w * +------+ +-----------+ +-----------+ * | | | | | | * | HEAD +---> Immutable +---> Immutable + * | | | Hook 1 | | Hook 2 | * +------+ +-----------+ +-----------+ * | | * v v * Callback Callback After registering initial dynamic_hook_list[] and applying __ro_after_init. r/o r/o r/o r/w * +------+ +-----------+ +-----------+ +----------------+ * | | | | | | | | * | HEAD +---> Immutable +---> Immutable +---> Hook for first + * | | | Hook 1 | | Hook 2 | | Mutable Module | * +------+ +-----------+ +-----------+ +----------------+ * | | * v v * Callback Callback After registering first mutable LSM module. r/o r/o r/o r/w r/w * +------+ +-----------+ +-----------+ +-----------+ +-----------------+ * | | | | | | | | | | * | HEAD +---> Immutable +---> Immutable +---> Mutable +---> Hook for second + * | | | Hook 1 | | Hook 2 | | Hook 1 | | Mutable Module | * +------+ +-----------+ +-----------+ +-----------+ +-----------------+ * | | | * v v v * Callback Callback Callback After registering second mutable LSM module. r/o r/o r/o r/w r/w r/w * +------+ +-----------+ +-----------+ +-----------+ +-----------+ +-----------------+ * | | | | | | | | | | | | * | HEAD +---> Immutable +---> Immutable +---> Mutable +---> Mutable +---> Hook for third + * | | | Hook 1 | | Hook 2 | | Hook 1 | | Hook 2 | | Mutable Module | * +------+ +-----------+ +-----------+ +-----------+ +-----------+ +-----------------+ * | | | * v v v * Callback Callback Callback After protectable memory is accepted, all r/w above except the last one will be marked as r/o by allocating "Hook for X'th Mutable Module" using that allocator.