]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - security/security.c
security: smack: Fix possible null-pointer dereferences in smack_socket_sock_rcv_skb()
[mirror_ubuntu-bionic-kernel.git] / security / security.c
index 14fdde773bad6804550578812a1f42c0b50b2259..e8dc75fab2ec788f7535bd65d48b13d425b3d335 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,7 +66,11 @@ 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 __initdata char chosen_display_lsm[SECURITY_NAME_MAX + 1]
+#ifdef CONFIG_SECURITY_STACKING
+       = CONFIG_SECURITY_DEFAULT_DISPLAY_NAME
+#endif
+;
 static char default_display_lsm[SECURITY_NAME_MAX + 1];
 
 static void __init do_security_initcalls(void)
@@ -182,6 +186,8 @@ static int lsm_append(char *new, char **result)
 
        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))
@@ -437,53 +443,6 @@ static inline char *lsm_of_task(struct task_struct *task)
 }
 #endif
 
-#ifdef CONFIG_SECURITY_STACKING
-struct lsm_value {
-       char *lsm;
-       char *data;
-};
-
-/**
- * lsm_parse_context - break a compound "context" into module data
- * @cxt: the initial data, which will be modified
- * @vlist: an array to receive the results
- *
- * Returns the number of entries, or -EINVAL if the cxt is unworkable.
- */
-static int lsm_parse_context(char *cxt, struct lsm_value *vlist)
-{
-       char *lsm;
-       char *data;
-       char *cp;
-       int i;
-
-       lsm = cxt;
-       for (i = 0; i < LSM_MAX_MAJOR; i++) {
-               data = strstr(lsm, "='");
-               if (!data)
-                       break;
-               *data = '\0';
-               data += 2;
-               cp = strchr(data, '\'');
-               if (!cp)
-                       return -EINVAL;
-               *cp++ = '\0';
-               vlist[i].lsm = lsm;
-               vlist[i].data = data;
-               if (*cp == '\0') {
-                       i++;
-                       break;
-               }
-               if (*cp == ',')
-                       cp++;
-               else
-                       return -EINVAL;
-               lsm = cp;
-       }
-       return i;
-}
-#endif /* CONFIG_SECURITY_STACKING */
-
 /**
  * lsm_task_alloc - allocate a composite task blob
  * @task: the task that needs a blob
@@ -1545,6 +1504,13 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 
 void security_cred_free(struct cred *cred)
 {
+       /*
+        * There is a failure case in prepare_creds() that
+        * may result in a call here with ->security being NULL.
+        */
+       if (unlikely(cred->security == NULL))
+               return;
+
        call_void_hook(cred_free, cred);
 
        kfree(cred->security);
@@ -1687,6 +1653,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)
 {
@@ -1694,7 +1687,6 @@ static int lsm_task_prctl(int option, unsigned long arg2, unsigned long arg3,
        char buffer[SECURITY_NAME_MAX + 1];
        __user char *optval = (__user char *)arg2;
        __user int *optlen = (__user int *)arg3;
-       struct security_hook_list *hp;
        int dlen;
        int len;
 
@@ -1721,21 +1713,12 @@ static int lsm_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                        return -EFAULT;
                buffer[len] = '\0';
                /* verify the requested LSM is registered */
-               list_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
-                       if (!strcmp(buffer, hp->lsm)) {
-                               strcpy(lsm, hp->lsm);
-                               goto out;
-                       }
-               }
-               if (!strncmp(buffer, nolsm, NOLSMLEN))
-                       lsm[0] = '\0';
-               else
+               if (!set_lsm_of_current(buffer, len))
                        return -ENOENT;
                break;
        default:
                return -ENOSYS;
        }
-out:
        return 0;
 }
 #endif
@@ -1930,6 +1913,14 @@ int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
        char *speclsm = lsm_of_task(p);
 #endif
        struct security_hook_list *hp;
+       int rc;
+
+       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))
@@ -1950,87 +1941,21 @@ int security_setprocattr(const char *lsm, const char *name, void *value,
 {
 #ifdef CONFIG_SECURITY_STACKING
        char *speclsm = lsm_of_task(current);
-       struct lsm_value *lsm_value = NULL;
-       int count;
 #else
        char *tvalue;
 #endif
        struct security_hook_list *hp;
        int rc;
-       char *temp;
-       char *cp;
 
-       /*
-        * If lsm is NULL look at all the modules to find one
-        * that processes name. If lsm is not NULL only look at
-        * that module.
-        *
-        * "context" is handled directly here.
-        */
-       if (strcmp(name, "context") == 0) {
-               rc = -EINVAL;
-               temp = kmemdup(value, size + 1, GFP_KERNEL);
-               if (!temp)
-                       return -ENOMEM;
-
-               temp[size] = '\0';
-               cp = strrchr(temp, '\'');
-               if (!cp)
-                       goto free_out;
+       if (!size)
+               return -EINVAL;
 
-               cp[1] = '\0';
+       if (strcmp(name, "display_lsm") == 0) {
 #ifdef CONFIG_SECURITY_STACKING
-               lsm_value = kzalloc(sizeof(*lsm_value) * LSM_MAX_MAJOR,
-                                       GFP_KERNEL);
-               if (!lsm_value) {
-                       rc = -ENOMEM;
-                       goto free_out;
-               }
-
-               count = lsm_parse_context(temp, lsm_value);
-               if (count <= 0)
-                       goto free_out;
-
-               for (count--; count >= 0; count--) {
-                       list_for_each_entry(hp,
-                               &security_hook_heads.setprocattr, list) {
-
-                               if (lsm && strcmp(lsm, hp->lsm))
-                                       continue;
-                               if (!strcmp(hp->lsm, lsm_value[count].lsm)) {
-                                       rc = hp->hook.setprocattr("context",
-                                               lsm_value[count].data,
-                                               strlen(lsm_value[count].data));
-                                       break;
-                               }
-                       }
-                       if (rc < 0 || (lsm && rc >0))
-                               break;
-               }
-#else /* CONFIG_SECURITY_STACKING */
-               cp = strstr(temp, "='");
-               if (!cp)
-                       goto free_out;
-               *cp = '\0';
-               tvalue = strchr(cp + 2, '\'');
-               if (!tvalue)
-                       goto free_out;
-               list_for_each_entry(hp, &security_hook_heads.setprocattr,
-                                                               list) {
-                       if (lsm == NULL || !strcmp(lsm, hp->lsm)) {
-                               rc = hp->hook.setprocattr(name, tvalue, size);
-                               break;
-                       }
-               }
-#endif /* CONFIG_SECURITY_STACKING */
-free_out:
-               kfree(temp);
-#ifdef CONFIG_SECURITY_STACKING
-               kfree(lsm_value);
-#endif
-               if (rc >= 0)
+               if (set_lsm_of_current(value, size))
                        return size;
-               return rc;
+#endif
+               return -EINVAL;
        }
 
        list_for_each_entry(hp, &security_hook_heads.setprocattr, list) {