]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - security/security.c
UBUNTU: SAUCE: LSM stacking: fixup: alloc_task_ctx is dead code
[mirror_ubuntu-bionic-kernel.git] / security / security.c
index 1cd8526cb0b775647fe567a6910cc7b811cff21a..1cdb8e1e9d3bbc09440e1c63bca16f90ff34200d 100644 (file)
 #include <linux/personality.h>
 #include <linux/backing-dev.h>
 #include <linux/string.h>
+#include <linux/msg.h>
 #include <net/flow.h>
+#include <net/sock.h>
 
 #define MAX_LSM_EVM_XATTR      2
 
 /* Maximum number of letters for an LSM name string */
 #define SECURITY_NAME_MAX      10
+#define MODULE_STACK           "(stacking)"
 
 struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
 
+static struct kmem_cache *lsm_file_cache;
+static struct kmem_cache *lsm_inode_cache;
+
 char *lsm_names;
+static struct lsm_blob_sizes blob_sizes;
+
 /* Boot-time LSM user choice */
 static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
+#ifdef CONFIG_SECURITY_STACKING
+       MODULE_STACK;
+#else
        CONFIG_DEFAULT_SECURITY;
+#endif
 
 static void __init do_security_initcalls(void)
 {
@@ -76,10 +88,43 @@ int __init security_init(void)
        loadpin_add_hooks();
 
        /*
-        * Load all the remaining security modules.
+        * The first call to a module specific init function
+        * updates the blob size requirements.
         */
        do_security_initcalls();
 
+       /*
+        * Create any kmem_caches needed for blobs
+        */
+       if (blob_sizes.lbs_file)
+               lsm_file_cache = kmem_cache_create("lsm_file_cache",
+                                                  blob_sizes.lbs_file, 0,
+                                                  SLAB_PANIC, NULL);
+       if (blob_sizes.lbs_inode)
+               lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
+                                                   blob_sizes.lbs_inode, 0,
+                                                   SLAB_PANIC, NULL);
+       /*
+        * The second call to a module specific init function
+        * adds hooks to the hook lists and does any other early
+        * initializations required.
+        */
+       do_security_initcalls();
+
+#ifdef CONFIG_SECURITY_LSM_DEBUG
+       pr_info("LSM: cred blob size       = %d\n", blob_sizes.lbs_cred);
+       pr_info("LSM: file blob size       = %d\n", blob_sizes.lbs_file);
+       pr_info("LSM: inode blob size      = %d\n", blob_sizes.lbs_inode);
+       pr_info("LSM: ipc blob size        = %d\n", blob_sizes.lbs_ipc);
+#ifdef CONFIG_KEYS
+       pr_info("LSM: key blob size        = %d\n", blob_sizes.lbs_key);
+#endif /* CONFIG_KEYS */
+       pr_info("LSM: msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
+       pr_info("LSM: sock blob size       = %d\n", blob_sizes.lbs_sock);
+       pr_info("LSM: superblock blob size = %d\n", blob_sizes.lbs_superblock);
+       pr_info("LSM: task blob size       = %d\n", blob_sizes.lbs_task);
+#endif /* CONFIG_SECURITY_LSM_DEBUG */
+
        return 0;
 }
 
@@ -128,6 +173,7 @@ static int lsm_append(char *new, char **result)
 /**
  * security_module_enable - Load given security module on boot ?
  * @module: the name of the module
+ * @stacked: indicates that the module wants to be stacked
  *
  * Each LSM must pass this method before registering its own operations
  * to avoid security registration races. This method may also be used
@@ -143,9 +189,29 @@ static int lsm_append(char *new, char **result)
  *
  * Otherwise, return false.
  */
-int __init security_module_enable(const char *module)
+bool __init security_module_enable(const char *lsm, const bool stacked)
 {
-       return !strcmp(module, chosen_lsm);
+#ifdef CONFIG_SECURITY_STACKING
+       /*
+        * Module defined on the command line security=XXXX
+        */
+       if (strcmp(chosen_lsm, MODULE_STACK)) {
+               if (!strcmp(lsm, chosen_lsm)) {
+                       pr_info("Command line sets the %s security module.\n",
+                               lsm);
+                       return true;
+               }
+               return false;
+       }
+       /*
+        * Module configured as stacked.
+        */
+       return stacked;
+#else
+       if (strcmp(lsm, chosen_lsm) == 0)
+               return true;
+       return false;
+#endif
 }
 
 /**
@@ -187,6 +253,277 @@ int unregister_lsm_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL(unregister_lsm_notifier);
 
+/**
+ * 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)
+{
+       if (blob_sizes.lbs_cred == 0) {
+               cred->security = NULL;
+               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_ipc, &blob_sizes.lbs_ipc);
+       lsm_set_size(&needed->lbs_key, &blob_sizes.lbs_key);
+       lsm_set_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+       lsm_set_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
+       lsm_set_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
+       lsm_set_size(&needed->lbs_task, &blob_sizes.lbs_task);
+       /*
+        * The inode blob gets an rcu_head in addition to
+        * what the modules might need.
+        */
+       if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
+               blob_sizes.lbs_inode = sizeof(struct rcu_head);
+       lsm_set_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+}
+
+/**
+ * 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)
+{
+       if (!lsm_file_cache) {
+               file->f_security = NULL;
+               return 0;
+       }
+
+       file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
+       if (file->f_security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * 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)
+{
+       if (blob_sizes.lbs_task == 0) {
+               task->security = NULL;
+               return 0;
+       }
+
+       task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
+       if (task->security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_inode_alloc - allocate a composite inode blob
+ * @inode: the inode that needs a blob
+ *
+ * Allocate the inode blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_inode_alloc(struct inode *inode)
+{
+       if (!lsm_inode_cache) {
+               inode->i_security = NULL;
+               return 0;
+       }
+
+       inode->i_security = kmem_cache_zalloc(lsm_inode_cache, GFP_KERNEL);
+       if (inode->i_security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_early_inode - during initialization allocate a composite inode blob
+ * @inode: the inode that needs a blob
+ *
+ * Allocate the inode blob for all the modules if it's not already there
+ */
+void lsm_early_inode(struct inode *inode)
+{
+       int rc;
+
+       if (inode == NULL)
+               panic("%s: NULL inode.\n", __func__);
+       if (inode->i_security != NULL)
+               return;
+       rc = lsm_inode_alloc(inode);
+       if (rc)
+               panic("%s: Early inode alloc failed.\n", __func__);
+}
+
+/**
+ * lsm_ipc_alloc - allocate a composite ipc blob
+ * @kip: the ipc that needs a blob
+ *
+ * Allocate the ipc blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_ipc_alloc(struct kern_ipc_perm *kip)
+{
+       if (blob_sizes.lbs_ipc == 0) {
+               kip->security = NULL;
+               return 0;
+       }
+
+       kip->security = kzalloc(blob_sizes.lbs_ipc, GFP_KERNEL);
+       if (kip->security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+#ifdef CONFIG_KEYS
+/**
+ * lsm_key_alloc - allocate a composite key blob
+ * @key: the key that needs a blob
+ *
+ * Allocate the key blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_key_alloc(struct key *key)
+{
+       if (blob_sizes.lbs_key == 0) {
+               key->security = NULL;
+               return 0;
+       }
+
+       key->security = kzalloc(blob_sizes.lbs_key, GFP_KERNEL);
+       if (key->security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+#endif /* CONFIG_KEYS */
+
+/**
+ * lsm_msg_msg_alloc - allocate a composite msg_msg blob
+ * @mp: the msg_msg that needs a blob
+ *
+ * Allocate the ipc blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_msg_msg_alloc(struct msg_msg *mp)
+{
+       if (blob_sizes.lbs_msg_msg == 0) {
+               mp->security = NULL;
+               return 0;
+       }
+
+       mp->security = kzalloc(blob_sizes.lbs_msg_msg, GFP_KERNEL);
+       if (mp->security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_sock_alloc - allocate a composite sock blob
+ * @sock: the sock that needs a blob
+ * @priority: allocation mode
+ *
+ * Allocate the sock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_sock_alloc(struct sock *sock, gfp_t priority)
+{
+       if (blob_sizes.lbs_sock == 0) {
+               sock->sk_security = NULL;
+               return 0;
+       }
+
+       sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority);
+       if (sock->sk_security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_superblock_alloc - allocate a composite superblock blob
+ * @sb: the superblock that needs a blob
+ *
+ * Allocate the superblock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_superblock_alloc(struct super_block *sb)
+{
+       if (blob_sizes.lbs_superblock == 0) {
+               sb->s_security = NULL;
+               return 0;
+       }
+
+       sb->s_security = kzalloc(blob_sizes.lbs_superblock, GFP_KERNEL);
+       if (sb->s_security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
 /*
  * Hook list operation macros.
  *
@@ -354,12 +691,21 @@ void security_bprm_committed_creds(struct linux_binprm *bprm)
 
 int security_sb_alloc(struct super_block *sb)
 {
-       return call_int_hook(sb_alloc_security, 0, sb);
+       int rc = lsm_superblock_alloc(sb);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(sb_alloc_security, 0, sb);
+       if (unlikely(rc))
+               security_sb_free(sb);
+       return rc;
 }
 
 void security_sb_free(struct super_block *sb)
 {
        call_void_hook(sb_free_security, sb);
+       kfree(sb->s_security);
+       sb->s_security = NULL;
 }
 
 int security_sb_copy_data(char *orig, char *copy)
@@ -433,14 +779,40 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);
 
 int security_inode_alloc(struct inode *inode)
 {
-       inode->i_security = NULL;
-       return call_int_hook(inode_alloc_security, 0, inode);
+       int rc = lsm_inode_alloc(inode);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(inode_alloc_security, 0, inode);
+       if (unlikely(rc))
+               security_inode_free(inode);
+       return rc;
+}
+
+static void inode_free_by_rcu(struct rcu_head *head)
+{
+       /*
+        * The rcu head is at the start of the inode blob
+        */
+       kmem_cache_free(lsm_inode_cache, head);
 }
 
 void security_inode_free(struct inode *inode)
 {
        integrity_inode_free(inode);
        call_void_hook(inode_free_security, inode);
+       /*
+        * The inode may still be referenced in a path walk and
+        * a call to security_inode_permission() can be made
+        * after inode_free_security() is called. Ideally, the VFS
+        * wouldn't do this, but fixing that is a much harder
+        * job. For now, simply free the i_security via RCU, and
+        * leave the current inode->i_security pointer intact.
+        * The inode will be freed after the RCU grace period too.
+        */
+       if (inode->i_security)
+               call_rcu((struct rcu_head *)inode->i_security,
+                               inode_free_by_rcu);
 }
 
 int security_dentry_init_security(struct dentry *dentry, int mode,
@@ -531,6 +903,7 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry)
                return 0;
        return call_int_hook(path_rmdir, 0, dir, dentry);
 }
+EXPORT_SYMBOL_GPL(security_path_rmdir);
 
 int security_path_unlink(const struct path *dir, struct dentry *dentry)
 {
@@ -547,6 +920,7 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry,
                return 0;
        return call_int_hook(path_symlink, 0, dir, dentry, old_name);
 }
+EXPORT_SYMBOL_GPL(security_path_symlink);
 
 int security_path_link(struct dentry *old_dentry, const struct path *new_dir,
                       struct dentry *new_dentry)
@@ -555,6 +929,7 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir,
                return 0;
        return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry);
 }
+EXPORT_SYMBOL_GPL(security_path_link);
 
 int security_path_rename(const struct path *old_dir, struct dentry *old_dentry,
                         const struct path *new_dir, struct dentry *new_dentry,
@@ -582,6 +957,7 @@ int security_path_truncate(const struct path *path)
                return 0;
        return call_int_hook(path_truncate, 0, path);
 }
+EXPORT_SYMBOL_GPL(security_path_truncate);
 
 int security_path_chmod(const struct path *path, umode_t mode)
 {
@@ -589,6 +965,7 @@ int security_path_chmod(const struct path *path, umode_t mode)
                return 0;
        return call_int_hook(path_chmod, 0, path, mode);
 }
+EXPORT_SYMBOL_GPL(security_path_chmod);
 
 int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
 {
@@ -596,6 +973,7 @@ int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
                return 0;
        return call_int_hook(path_chown, 0, path, uid, gid);
 }
+EXPORT_SYMBOL_GPL(security_path_chown);
 
 int security_path_chroot(const struct path *path)
 {
@@ -681,6 +1059,7 @@ int security_inode_readlink(struct dentry *dentry)
                return 0;
        return call_int_hook(inode_readlink, 0, dentry);
 }
+EXPORT_SYMBOL_GPL(security_inode_readlink);
 
 int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
                               bool rcu)
@@ -696,6 +1075,7 @@ int security_inode_permission(struct inode *inode, int mask)
                return 0;
        return call_int_hook(inode_permission, 0, inode, mask);
 }
+EXPORT_SYMBOL_GPL(security_inode_permission);
 
 int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
 {
@@ -867,15 +1247,32 @@ int security_file_permission(struct file *file, int mask)
 
        return fsnotify_perm(file, mask);
 }
+EXPORT_SYMBOL_GPL(security_file_permission);
 
 int security_file_alloc(struct file *file)
 {
-       return call_int_hook(file_alloc_security, 0, file);
+       int rc = lsm_file_alloc(file);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(file_alloc_security, 0, file);
+       if (unlikely(rc))
+               security_file_free(file);
+       return rc;
 }
 
 void security_file_free(struct file *file)
 {
+       void *blob;
+
+       if (!lsm_file_cache)
+               return;
+
        call_void_hook(file_free_security, file);
+
+       blob = file->f_security;
+       file->f_security = NULL;
+       kmem_cache_free(lsm_file_cache, blob);
 }
 
 int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -926,6 +1323,7 @@ int security_mmap_file(struct file *file, unsigned long prot,
                return ret;
        return ima_file_mmap(file, prot);
 }
+EXPORT_SYMBOL_GPL(security_mmap_file);
 
 int security_mmap_addr(unsigned long addr)
 {
@@ -977,27 +1375,56 @@ int security_file_open(struct file *file, const struct cred *cred)
 
 int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
 {
-       return call_int_hook(task_alloc, 0, task, clone_flags);
+       int rc = lsm_task_alloc(task);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(task_alloc, 0, task, clone_flags);
+       if (unlikely(rc))
+               security_task_free(task);
+       return rc;
 }
 
 void security_task_free(struct task_struct *task)
 {
        call_void_hook(task_free, task);
+
+       kfree(task->security);
+       task->security = NULL;
 }
 
 int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
-       return call_int_hook(cred_alloc_blank, 0, cred, gfp);
+       int rc = lsm_cred_alloc(cred, gfp);
+
+       if (unlikely(rc))
+               return rc;
+
+       rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
+       if (unlikely(rc))
+               security_cred_free(cred);
+       return rc;
 }
 
 void security_cred_free(struct cred *cred)
 {
        call_void_hook(cred_free, cred);
+
+       kfree(cred->security);
+       cred->security = NULL;
 }
 
 int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
 {
-       return call_int_hook(cred_prepare, 0, new, old, gfp);
+       int rc = lsm_cred_alloc(new, gfp);
+
+       if (unlikely(rc))
+               return rc;
+
+       rc = call_int_hook(cred_prepare, 0, new, old, gfp);
+       if (unlikely(rc))
+               security_cred_free(new);
+       return rc;
 }
 
 void security_transfer_creds(struct cred *new, const struct cred *old)
@@ -1155,22 +1582,42 @@ void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
 
 int security_msg_msg_alloc(struct msg_msg *msg)
 {
-       return call_int_hook(msg_msg_alloc_security, 0, msg);
+       int rc = lsm_msg_msg_alloc(msg);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(msg_msg_alloc_security, 0, msg);
+       if (unlikely(rc))
+               security_msg_msg_free(msg);
+       return rc;
 }
 
 void security_msg_msg_free(struct msg_msg *msg)
 {
        call_void_hook(msg_msg_free_security, msg);
+       kfree(msg->security);
+       msg->security = NULL;
 }
 
 int security_msg_queue_alloc(struct msg_queue *msq)
 {
-       return call_int_hook(msg_queue_alloc_security, 0, msq);
+       int rc = lsm_ipc_alloc(&msq->q_perm);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(msg_queue_alloc_security, 0, msq);
+       if (unlikely(rc))
+               security_msg_queue_free(msq);
+       return rc;
 }
 
 void security_msg_queue_free(struct msg_queue *msq)
 {
+       struct kern_ipc_perm *kip = &msq->q_perm;
+
        call_void_hook(msg_queue_free_security, msq);
+       kfree(kip->security);
+       kip->security = NULL;
 }
 
 int security_msg_queue_associate(struct msg_queue *msq, int msqflg)
@@ -1197,12 +1644,23 @@ int security_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 
 int security_shm_alloc(struct shmid_kernel *shp)
 {
-       return call_int_hook(shm_alloc_security, 0, shp);
+       int rc = lsm_ipc_alloc(&shp->shm_perm);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(shm_alloc_security, 0, shp);
+       if (unlikely(rc))
+               security_shm_free(shp);
+       return rc;
 }
 
 void security_shm_free(struct shmid_kernel *shp)
 {
+       struct kern_ipc_perm *kip = &shp->shm_perm;
+
        call_void_hook(shm_free_security, shp);
+       kfree(kip->security);
+       kip->security = NULL;
 }
 
 int security_shm_associate(struct shmid_kernel *shp, int shmflg)
@@ -1222,12 +1680,23 @@ int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmfl
 
 int security_sem_alloc(struct sem_array *sma)
 {
-       return call_int_hook(sem_alloc_security, 0, sma);
+       int rc = lsm_ipc_alloc(&sma->sem_perm);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(sem_alloc_security, 0, sma);
+       if (unlikely(rc))
+               security_sem_free(sma);
+       return rc;
 }
 
 void security_sem_free(struct sem_array *sma)
 {
+       struct kern_ipc_perm *kip = &sma->sem_perm;
+
        call_void_hook(sem_free_security, sma);
+       kfree(kip->security);
+       kip->security = NULL;
 }
 
 int security_sem_associate(struct sem_array *sma, int semflg)
@@ -1254,14 +1723,30 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 }
 EXPORT_SYMBOL(security_d_instantiate);
 
-int security_getprocattr(struct task_struct *p, char *name, char **value)
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+                               char **value)
 {
-       return call_int_hook(getprocattr, -EINVAL, p, name, value);
+       struct security_hook_list *hp;
+
+       list_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
+               if (lsm != NULL && strcmp(lsm, hp->lsm))
+                       continue;
+               return hp->hook.getprocattr(p, name, value);
+       }
+       return -EINVAL;
 }
 
-int security_setprocattr(const char *name, void *value, size_t size)
+int security_setprocattr(const char *lsm, const char *name, void *value,
+                        size_t size)
 {
-       return call_int_hook(setprocattr, -EINVAL, name, value, size);
+       struct security_hook_list *hp;
+
+       list_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
+               if (lsm != NULL && strcmp(lsm, hp->lsm))
+                       continue;
+               return hp->hook.setprocattr(name, value, size);
+       }
+       return -EINVAL;
 }
 
 int security_netlink_send(struct sock *sk, struct sk_buff *skb)
@@ -1423,12 +1908,21 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram);
 
 int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
 {
-       return call_int_hook(sk_alloc_security, 0, sk, family, priority);
+       int rc = lsm_sock_alloc(sk, priority);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(sk_alloc_security, 0, sk, family, priority);
+       if (unlikely(rc))
+               security_sk_free(sk);
+       return rc;
 }
 
 void security_sk_free(struct sock *sk)
 {
        call_void_hook(sk_free_security, sk);
+       kfree(sk->sk_security);
+       sk->sk_security = NULL;
 }
 
 void security_sk_clone(const struct sock *sk, struct sock *newsk)
@@ -1658,12 +2152,21 @@ EXPORT_SYMBOL(security_skb_classify_flow);
 int security_key_alloc(struct key *key, const struct cred *cred,
                       unsigned long flags)
 {
-       return call_int_hook(key_alloc, 0, key, cred, flags);
+       int rc = lsm_key_alloc(key);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(key_alloc, 0, key, cred, flags);
+       if (unlikely(rc))
+               security_key_free(key);
+       return rc;
 }
 
 void security_key_free(struct key *key)
 {
        call_void_hook(key_free, key);
+       kfree(key->security);
+       key->security = NULL;
 }
 
 int security_key_permission(key_ref_t key_ref,