diff options
authorMickaël Salaün <mic@digikod.net>2017-05-10 22:48:48 +0200
committerJames Morris <james.l.morris@oracle.com>2017-05-15 09:35:53 +1000
commit3bb857e47e49f72352249c938aa8b9159d636530 (patch)
parenttpm: Fix reference count to main device (diff)
LSM: Enable multiple calls to security_add_hooks() for the same LSM
The commit d69dece5f5b6 ("LSM: Add /sys/kernel/security/lsm") extend security_add_hooks() with a new parameter to register the LSM name, which may be useful to make the list of currently loaded LSM available to userspace. However, there is no clean way for an LSM to split its hook declarations into multiple files, which may reduce the mess with all the included files (needed for LSM hook argument types) and make the source code easier to review and maintain. This change allows an LSM to register multiple times its hook while keeping a consistent list of LSM names as described in Documentation/security/LSM.txt . The list reflects the order in which checks are made. This patch only check for the last registered LSM. If an LSM register multiple times its hooks, interleaved with other LSM registrations (which should not happen), its name will still appear in the same order that the hooks are called, hence multiple times. To sum up, "capability,selinux,foo,foo" will be replaced with "capability,selinux,foo", however "capability,foo,selinux,foo" will remain as is. Signed-off-by: Mickaël Salaün <mic@digikod.net> Acked-by: Kees Cook <keescook@chromium.org> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: James Morris <james.l.morris@oracle.com>
1 files changed, 19 insertions, 0 deletions
diff --git a/security/security.c b/security/security.c
index 549bddcc2116..54b1e395978a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -25,6 +25,7 @@
#include <linux/mount.h>
#include <linux/personality.h>
#include <linux/backing-dev.h>
+#include <linux/string.h>
#include <net/flow.h>
@@ -86,6 +87,21 @@ static int __init choose_lsm(char *str)
__setup("security=", choose_lsm);
+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(char *new, char **result)
char *cp;
@@ -93,6 +109,9 @@ static int lsm_append(char *new, char **result)
if (*result == NULL) {
*result = kstrdup(new, GFP_KERNEL);
} 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;