+/**
+ * lsm_cred_alloc - allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ * @gfp: allocation type
+ *
+ * Allocate the cred blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+{
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+ if (cred->security)
+ pr_info("%s: Inbound cred blob is not NULL.\n", __func__);
+#endif
+ if (blob_sizes.lbs_cred == 0)
+ return 0;
+
+ cred->security = kzalloc(blob_sizes.lbs_cred, gfp);
+ if (cred->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_early_cred - during initialization allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ *
+ * Allocate the cred blob for all the modules if it's not already there
+ */
+void lsm_early_cred(struct cred *cred)
+{
+ int rc;
+
+ if (cred == NULL)
+ panic("%s: NULL cred.\n", __func__);
+ if (cred->security != NULL)
+ return;
+ rc = lsm_cred_alloc(cred, GFP_KERNEL);
+ if (rc)
+ panic("%s: Early cred alloc failed.\n", __func__);
+}
+
+static void __init lsm_set_size(int *need, int *lbs)
+{
+ int offset;
+
+ if (*need > 0) {
+ offset = *lbs;
+ *lbs += *need;
+ *need = offset;
+ }
+}
+
+/**
+ * security_add_blobs - Report blob sizes
+ * @needed: the size of blobs needed by the module
+ *
+ * Each LSM has to register its blobs with the infrastructure.
+ * The "needed" data tells the infrastructure how much memory
+ * the module requires for each of its blobs. On return the
+ * structure is filled with the offset that module should use
+ * from the blob pointer.
+ */
+void __init security_add_blobs(struct lsm_blob_sizes *needed)
+{
+ lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
+ lsm_set_size(&needed->lbs_task, &blob_sizes.lbs_task);
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_file_alloc(struct file *file)
+{
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+ if (file->f_security)
+ pr_info("%s: Inbound file blob is not NULL.\n", __func__);
+#endif
+ if (blob_sizes.lbs_file == 0)
+ return 0;
+
+ file->f_security = kzalloc(blob_sizes.lbs_file, GFP_KERNEL);
+ if (file->f_security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+#ifdef CONFIG_SECURITY_STACKING
+static inline char *lsm_of_task(struct task_struct *task)
+{
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+ if (task->security == NULL)
+ pr_info("%s: task has no lsm name.\n", __func__);
+#endif
+ return task->security;
+}
+#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
+ *
+ * Allocate the task blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_task_alloc(struct task_struct *task)
+{
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+ if (task->security)
+ pr_info("%s: Inbound task blob is not NULL.\n", __func__);
+#endif
+ if (blob_sizes.lbs_task == 0)
+ return 0;
+
+ task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
+ if (task->security == NULL)
+ return -ENOMEM;
+
+ /* inherit current display lsm */
+#ifdef CONFIG_SECURITY_STACKING
+ if (current->security)
+ strcpy(task->security, lsm_of_task(current));
+ else
+ strcpy(task->security, default_display_lsm);
+#endif
+ return 0;
+}
+