]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - security/security.c
UBUNTU: SAUCE: LSM stacking: add /proc/<pid>/attr/display_lsm
[mirror_ubuntu-bionic-kernel.git] / security / security.c
index 4c1fec9f8bc055ce223c510abe830391f416b6ba..03624c3e0b7fc66907753da882f21691e58c1b7c 100644 (file)
@@ -55,7 +55,7 @@ char *lsm_names;
  */
 static struct lsm_blob_sizes blob_sizes = {
 #ifdef CONFIG_SECURITY_STACKING
-       .lbs_task = SECURITY_NAME_MAX + 2,
+       .lbs_task = SECURITY_NAME_MAX + 6,
 #endif
 };
 
@@ -66,6 +66,8 @@ static __initdata char chosen_lsms[SECURITY_CHOSEN_NAMES_MAX + 1] =
 #else
        CONFIG_DEFAULT_SECURITY;
 #endif
+static __initdata char chosen_display_lsm[SECURITY_NAME_MAX + 1];
+static char default_display_lsm[SECURITY_NAME_MAX + 1];
 
 static void __init do_security_initcalls(void)
 {
@@ -150,6 +152,15 @@ static int __init choose_lsm(char *str)
 }
 __setup("security=", choose_lsm);
 
+static int __init choose_display_lsm(char *str)
+{
+       strncpy(chosen_display_lsm, str, SECURITY_NAME_MAX);
+       pr_info("LSM: command line set default display lsm %s'\n",
+               chosen_display_lsm);
+       return 1;
+}
+__setup("security.display=", choose_display_lsm);
+
 static bool match_last_lsm(const char *list, const char *lsm)
 {
        const char *last;
@@ -231,16 +242,35 @@ bool __init security_module_enable(const char *lsm, const bool stacked)
        /*
         * Module defined on the command line security=XXXX
         */
-       if (strcmp(chosen_lsms, MODULE_STACK))
-               return cmp_lsms(lsm);
-
+       if (strcmp(chosen_lsms, MODULE_STACK)) {
+               if (cmp_lsms(lsm)) {
+                       /* set to first LSM registered and then override */
+                       if (!*default_display_lsm)
+                               strcpy(default_display_lsm, lsm);
+                       else if (*chosen_display_lsm && !strcmp(chosen_display_lsm, lsm)) {
+                               strcpy(default_display_lsm, lsm);
+                               pr_info("LSM: default display lsm '%s'\n", default_display_lsm);
+                       }
+                       return true;
+               }
+               return false;
+       }
        /*
         * Module configured as stacked.
         */
+       if (stacked && !*default_display_lsm)
+               strcpy(default_display_lsm, lsm);
+       else if (stacked && *chosen_display_lsm && !strcmp(chosen_display_lsm, lsm)) {
+               strcpy(default_display_lsm, lsm);
+               pr_info("LSM: default display lsm '%s'\n", default_display_lsm);
+       }
+
        return stacked;
 #else
-       if (strcmp(lsm, chosen_lsms) == 0)
+       if (strcmp(lsm, chosen_lsms) == 0) {
+               strcpy(default_display_lsm, lsm);
                return true;
+       }
        return false;
 #endif
 }
@@ -477,6 +507,8 @@ int lsm_task_alloc(struct task_struct *task)
 #ifdef CONFIG_SECURITY_STACKING
        if (current->security)
                strcpy(task->security, lsm_of_task(current));
+       else
+               strcpy(task->security, default_display_lsm);
 #endif
        return 0;
 }
@@ -1655,6 +1687,33 @@ int security_task_kill(struct task_struct *p, struct siginfo *info,
 static char *nolsm = "-default";
 #define NOLSMLEN       9
 
+static bool is_registered_lsm(const char *str, size_t size)
+{
+       struct security_hook_list *hp;
+
+       list_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
+               if (size == strlen(hp->lsm) && !strncmp(str, hp->lsm, size))
+                       return true;
+       }
+
+       return false;
+}
+
+static bool set_lsm_of_current(const char *str, size_t size)
+{
+       char *lsm = lsm_of_task(current);
+
+       if (is_registered_lsm(str, size)) {
+               strncpy(lsm, str, size);
+               lsm[size] = '\0';
+       } else if (size == NOLSMLEN && !strncmp(str, nolsm, size)) {
+               lsm[0] = '\0';
+       } else {
+               return false;
+       }
+       return true;
+}
+
 static int lsm_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                                unsigned long arg4, unsigned long arg5)
 {
@@ -1687,13 +1746,9 @@ static int lsm_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                if (copy_from_user(buffer, optval, len))
                        return -EFAULT;
                buffer[len] = '\0';
-               /*
-                * Trust the caller to know what lsm name(s) are available.
-                */
-               if (!strncmp(buffer, nolsm, NOLSMLEN))
-                       lsm[0] = '\0';
-               else
-                       strcpy(lsm, buffer);
+               /* verify the requested LSM is registered */
+               if (!set_lsm_of_current(buffer, len))
+                       return -ENOENT;
                break;
        default:
                return -ENOSYS;
@@ -1892,6 +1947,53 @@ int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
        char *speclsm = lsm_of_task(p);
 #endif
        struct security_hook_list *hp;
+       char *vp;
+       char *cp = NULL;
+       int trc;
+       int rc;
+
+       /*
+        * "context" requires work here in addition to what
+        * the modules provide.
+        */
+       if (strcmp(name, "context") == 0) {
+               *value = NULL;
+               rc = -EINVAL;
+               list_for_each_entry(hp,
+                               &security_hook_heads.getprocattr, list) {
+                       if (lsm != NULL && strcmp(lsm, hp->lsm))
+                               continue;
+                       trc = hp->hook.getprocattr(p, "context", &vp);
+                       if (trc == -ENOENT)
+                               continue;
+                       if (trc <= 0) {
+                               kfree(*value);
+                               return trc;
+                       }
+                       rc = trc;
+                       if (*value == NULL) {
+                               *value = vp;
+                       } else {
+                               cp = kasprintf(GFP_KERNEL, "%s,%s", *value, vp);
+                               if (cp == NULL) {
+                                       kfree(*value);
+                                       kfree(vp);
+                                       return -ENOMEM;
+                               }
+                               kfree(*value);
+                               kfree(vp);
+                               *value = cp;
+                       }
+               }
+               if (rc > 0)
+                       return strlen(*value);
+               return rc;
+       } else if (strcmp(name, "display_lsm") == 0) {
+               *value = kstrdup(current->security, GFP_KERNEL);
+               if (*value == NULL)
+                       return -ENOMEM;
+               return strlen(*value);
+       }
 
        list_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
                if (lsm != NULL && strcmp(lsm, hp->lsm))
@@ -1993,6 +2095,12 @@ free_out:
                if (rc >= 0)
                        return size;
                return rc;
+       } else if (strcmp(name, "display_lsm") == 0) {
+#ifdef CONFIG_SECURITY_STACKING
+               if (set_lsm_of_current(value, size))
+                       return size;
+#endif
+               return -EINVAL;
        }
 
        list_for_each_entry(hp, &security_hook_heads.setprocattr, list) {