On 4/9/2025 11:49 AM, Paul Moore wrote:
> The LSM currently has a lot of code to maintain a list of the
> currently active LSMs in a human readable string, with the only
> user being the "/sys/kernel/security/lsm" code.  Let's drop all
> of that code and generate the string on an as-needed basis when
> userspace reads "/sys/kernel/security/lsm".
>
> Signed-off-by: Paul Moore <p...@paul-moore.com>
> ---
>  include/linux/lsm_hooks.h |  1 -
>  security/inode.c          | 27 +++++++++++++++++++--
>  security/lsm_init.c       | 49 ---------------------------------------
>  3 files changed, 25 insertions(+), 52 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 4cd17c9a229f..bc477fb20d02 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -169,7 +169,6 @@ struct lsm_info {
>  
>  
>  /* DO NOT tamper with these variables outside of the LSM framework */
> -extern char *lsm_names;
>  extern struct lsm_static_calls_table static_calls_table __ro_after_init;
>  
>  /**
> diff --git a/security/inode.c b/security/inode.c
> index da3ab44c8e57..49bc3578bd23 100644
> --- a/security/inode.c
> +++ b/security/inode.c
> @@ -22,6 +22,8 @@
>  #include <linux/lsm_hooks.h>
>  #include <linux/magic.h>
>  
> +#include "lsm.h"
> +
>  static struct vfsmount *mount;
>  static int mount_count;
>  
> @@ -343,8 +345,29 @@ static struct dentry *lsm_dentry;
>  static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
>                       loff_t *ppos)
>  {
> -     return simple_read_from_buffer(buf, count, ppos, lsm_names,
> -             strlen(lsm_names));
> +     int i;
> +     char *str;
> +     ssize_t rc, len = 0;
> +
> +     for (i = 0; i < lsm_count; i++)
> +             /* the '+ 1' accounts for either a comma or a NUL terminator */
> +             len += strlen(lsm_order[i]->id->name) + 1;
> +
> +     str = kmalloc(len, GFP_KERNEL);
> +     if (!str)
> +             return -ENOMEM;
> +     str[0] = '\0';
> +
> +     i = 0;
> +     while (i < lsm_count) {
> +             strcat(str, lsm_order[i]->id->name);
> +             if (++i < lsm_count)
> +                     strcat(str, ",");
> +     }
> +
> +     rc = simple_read_from_buffer(buf, count, ppos, str, len);

This results in a trailing nul byte at the end of the string.

> +     kfree(str);
> +     return rc;
>  }
>  
>  static const struct file_operations lsm_ops = {
> diff --git a/security/lsm_init.c b/security/lsm_init.c
> index 981ddb20f48e..978bb81b58fa 100644
> --- a/security/lsm_init.c
> +++ b/security/lsm_init.c
> @@ -10,8 +10,6 @@
>  
>  #include "lsm.h"
>  
> -char *lsm_names;
> -
>  /* Pointers to LSM sections defined in include/asm-generic/vmlinux.lds.h */
>  extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
>  extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[];
> @@ -363,42 +361,6 @@ static void __init lsm_init_ordered(void)
>       }
>  }
>  
> -static bool match_last_lsm(const char *list, const char *lsm)
> -{
> -     const char *last;
> -
> -     if (WARN_ON(!list || !lsm))
> -             return false;
> -     last = strrchr(list, ',');
> -     if (last)
> -             /* Pass the comma, strcmp() will check for '\0' */
> -             last++;
> -     else
> -             last = list;
> -     return !strcmp(last, lsm);
> -}
> -
> -static int lsm_append(const char *new, char **result)
> -{
> -     char *cp;
> -
> -     if (*result == NULL) {
> -             *result = kstrdup(new, GFP_KERNEL);
> -             if (*result == NULL)
> -                     return -ENOMEM;
> -     } else {
> -             /* Check if it is the last registered name */
> -             if (match_last_lsm(*result, new))
> -                     return 0;
> -             cp = kasprintf(GFP_KERNEL, "%s,%s", *result, new);
> -             if (cp == NULL)
> -                     return -ENOMEM;
> -             kfree(*result);
> -             *result = cp;
> -     }
> -     return 0;
> -}
> -
>  static void __init lsm_static_call_init(struct security_hook_list *hl)
>  {
>       struct lsm_static_call *scall = hl->scalls;
> @@ -435,15 +397,6 @@ void __init security_add_hooks(struct security_hook_list 
> *hooks, int count,
>               hooks[i].lsmid = lsmid;
>               lsm_static_call_init(&hooks[i]);
>       }
> -
> -     /*
> -      * Don't try to append during early_security_init(), we'll come back
> -      * and fix this up afterwards.
> -      */
> -     if (slab_is_available()) {
> -             if (lsm_append(lsmid->name, &lsm_names) < 0)
> -                     panic("%s - Cannot get early memory.\n", __func__);
> -     }
>  }
>  
>  int __init early_security_init(void)
> @@ -480,8 +433,6 @@ int __init security_init(void)
>       lsm_early_for_each_raw(lsm) {
>               init_debug("  early started: %s (%s)\n", lsm->id->name,
>                          is_enabled(lsm) ? "enabled" : "disabled");
> -             if (lsm->enabled)
> -                     lsm_append(lsm->id->name, &lsm_names);
>       }
>  
>       /* Load LSMs in specified order. */

Reply via email to