]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - security/security.c
UBUNTU: SAUCE: LSM: Use lsmcontext in security_inode_getsecctx
[mirror_ubuntu-jammy-kernel.git] / security / security.c
index 9ffa9e9c5c554a6939cf175560a617414ce38a00..24f28cfc0a31fcf20ce1bbe0daf9336d881f3701 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/string.h>
 #include <linux/msg.h>
 #include <net/flow.h>
+#include <net/sock.h>
 
 #define MAX_LSM_EVM_XATTR      2
 
@@ -77,7 +78,14 @@ static struct kmem_cache *lsm_file_cache;
 static struct kmem_cache *lsm_inode_cache;
 
 char *lsm_names;
-static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;
+
+/*
+ * The task blob includes the "display" slot used for
+ * chosing which module presents contexts.
+ */
+static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init = {
+       .lbs_task = sizeof(int),
+};
 
 /* Boot-time LSM user choice */
 static __initdata const char *chosen_lsm_order;
@@ -205,6 +213,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
        lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
        lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
        lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
+       lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
        lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
 }
 
@@ -341,7 +350,9 @@ static void __init ordered_lsm_init(void)
        init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
        init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
        init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
+       init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
        init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
+       init_debug("lsmblob size       = %zu\n", sizeof(struct lsmblob));
 
        /*
         * Create any kmem_caches needed for blobs
@@ -469,21 +480,39 @@ static int lsm_append(const char *new, char **result)
        return 0;
 }
 
+/*
+ * Current index to use while initializing the lsmblob secid list.
+ * Pointers to the LSM id structures for local use.
+ */
+static int lsm_slot __lsm_ro_after_init;
+static struct lsm_id *lsm_slotlist[LSMBLOB_ENTRIES];
+
 /**
  * security_add_hooks - Add a modules hooks to the hook lists.
  * @hooks: the hooks to add
  * @count: the number of hooks to add
- * @lsm: the name of the security module
+ * @lsmid: the the identification information for the security module
  *
  * Each LSM has to register its hooks with the infrastructure.
+ * If the LSM is using hooks that export secids allocate a slot
+ * for it in the lsmblob.
  */
 void __init security_add_hooks(struct security_hook_list *hooks, int count,
-                               char *lsm)
+                              struct lsm_id *lsmid)
 {
        int i;
 
+       if (lsmid->slot == LSMBLOB_NEEDED) {
+               if (lsm_slot >= LSMBLOB_ENTRIES)
+                       panic("%s Too many LSMs registered.\n", __func__);
+               lsm_slotlist[lsm_slot] = lsmid;
+               lsmid->slot = lsm_slot++;
+               init_debug("%s assigned lsmblob slot %d\n", lsmid->lsm,
+                          lsmid->slot);
+       }
+
        for (i = 0; i < count; i++) {
-               hooks[i].lsm = lsm;
+               hooks[i].lsmid = lsmid;
                hlist_add_tail_rcu(&hooks[i].list, hooks[i].head);
        }
 
@@ -492,7 +521,7 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
         * and fix this up afterwards.
         */
        if (slab_is_available()) {
-               if (lsm_append(lsm, &lsm_names) < 0)
+               if (lsm_append(lsmid->lsm, &lsm_names) < 0)
                        panic("%s - Cannot get early memory.\n", __func__);
        }
 }
@@ -606,6 +635,8 @@ int lsm_inode_alloc(struct inode *inode)
  */
 static int lsm_task_alloc(struct task_struct *task)
 {
+       int *display;
+
        if (blob_sizes.lbs_task == 0) {
                task->security = NULL;
                return 0;
@@ -614,6 +645,15 @@ static int lsm_task_alloc(struct task_struct *task)
        task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
        if (task->security == NULL)
                return -ENOMEM;
+
+       /*
+        * The start of the task blob contains the "display" LSM slot number.
+        * Start with it set to the invalid slot number, indicating that the
+        * default first registered LSM be displayed.
+        */
+       display = task->security;
+       *display = LSMBLOB_INVALID;
+
        return 0;
 }
 
@@ -659,6 +699,28 @@ static int lsm_msg_msg_alloc(struct msg_msg *mp)
        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.
+ */
+static 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_early_task - during initialization allocate a composite task blob
  * @task: the task that needs a blob
@@ -751,24 +813,28 @@ int security_binder_set_context_mgr(struct task_struct *mgr)
 {
        return call_int_hook(binder_set_context_mgr, 0, mgr);
 }
+EXPORT_SYMBOL(security_binder_set_context_mgr);
 
 int security_binder_transaction(struct task_struct *from,
                                struct task_struct *to)
 {
        return call_int_hook(binder_transaction, 0, from, to);
 }
+EXPORT_SYMBOL(security_binder_transaction);
 
 int security_binder_transfer_binder(struct task_struct *from,
                                    struct task_struct *to)
 {
        return call_int_hook(binder_transfer_binder, 0, from, to);
 }
+EXPORT_SYMBOL(security_binder_transfer_binder);
 
 int security_binder_transfer_file(struct task_struct *from,
                                  struct task_struct *to, struct file *file)
 {
        return call_int_hook(binder_transfer_file, 0, from, to, file);
 }
+EXPORT_SYMBOL(security_binder_transfer_file);
 
 int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
@@ -1461,9 +1527,16 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
 }
 EXPORT_SYMBOL(security_inode_listsecurity);
 
-void security_inode_getsecid(struct inode *inode, u32 *secid)
+void security_inode_getsecid(struct inode *inode, struct lsmblob *blob)
 {
-       call_void_hook(inode_getsecid, inode, secid);
+       struct security_hook_list *hp;
+
+       lsmblob_init(blob, 0);
+       hlist_for_each_entry(hp, &security_hook_heads.inode_getsecid, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               hp->hook.inode_getsecid(inode, &blob->secid[hp->lsmid->slot]);
+       }
 }
 
 int security_inode_copy_up(struct dentry *src, struct cred **new)
@@ -1640,14 +1713,26 @@ int security_file_open(struct file *file)
 
 int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
 {
+       int *odisplay = current->security;
+       int *ndisplay;
        int rc = lsm_task_alloc(task);
 
-       if (rc)
+       if (unlikely(rc))
                return rc;
+
        rc = call_int_hook(task_alloc, 0, task, clone_flags);
-       if (unlikely(rc))
+       if (unlikely(rc)) {
                security_task_free(task);
-       return rc;
+               return rc;
+       }
+
+       if (odisplay) {
+               ndisplay = task->security;
+               if (ndisplay)
+                       *ndisplay = *odisplay;
+       }
+
+       return 0;
 }
 
 void security_task_free(struct task_struct *task)
@@ -1704,16 +1789,32 @@ void security_transfer_creds(struct cred *new, const struct cred *old)
        call_void_hook(cred_transfer, new, old);
 }
 
-void security_cred_getsecid(const struct cred *c, u32 *secid)
+void security_cred_getsecid(const struct cred *c, struct lsmblob *blob)
 {
-       *secid = 0;
-       call_void_hook(cred_getsecid, c, secid);
+       struct security_hook_list *hp;
+
+       lsmblob_init(blob, 0);
+       hlist_for_each_entry(hp, &security_hook_heads.cred_getsecid, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               hp->hook.cred_getsecid(c, &blob->secid[hp->lsmid->slot]);
+       }
 }
 EXPORT_SYMBOL(security_cred_getsecid);
 
-int security_kernel_act_as(struct cred *new, u32 secid)
+int security_kernel_act_as(struct cred *new, struct lsmblob *blob)
 {
-       return call_int_hook(kernel_act_as, 0, new, secid);
+       struct security_hook_list *hp;
+       int rc;
+
+       hlist_for_each_entry(hp, &security_hook_heads.kernel_act_as, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               rc = hp->hook.kernel_act_as(new, blob->secid[hp->lsmid->slot]);
+               if (rc != 0)
+                       return rc;
+       }
+       return 0;
 }
 
 int security_kernel_create_files_as(struct cred *new, struct inode *inode)
@@ -1807,17 +1908,29 @@ int security_task_getsid(struct task_struct *p)
        return call_int_hook(task_getsid, 0, p);
 }
 
-void security_task_getsecid_subj(struct task_struct *p, u32 *secid)
+void security_task_getsecid_subj(struct task_struct *p, struct lsmblob *blob)
 {
-       *secid = 0;
-       call_void_hook(task_getsecid_subj, p, secid);
+       struct security_hook_list *hp;
+
+       lsmblob_init(blob, 0);
+       hlist_for_each_entry(hp, &security_hook_heads.task_getsecid_subj, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               hp->hook.task_getsecid_subj(p, &blob->secid[hp->lsmid->slot]);
+       }
 }
 EXPORT_SYMBOL(security_task_getsecid_subj);
 
-void security_task_getsecid_obj(struct task_struct *p, u32 *secid)
+void security_task_getsecid_obj(struct task_struct *p, struct lsmblob *blob)
 {
-       *secid = 0;
-       call_void_hook(task_getsecid_obj, p, secid);
+       struct security_hook_list *hp;
+
+       lsmblob_init(blob, 0);
+       hlist_for_each_entry(hp, &security_hook_heads.task_getsecid_obj, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               hp->hook.task_getsecid_obj(p, &blob->secid[hp->lsmid->slot]);
+       }
 }
 EXPORT_SYMBOL(security_task_getsecid_obj);
 
@@ -1897,10 +2010,16 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
        return call_int_hook(ipc_permission, 0, ipcp, flag);
 }
 
-void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
+void security_ipc_getsecid(struct kern_ipc_perm *ipcp, struct lsmblob *blob)
 {
-       *secid = 0;
-       call_void_hook(ipc_getsecid, ipcp, secid);
+       struct security_hook_list *hp;
+
+       lsmblob_init(blob, 0);
+       hlist_for_each_entry(hp, &security_hook_heads.ipc_getsecid, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               hp->hook.ipc_getsecid(ipcp, &blob->secid[hp->lsmid->slot]);
+       }
 }
 
 int security_msg_msg_alloc(struct msg_msg *msg)
@@ -2044,22 +2163,109 @@ int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
                                char **value)
 {
        struct security_hook_list *hp;
+       int display = lsm_task_display(current);
+       int slot = 0;
+
+       if (!strcmp(name, "display")) {
+               /*
+                * lsm_slot will be 0 if there are no displaying modules.
+                */
+               if (lsm_slot == 0)
+                       return -EINVAL;
+
+               /*
+                * Only allow getting the current process' display.
+                * There are too few reasons to get another process'
+                * display and too many LSM policy issues.
+                */
+               if (current != p)
+                       return -EINVAL;
+
+               display = lsm_task_display(p);
+               if (display != LSMBLOB_INVALID)
+                       slot = display;
+               *value = kstrdup(lsm_slotlist[slot]->lsm, GFP_KERNEL);
+               if (*value)
+                       return strlen(*value);
+               return -ENOMEM;
+       }
 
        hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
-               if (lsm != NULL && strcmp(lsm, hp->lsm))
+               if (lsm != NULL && strcmp(lsm, hp->lsmid->lsm))
+                       continue;
+               if (lsm == NULL && display != LSMBLOB_INVALID &&
+                   display != hp->lsmid->slot)
                        continue;
                return hp->hook.getprocattr(p, name, value);
        }
        return LSM_RET_DEFAULT(getprocattr);
 }
 
+/**
+ * security_setprocattr - Set process attributes via /proc
+ * @lsm: name of module involved, or NULL
+ * @name: name of the attribute
+ * @value: value to set the attribute to
+ * @size: size of the value
+ *
+ * Set the process attribute for the specified security module
+ * to the specified value. Note that this can only be used to set
+ * the process attributes for the current, or "self" process.
+ * The /proc code has already done this check.
+ *
+ * Returns 0 on success, an appropriate code otherwise.
+ */
 int security_setprocattr(const char *lsm, const char *name, void *value,
                         size_t size)
 {
        struct security_hook_list *hp;
+       char *termed;
+       char *copy;
+       int *display = current->security;
+       int rc = -EINVAL;
+       int slot = 0;
+
+       if (!strcmp(name, "display")) {
+               /*
+                * Change the "display" value only if all the security
+                * modules that support setting a procattr allow it.
+                * It is assumed that all such security modules will be
+                * cooperative.
+                */
+               if (size == 0)
+                       return -EINVAL;
+
+               hlist_for_each_entry(hp, &security_hook_heads.setprocattr,
+                                    list) {
+                       rc = hp->hook.setprocattr(name, value, size);
+                       if (rc < 0)
+                               return rc;
+               }
+
+               rc = -EINVAL;
+
+               copy = kmemdup_nul(value, size, GFP_KERNEL);
+               if (copy == NULL)
+                       return -ENOMEM;
+
+               termed = strsep(&copy, " \n");
+
+               for (slot = 0; slot < lsm_slot; slot++)
+                       if (!strcmp(termed, lsm_slotlist[slot]->lsm)) {
+                               *display = lsm_slotlist[slot]->slot;
+                               rc = size;
+                               break;
+                       }
+
+               kfree(termed);
+               return rc;
+       }
 
        hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
-               if (lsm != NULL && strcmp(lsm, hp->lsm))
+               if (lsm != NULL && strcmp(lsm, hp->lsmid->lsm))
+                       continue;
+               if (lsm == NULL && *display != LSMBLOB_INVALID &&
+                   *display != hp->lsmid->slot)
                        continue;
                return hp->hook.setprocattr(name, value, size);
        }
@@ -2077,35 +2283,57 @@ int security_ismaclabel(const char *name)
 }
 EXPORT_SYMBOL(security_ismaclabel);
 
-int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
+int security_secid_to_secctx(struct lsmblob *blob, struct lsmcontext *cp)
 {
        struct security_hook_list *hp;
-       int rc;
+       int display = lsm_task_display(current);
+
+       memset(cp, 0, sizeof(*cp));
 
-       /*
-        * Currently, only one LSM can implement secid_to_secctx (i.e this
-        * LSM hook is not "stackable").
-        */
        hlist_for_each_entry(hp, &security_hook_heads.secid_to_secctx, list) {
-               rc = hp->hook.secid_to_secctx(secid, secdata, seclen);
-               if (rc != LSM_RET_DEFAULT(secid_to_secctx))
-                       return rc;
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               if (display == LSMBLOB_INVALID || display == hp->lsmid->slot) {
+                       cp->slot = hp->lsmid->slot;
+                       return hp->hook.secid_to_secctx(
+                                       blob->secid[hp->lsmid->slot],
+                                       &cp->context, &cp->len);
+               }
        }
 
        return LSM_RET_DEFAULT(secid_to_secctx);
 }
 EXPORT_SYMBOL(security_secid_to_secctx);
 
-int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
+int security_secctx_to_secid(const char *secdata, u32 seclen,
+                            struct lsmblob *blob)
 {
-       *secid = 0;
-       return call_int_hook(secctx_to_secid, 0, secdata, seclen, secid);
+       struct security_hook_list *hp;
+       int display = lsm_task_display(current);
+
+       lsmblob_init(blob, 0);
+       hlist_for_each_entry(hp, &security_hook_heads.secctx_to_secid, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               if (display == LSMBLOB_INVALID || display == hp->lsmid->slot)
+                       return hp->hook.secctx_to_secid(secdata, seclen,
+                                               &blob->secid[hp->lsmid->slot]);
+       }
+       return 0;
 }
 EXPORT_SYMBOL(security_secctx_to_secid);
 
-void security_release_secctx(char *secdata, u32 seclen)
+void security_release_secctx(struct lsmcontext *cp)
 {
-       call_void_hook(release_secctx, secdata, seclen);
+       struct security_hook_list *hp;
+
+       hlist_for_each_entry(hp, &security_hook_heads.release_secctx, list)
+               if (cp->slot == hp->lsmid->slot) {
+                       hp->hook.release_secctx(cp->context, cp->len);
+                       break;
+               }
+
+       memset(cp, 0, sizeof(*cp));
 }
 EXPORT_SYMBOL(security_release_secctx);
 
@@ -2127,9 +2355,18 @@ int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
 }
 EXPORT_SYMBOL(security_inode_setsecctx);
 
-int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
+int security_inode_getsecctx(struct inode *inode, struct lsmcontext *cp)
 {
-       return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen);
+       struct security_hook_list *hp;
+
+       memset(cp, 0, sizeof(*cp));
+
+       hlist_for_each_entry(hp, &security_hook_heads.inode_getsecctx, list) {
+               cp->slot = hp->lsmid->slot;
+               return hp->hook.inode_getsecctx(inode, (void **)&cp->context,
+                                               &cp->len);
+       }
+       return -EOPNOTSUPP;
 }
 EXPORT_SYMBOL(security_inode_getsecctx);
 
@@ -2246,25 +2483,53 @@ EXPORT_SYMBOL(security_sock_rcv_skb);
 int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
                                      int __user *optlen, unsigned len)
 {
-       return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
-                               optval, optlen, len);
+       int display = lsm_task_display(current);
+       struct security_hook_list *hp;
+
+       hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_stream,
+                            list)
+               if (display == LSMBLOB_INVALID || display == hp->lsmid->slot)
+                       return hp->hook.socket_getpeersec_stream(sock, optval,
+                                                                optlen, len);
+       return -ENOPROTOOPT;
 }
 
-int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
+int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb,
+                                    struct lsmblob *blob)
 {
-       return call_int_hook(socket_getpeersec_dgram, -ENOPROTOOPT, sock,
-                            skb, secid);
+       struct security_hook_list *hp;
+       int rc = -ENOPROTOOPT;
+
+       hlist_for_each_entry(hp, &security_hook_heads.socket_getpeersec_dgram,
+                            list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               rc = hp->hook.socket_getpeersec_dgram(sock, skb,
+                                               &blob->secid[hp->lsmid->slot]);
+               if (rc != 0)
+                       break;
+       }
+       return rc;
 }
 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)
@@ -2312,9 +2577,21 @@ void security_inet_conn_established(struct sock *sk,
 }
 EXPORT_SYMBOL(security_inet_conn_established);
 
-int security_secmark_relabel_packet(u32 secid)
+int security_secmark_relabel_packet(struct lsmblob *blob)
 {
-       return call_int_hook(secmark_relabel_packet, 0, secid);
+       struct security_hook_list *hp;
+       int rc = 0;
+
+       hlist_for_each_entry(hp, &security_hook_heads.secmark_relabel_packet,
+                            list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               rc = hp->hook.secmark_relabel_packet(
+                                               blob->secid[hp->lsmid->slot]);
+               if (rc != 0)
+                       break;
+       }
+       return rc;
 }
 EXPORT_SYMBOL(security_secmark_relabel_packet);
 
@@ -2543,7 +2820,24 @@ int security_key_getsecurity(struct key *key, char **_buffer)
 
 int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
 {
-       return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
+       struct security_hook_list *hp;
+       bool one_is_good = false;
+       int rc = 0;
+       int trc;
+
+       hlist_for_each_entry(hp, &security_hook_heads.audit_rule_init, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               trc = hp->hook.audit_rule_init(field, op, rulestr,
+                                              &lsmrule[hp->lsmid->slot]);
+               if (trc == 0)
+                       one_is_good = true;
+               else
+                       rc = trc;
+       }
+       if (one_is_good)
+               return 0;
+       return rc;
 }
 
 int security_audit_rule_known(struct audit_krule *krule)
@@ -2551,14 +2845,37 @@ int security_audit_rule_known(struct audit_krule *krule)
        return call_int_hook(audit_rule_known, 0, krule);
 }
 
-void security_audit_rule_free(void *lsmrule)
+void security_audit_rule_free(void **lsmrule)
 {
-       call_void_hook(audit_rule_free, lsmrule);
+       struct security_hook_list *hp;
+
+       hlist_for_each_entry(hp, &security_hook_heads.audit_rule_free, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               if (lsmrule[hp->lsmid->slot] == NULL)
+                       continue;
+               hp->hook.audit_rule_free(lsmrule[hp->lsmid->slot]);
+       }
 }
 
-int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
+int security_audit_rule_match(struct lsmblob *blob, u32 field, u32 op,
+                             void **lsmrule)
 {
-       return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
+       struct security_hook_list *hp;
+       int rc;
+
+       hlist_for_each_entry(hp, &security_hook_heads.audit_rule_match, list) {
+               if (WARN_ON(hp->lsmid->slot < 0 || hp->lsmid->slot >= lsm_slot))
+                       continue;
+               if (lsmrule[hp->lsmid->slot] == NULL)
+                       continue;
+               rc = hp->hook.audit_rule_match(blob->secid[hp->lsmid->slot],
+                                              field, op,
+                                              &lsmrule[hp->lsmid->slot]);
+               if (rc)
+                       return rc;
+       }
+       return 0;
 }
 #endif /* CONFIG_AUDIT */