Re: [PATCH v3 1/1] security: Add mechanism to safely (un)load LSMs after boot time

From: Tetsuo Handa
Date: Sun Apr 01 2018 - 06:38:25 EST


> +/*
> + * 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.