One part of a larger effort to cleanup the LSM framework initialization code.
Signed-off-by: Paul Moore <p...@paul-moore.com> --- security/lsm_init.c | 211 ++++++++++++++++++++++---------------------- 1 file changed, 106 insertions(+), 105 deletions(-) diff --git a/security/lsm_init.c b/security/lsm_init.c index 163fc2a1a952..e07fd4d2a16a 100644 --- a/security/lsm_init.c +++ b/security/lsm_init.c @@ -36,6 +36,9 @@ static __initdata bool debug; #define lsm_order_for_each(iter) \ for ((iter) = lsm_order; *(iter); (iter)++) +#define lsm_for_each_raw(iter) \ + for ((iter) = __start_lsm_info; \ + (iter) < __end_lsm_info; (iter)++) #define lsm_early_for_each_raw(iter) \ for ((iter) = __start_early_lsm_info; \ (iter) < __end_early_lsm_info; (iter)++) @@ -127,6 +130,10 @@ static bool __init lsm_order_exists(struct lsm_info *lsm) * lsm_order_append - Append a LSM to the ordered list * @lsm: LSM definition * @src: source of the addition + * + * Append @lsm to the enabled LSM array after ensuring that it hasn't been + * explicitly disabled, is a duplicate entry, or would run afoul of the + * LSM_FLAG_EXCLUSIVE logic. */ static void __init lsm_order_append(struct lsm_info *lsm, const char *src) { @@ -135,19 +142,106 @@ static void __init lsm_order_append(struct lsm_info *lsm, const char *src) return; /* Skip explicitly disabled LSMs. */ - if (lsm->enabled && !lsm_is_enabled(lsm)) { - if (WARN(lsm_count == MAX_LSM_COUNT, - "%s: out of LSM static calls!?\n", src)) - return; - lsm_enabled_set(lsm, true); - lsm_order[lsm_count] = lsm; - lsm_idlist[lsm_count++] = lsm->id; + if (lsm->enabled && !lsm_is_enabled(lsm)) + goto out; + + if (WARN(lsm_count == MAX_LSM_COUNT, + "%s: out of LSM static calls!?\n", src)) { + lsm_enabled_set(lsm, false); + goto out; } + if (lsm->flags & LSM_FLAG_EXCLUSIVE) { + if (lsm_exclusive) { + init_debug("exclusive disabled: %s\n", lsm->id->name); + lsm_enabled_set(lsm, false); + goto out; + } else { + init_debug("exclusive chosen: %s\n", lsm->id->name); + lsm_exclusive = lsm; + } + } + + lsm_enabled_set(lsm, true); + lsm_order[lsm_count] = lsm; + lsm_idlist[lsm_count++] = lsm->id; + +out: init_debug("%s ordered: %s (%s)\n", src, lsm->id->name, lsm_is_enabled(lsm) ? "enabled" : "disabled"); } +/** + * lsm_order_parse - Parse the comma delimited LSM list + * @list: LSM list + * @src: source of the list + */ +static void __init lsm_order_parse(const char *list, const char *src) +{ + struct lsm_info *lsm; + char *sep, *name, *next; + + /* Handle any Legacy LSM exclusions if one was specified. */ + if (lsm_order_legacy) { + /* + * To match the original "security=" behavior, this explicitly + * does NOT fallback to another Legacy Major if the selected + * one was separately disabled: disable all non-matching + * Legacy Major LSMs. + */ + lsm_for_each_raw(lsm) { + if ((lsm->flags & LSM_FLAG_LEGACY_MAJOR) && + strcmp(lsm->id->name, lsm_order_legacy)) { + lsm_enabled_set(lsm, false); + init_debug("security=%s disabled: %s (only one legacy major LSM)\n", + lsm_order_legacy, lsm->id->name); + } + } + } + + /* LSM_ORDER_FIRST */ + lsm_for_each_raw(lsm) { + if (lsm->order == LSM_ORDER_FIRST) + lsm_order_append(lsm, "first"); + } + + /* Normal or "mutable" LSMs */ + sep = kstrdup(list, GFP_KERNEL); + next = sep; + /* Walk the list, looking for matching LSMs. */ + while ((name = strsep(&next, ",")) != NULL) { + lsm_for_each_raw(lsm) { + if (!strcmp(lsm->id->name, name) && + lsm->order == LSM_ORDER_MUTABLE) + lsm_order_append(lsm, src); + } + } + kfree(sep); + + /* Legacy LSM if specified. */ + if (lsm_order_legacy) { + lsm_for_each_raw(lsm) { + if (!strcmp(lsm->id->name, lsm_order_legacy)) + lsm_order_append(lsm, src); + } + } + + /* LSM_ORDER_LAST */ + lsm_for_each_raw(lsm) { + if (lsm->order == LSM_ORDER_LAST) + lsm_order_append(lsm, "last"); + } + + /* Disable all LSMs not previously enabled. */ + lsm_for_each_raw(lsm) { + if (lsm_order_exists(lsm)) + continue; + lsm_enabled_set(lsm, false); + init_debug("%s skipped: %s (not in requested order)\n", + src, lsm->id->name); + } +} + /** * lsm_blob_size_update - Update the LSM blob size and offset information * @sz_req: the requested additional blob size @@ -172,26 +266,12 @@ static void __init lsm_blob_size_update(unsigned int *sz_req, */ static void __init lsm_prep_single(struct lsm_info *lsm) { - struct lsm_blob_sizes *blobs; + struct lsm_blob_sizes *blobs = lsm->blobs; - if (!lsm_is_enabled(lsm)) { - lsm_enabled_set(lsm, false); + if (!blobs) return; - } else if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && lsm_exclusive) { - init_debug("exclusive disabled: %s\n", lsm->id->name); - lsm_enabled_set(lsm, false); - return; - } - - /* Mark the LSM as enabled. */ - lsm_enabled_set(lsm, true); - if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !lsm_exclusive) { - init_debug("exclusive chosen: %s\n", lsm->id->name); - lsm_exclusive = lsm; - } /* Register the LSM blob sizes. */ - blobs = lsm->blobs; lsm_blob_size_update(&blobs->lbs_cred, &blob_sizes.lbs_cred); lsm_blob_size_update(&blobs->lbs_file, &blob_sizes.lbs_file); lsm_blob_size_update(&blobs->lbs_ib, &blob_sizes.lbs_ib); @@ -230,86 +310,6 @@ static void __init lsm_init_single(struct lsm_info *lsm) WARN(ret, "%s failed to initialize: %d\n", lsm->id->name, ret); } -/* Populate ordered LSMs list from comma-separated LSM name list. */ -static void __init ordered_lsm_parse(const char *order, const char *origin) -{ - struct lsm_info *lsm; - char *sep, *name, *next; - - /* LSM_ORDER_FIRST is always first. */ - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { - if (lsm->order == LSM_ORDER_FIRST) - lsm_order_append(lsm, " first"); - } - - /* Process "security=", if given. */ - if (lsm_order_legacy) { - struct lsm_info *major; - - /* - * To match the original "security=" behavior, this - * explicitly does NOT fallback to another Legacy Major - * if the selected one was separately disabled: disable - * all non-matching Legacy Major LSMs. - */ - for (major = __start_lsm_info; major < __end_lsm_info; - major++) { - if ((major->flags & LSM_FLAG_LEGACY_MAJOR) && - strcmp(major->id->name, lsm_order_legacy) != 0) { - lsm_enabled_set(major, false); - init_debug("security=%s disabled: %s (only one legacy major LSM)\n", - lsm_order_legacy, major->id->name); - } - } - } - - sep = kstrdup(order, GFP_KERNEL); - next = sep; - /* Walk the list, looking for matching LSMs. */ - while ((name = strsep(&next, ",")) != NULL) { - bool found = false; - - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { - if (strcmp(lsm->id->name, name) == 0) { - if (lsm->order == LSM_ORDER_MUTABLE) - lsm_order_append(lsm, origin); - found = true; - } - } - - if (!found) - init_debug("%s ignored: %s (not built into kernel)\n", - origin, name); - } - - /* Process "security=", if given. */ - if (lsm_order_legacy) { - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { - if (lsm_order_exists(lsm)) - continue; - if (strcmp(lsm->id->name, lsm_order_legacy) == 0) - lsm_order_append(lsm, "security="); - } - } - - /* LSM_ORDER_LAST is always last. */ - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { - if (lsm->order == LSM_ORDER_LAST) - lsm_order_append(lsm, " last"); - } - - /* Disable all LSMs not in the ordered list. */ - for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { - if (lsm_order_exists(lsm)) - continue; - lsm_enabled_set(lsm, false); - init_debug("%s skipped: %s (not in requested order)\n", - origin, lsm->id->name); - } - - kfree(sep); -} - /** * lsm_init_ordered - Initialize the ordered LSMs */ @@ -324,9 +324,9 @@ static void __init lsm_init_ordered(void) lsm_order_legacy, lsm_order_cmdline); lsm_order_legacy = NULL; } - ordered_lsm_parse(lsm_order_cmdline, "cmdline"); + lsm_order_parse(lsm_order_cmdline, "cmdline"); } else - ordered_lsm_parse(lsm_order_builtin, "builtin"); + lsm_order_parse(lsm_order_builtin, "builtin"); lsm_order_for_each(lsm) { lsm_prep_single(*lsm); @@ -426,6 +426,7 @@ int __init early_security_init(void) lsm_early_for_each_raw(lsm) { lsm_enabled_set(lsm, true); + lsm_order_append(lsm, "early"); lsm_prep_single(lsm); lsm_init_single(lsm); } -- 2.49.0