Linux 6.9-rc5
[sfrench/cifs-2.6.git] / kernel / auditsc.c
index 95ae27edd4174d087478d209b9512bae8fd40fbc..6f0d6fb6523fa76fea59ebe32dd68def39d449c0 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /* auditsc.c -- System-call auditing support
  * Handles all system-call specific auditing features.
  *
@@ -6,20 +7,6 @@
  * Copyright (C) 2005, 2006 IBM Corporation
  * All Rights Reserved.
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  * Written by Rickard E. (Rik) Faith <faith@redhat.com>
  *
  * Many of the ideas implemented here are from Stephen C. Tweedie,
@@ -75,6 +62,9 @@
 #include <linux/uaccess.h>
 #include <linux/fsnotify_backend.h>
 #include <uapi/linux/limits.h>
+#include <uapi/linux/netfilter/nf_tables.h>
+#include <uapi/linux/openat2.h> // struct open_how
+#include <uapi/linux/fanotify.h>
 
 #include "audit.h"
 
@@ -101,8 +91,6 @@ struct audit_aux_data {
        int                     type;
 };
 
-#define AUDIT_AUX_IPCPERM      0
-
 /* Number of target pids per aux struct. */
 #define AUDIT_AUX_PIDS 16
 
@@ -130,15 +118,46 @@ struct audit_tree_refs {
        struct audit_chunk *c[31];
 };
 
+struct audit_nfcfgop_tab {
+       enum audit_nfcfgop      op;
+       const char              *s;
+};
+
+static const struct audit_nfcfgop_tab audit_nfcfgs[] = {
+       { AUDIT_XT_OP_REGISTER,                 "xt_register"              },
+       { AUDIT_XT_OP_REPLACE,                  "xt_replace"               },
+       { AUDIT_XT_OP_UNREGISTER,               "xt_unregister"            },
+       { AUDIT_NFT_OP_TABLE_REGISTER,          "nft_register_table"       },
+       { AUDIT_NFT_OP_TABLE_UNREGISTER,        "nft_unregister_table"     },
+       { AUDIT_NFT_OP_CHAIN_REGISTER,          "nft_register_chain"       },
+       { AUDIT_NFT_OP_CHAIN_UNREGISTER,        "nft_unregister_chain"     },
+       { AUDIT_NFT_OP_RULE_REGISTER,           "nft_register_rule"        },
+       { AUDIT_NFT_OP_RULE_UNREGISTER,         "nft_unregister_rule"      },
+       { AUDIT_NFT_OP_SET_REGISTER,            "nft_register_set"         },
+       { AUDIT_NFT_OP_SET_UNREGISTER,          "nft_unregister_set"       },
+       { AUDIT_NFT_OP_SETELEM_REGISTER,        "nft_register_setelem"     },
+       { AUDIT_NFT_OP_SETELEM_UNREGISTER,      "nft_unregister_setelem"   },
+       { AUDIT_NFT_OP_GEN_REGISTER,            "nft_register_gen"         },
+       { AUDIT_NFT_OP_OBJ_REGISTER,            "nft_register_obj"         },
+       { AUDIT_NFT_OP_OBJ_UNREGISTER,          "nft_unregister_obj"       },
+       { AUDIT_NFT_OP_OBJ_RESET,               "nft_reset_obj"            },
+       { AUDIT_NFT_OP_FLOWTABLE_REGISTER,      "nft_register_flowtable"   },
+       { AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,    "nft_unregister_flowtable" },
+       { AUDIT_NFT_OP_SETELEM_RESET,           "nft_reset_setelem"        },
+       { AUDIT_NFT_OP_RULE_RESET,              "nft_reset_rule"           },
+       { AUDIT_NFT_OP_INVALID,                 "nft_invalid"              },
+};
+
 static int audit_match_perm(struct audit_context *ctx, int mask)
 {
        unsigned n;
+
        if (unlikely(!ctx))
                return 0;
        n = ctx->major;
 
        switch (audit_classify_syscall(ctx->arch, n)) {
-       case 0: /* native */
+       case AUDITSC_NATIVE:
                if ((mask & AUDIT_PERM_WRITE) &&
                     audit_match_class(AUDIT_CLASS_WRITE, n))
                        return 1;
@@ -149,7 +168,7 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
                     audit_match_class(AUDIT_CLASS_CHATTR, n))
                        return 1;
                return 0;
-       case 1: /* 32bit on biarch */
+       case AUDITSC_COMPAT: /* 32bit on biarch */
                if ((mask & AUDIT_PERM_WRITE) &&
                     audit_match_class(AUDIT_CLASS_WRITE_32, n))
                        return 1;
@@ -160,14 +179,16 @@ static int audit_match_perm(struct audit_context *ctx, int mask)
                     audit_match_class(AUDIT_CLASS_CHATTR_32, n))
                        return 1;
                return 0;
-       case 2: /* open */
+       case AUDITSC_OPEN:
                return mask & ACC_MODE(ctx->argv[1]);
-       case 3: /* openat */
+       case AUDITSC_OPENAT:
                return mask & ACC_MODE(ctx->argv[2]);
-       case 4: /* socketcall */
+       case AUDITSC_SOCKETCALL:
                return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == SYS_BIND);
-       case 5: /* execve */
+       case AUDITSC_EXECVE:
                return mask & AUDIT_PERM_EXEC;
+       case AUDITSC_OPENAT2:
+               return mask & ACC_MODE((u32)ctx->openat2.flags);
        default:
                return 0;
        }
@@ -204,7 +225,7 @@ static void audit_set_auditable(struct audit_context *ctx)
 {
        if (!ctx->prio) {
                ctx->prio = 1;
-               ctx->current_state = AUDIT_RECORD_CONTEXT;
+               ctx->current_state = AUDIT_STATE_RECORD;
        }
 }
 
@@ -212,6 +233,7 @@ static int put_tree_ref(struct audit_context *ctx, struct audit_chunk *chunk)
 {
        struct audit_tree_refs *p = ctx->trees;
        int left = ctx->tree_count;
+
        if (likely(left)) {
                p->c[--left] = chunk;
                ctx->tree_count = left;
@@ -232,6 +254,7 @@ static int put_tree_ref(struct audit_context *ctx, struct audit_chunk *chunk)
 static int grow_tree_refs(struct audit_context *ctx)
 {
        struct audit_tree_refs *p = ctx->trees;
+
        ctx->trees = kzalloc(sizeof(struct audit_tree_refs), GFP_KERNEL);
        if (!ctx->trees) {
                ctx->trees = p;
@@ -250,6 +273,7 @@ static void unroll_tree_refs(struct audit_context *ctx,
 {
        struct audit_tree_refs *q;
        int n;
+
        if (!p) {
                /* we started with empty chain */
                p = ctx->first_trees;
@@ -276,6 +300,7 @@ static void unroll_tree_refs(struct audit_context *ctx,
 static void free_tree_refs(struct audit_context *ctx)
 {
        struct audit_tree_refs *p, *q;
+
        for (p = ctx->first_trees; p; p = q) {
                q = p->next;
                kfree(p);
@@ -286,6 +311,7 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)
 {
        struct audit_tree_refs *p;
        int n;
+
        if (!tree)
                return 0;
        /* full ones */
@@ -310,13 +336,13 @@ static int audit_compare_uid(kuid_t uid,
 {
        struct audit_names *n;
        int rc;
+
        if (name) {
                rc = audit_uid_comparator(uid, f->op, name->uid);
                if (rc)
                        return rc;
        }
+
        if (ctx) {
                list_for_each_entry(n, &ctx->names_list, list) {
                        rc = audit_uid_comparator(uid, f->op, n->uid);
@@ -334,13 +360,13 @@ static int audit_compare_gid(kgid_t gid,
 {
        struct audit_names *n;
        int rc;
+
        if (name) {
                rc = audit_gid_comparator(gid, f->op, name->gid);
                if (rc)
                        return rc;
        }
+
        if (ctx) {
                list_for_each_entry(n, &ctx->names_list, list) {
                        rc = audit_gid_comparator(gid, f->op, n->gid);
@@ -447,6 +473,9 @@ static int audit_filter_rules(struct task_struct *tsk,
        u32 sid;
        unsigned int sessionid;
 
+       if (ctx && rule->prio <= ctx->prio)
+               return 0;
+
        cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation);
 
        for (i = 0; i < rule->field_count; i++) {
@@ -523,11 +552,11 @@ static int audit_filter_rules(struct task_struct *tsk,
                        break;
 
                case AUDIT_EXIT:
-                       if (ctx && ctx->return_valid)
+                       if (ctx && ctx->return_valid != AUDITSC_INVALID)
                                result = audit_comparator(ctx->return_code, f->op, f->val);
                        break;
                case AUDIT_SUCCESS:
-                       if (ctx && ctx->return_valid) {
+                       if (ctx && ctx->return_valid != AUDITSC_INVALID) {
                                if (f->val)
                                        result = audit_comparator(ctx->return_valid, f->op, AUDITSC_SUCCESS);
                                else
@@ -601,12 +630,20 @@ static int audit_filter_rules(struct task_struct *tsk,
                        }
                        break;
                case AUDIT_WATCH:
-                       if (name)
-                               result = audit_watch_compare(rule->watch, name->ino, name->dev);
+                       if (name) {
+                               result = audit_watch_compare(rule->watch,
+                                                            name->ino,
+                                                            name->dev);
+                               if (f->op == Audit_not_equal)
+                                       result = !result;
+                       }
                        break;
                case AUDIT_DIR:
-                       if (ctx)
+                       if (ctx) {
                                result = match_tree_refs(ctx, rule->tree);
+                               if (f->op == Audit_not_equal)
+                                       result = !result;
+                       }
                        break;
                case AUDIT_LOGINUID:
                        result = audit_uid_comparator(audit_get_loginuid(tsk),
@@ -615,6 +652,11 @@ static int audit_filter_rules(struct task_struct *tsk,
                case AUDIT_LOGINUID_SET:
                        result = audit_comparator(audit_loginuid_set(tsk), f->op, f->val);
                        break;
+               case AUDIT_SADDR_FAM:
+                       if (ctx && ctx->sockaddr)
+                               result = audit_comparator(ctx->sockaddr->ss_family,
+                                                         f->op, f->val);
+                       break;
                case AUDIT_SUBJ_USER:
                case AUDIT_SUBJ_ROLE:
                case AUDIT_SUBJ_TYPE:
@@ -627,7 +669,16 @@ static int audit_filter_rules(struct task_struct *tsk,
                           logged upon error */
                        if (f->lsm_rule) {
                                if (need_sid) {
-                                       security_task_getsecid(tsk, &sid);
+                                       /* @tsk should always be equal to
+                                        * @current with the exception of
+                                        * fork()/copy_process() in which case
+                                        * the new @tsk creds are still a dup
+                                        * of @current's creds so we can still
+                                        * use security_current_getsecid_subj()
+                                        * here even though it always refs
+                                        * @current's creds
+                                        */
+                                       security_current_getsecid_subj(&sid);
                                        need_sid = 0;
                                }
                                result = security_audit_rule_match(sid, f->type,
@@ -684,9 +735,13 @@ static int audit_filter_rules(struct task_struct *tsk,
                        break;
                case AUDIT_PERM:
                        result = audit_match_perm(ctx, f->val);
+                       if (f->op == Audit_not_equal)
+                               result = !result;
                        break;
                case AUDIT_FILETYPE:
                        result = audit_match_filetype(ctx, f->val);
+                       if (f->op == Audit_not_equal)
+                               result = !result;
                        break;
                case AUDIT_FIELD_COMPARE:
                        result = audit_field_compare(tsk, cred, f, ctx, name);
@@ -697,8 +752,6 @@ static int audit_filter_rules(struct task_struct *tsk,
        }
 
        if (ctx) {
-               if (rule->prio <= ctx->prio)
-                       return 0;
                if (rule->filterkey) {
                        kfree(ctx->filterkey);
                        ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC);
@@ -707,10 +760,10 @@ static int audit_filter_rules(struct task_struct *tsk,
        }
        switch (rule->action) {
        case AUDIT_NEVER:
-               *state = AUDIT_DISABLED;
+               *state = AUDIT_STATE_DISABLED;
                break;
        case AUDIT_ALWAYS:
-               *state = AUDIT_RECORD_CONTEXT;
+               *state = AUDIT_STATE_RECORD;
                break;
        }
        return 1;
@@ -729,14 +782,14 @@ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)
        list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) {
                if (audit_filter_rules(tsk, &e->rule, NULL, NULL,
                                       &state, true)) {
-                       if (state == AUDIT_RECORD_CONTEXT)
+                       if (state == AUDIT_STATE_RECORD)
                                *key = kstrdup(e->rule.filterkey, GFP_ATOMIC);
                        rcu_read_unlock();
                        return state;
                }
        }
        rcu_read_unlock();
-       return AUDIT_BUILD_CONTEXT;
+       return AUDIT_STATE_BUILD;
 }
 
 static int audit_in_mask(const struct audit_krule *rule, unsigned long val)
@@ -755,33 +808,72 @@ static int audit_in_mask(const struct audit_krule *rule, unsigned long val)
        return rule->mask[word] & bit;
 }
 
-/* At syscall entry and exit time, this filter is called if the
- * audit_state is not low enough that auditing cannot take place, but is
- * also not high enough that we already know we have to write an audit
- * record (i.e., the state is AUDIT_SETUP_CONTEXT or AUDIT_BUILD_CONTEXT).
+/**
+ * __audit_filter_op - common filter helper for operations (syscall/uring/etc)
+ * @tsk: associated task
+ * @ctx: audit context
+ * @list: audit filter list
+ * @name: audit_name (can be NULL)
+ * @op: current syscall/uring_op
+ *
+ * Run the udit filters specified in @list against @tsk using @ctx,
+ * @name, and @op, as necessary; the caller is responsible for ensuring
+ * that the call is made while the RCU read lock is held. The @name
+ * parameter can be NULL, but all others must be specified.
+ * Returns 1/true if the filter finds a match, 0/false if none are found.
  */
-static enum audit_state audit_filter_syscall(struct task_struct *tsk,
-                                            struct audit_context *ctx,
-                                            struct list_head *list)
+static int __audit_filter_op(struct task_struct *tsk,
+                          struct audit_context *ctx,
+                          struct list_head *list,
+                          struct audit_names *name,
+                          unsigned long op)
 {
        struct audit_entry *e;
        enum audit_state state;
 
-       if (auditd_test_task(tsk))
-               return AUDIT_DISABLED;
-
-       rcu_read_lock();
        list_for_each_entry_rcu(e, list, list) {
-               if (audit_in_mask(&e->rule, ctx->major) &&
-                   audit_filter_rules(tsk, &e->rule, ctx, NULL,
+               if (audit_in_mask(&e->rule, op) &&
+                   audit_filter_rules(tsk, &e->rule, ctx, name,
                                       &state, false)) {
-                       rcu_read_unlock();
                        ctx->current_state = state;
-                       return state;
+                       return 1;
                }
        }
+       return 0;
+}
+
+/**
+ * audit_filter_uring - apply filters to an io_uring operation
+ * @tsk: associated task
+ * @ctx: audit context
+ */
+static void audit_filter_uring(struct task_struct *tsk,
+                              struct audit_context *ctx)
+{
+       if (auditd_test_task(tsk))
+               return;
+
+       rcu_read_lock();
+       __audit_filter_op(tsk, ctx, &audit_filter_list[AUDIT_FILTER_URING_EXIT],
+                       NULL, ctx->uring_op);
+       rcu_read_unlock();
+}
+
+/* At syscall exit time, this filter is called if the audit_state is
+ * not low enough that auditing cannot take place, but is also not
+ * high enough that we already know we have to write an audit record
+ * (i.e., the state is AUDIT_STATE_BUILD).
+ */
+static void audit_filter_syscall(struct task_struct *tsk,
+                                struct audit_context *ctx)
+{
+       if (auditd_test_task(tsk))
+               return;
+
+       rcu_read_lock();
+       __audit_filter_op(tsk, ctx, &audit_filter_list[AUDIT_FILTER_EXIT],
+                       NULL, ctx->major);
        rcu_read_unlock();
-       return AUDIT_BUILD_CONTEXT;
 }
 
 /*
@@ -790,20 +882,12 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,
  */
 static int audit_filter_inode_name(struct task_struct *tsk,
                                   struct audit_names *n,
-                                  struct audit_context *ctx) {
+                                  struct audit_context *ctx)
+{
        int h = audit_hash_ino((u32)n->ino);
        struct list_head *list = &audit_inode_hash[h];
-       struct audit_entry *e;
-       enum audit_state state;
 
-       list_for_each_entry_rcu(e, list, list) {
-               if (audit_in_mask(&e->rule, ctx->major) &&
-                   audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) {
-                       ctx->current_state = state;
-                       return 1;
-               }
-       }
-       return 0;
+       return __audit_filter_op(tsk, ctx, list, n, ctx->major);
 }
 
 /* At syscall exit time, this filter is called if any audit_names have been
@@ -866,10 +950,80 @@ static inline void audit_free_aux(struct audit_context *context)
                context->aux = aux->next;
                kfree(aux);
        }
+       context->aux = NULL;
        while ((aux = context->aux_pids)) {
                context->aux_pids = aux->next;
                kfree(aux);
        }
+       context->aux_pids = NULL;
+}
+
+/**
+ * audit_reset_context - reset a audit_context structure
+ * @ctx: the audit_context to reset
+ *
+ * All fields in the audit_context will be reset to an initial state, all
+ * references held by fields will be dropped, and private memory will be
+ * released.  When this function returns the audit_context will be suitable
+ * for reuse, so long as the passed context is not NULL or a dummy context.
+ */
+static void audit_reset_context(struct audit_context *ctx)
+{
+       if (!ctx)
+               return;
+
+       /* if ctx is non-null, reset the "ctx->context" regardless */
+       ctx->context = AUDIT_CTX_UNUSED;
+       if (ctx->dummy)
+               return;
+
+       /*
+        * NOTE: It shouldn't matter in what order we release the fields, so
+        *       release them in the order in which they appear in the struct;
+        *       this gives us some hope of quickly making sure we are
+        *       resetting the audit_context properly.
+        *
+        *       Other things worth mentioning:
+        *       - we don't reset "dummy"
+        *       - we don't reset "state", we do reset "current_state"
+        *       - we preserve "filterkey" if "state" is AUDIT_STATE_RECORD
+        *       - much of this is likely overkill, but play it safe for now
+        *       - we really need to work on improving the audit_context struct
+        */
+
+       ctx->current_state = ctx->state;
+       ctx->serial = 0;
+       ctx->major = 0;
+       ctx->uring_op = 0;
+       ctx->ctime = (struct timespec64){ .tv_sec = 0, .tv_nsec = 0 };
+       memset(ctx->argv, 0, sizeof(ctx->argv));
+       ctx->return_code = 0;
+       ctx->prio = (ctx->state == AUDIT_STATE_RECORD ? ~0ULL : 0);
+       ctx->return_valid = AUDITSC_INVALID;
+       audit_free_names(ctx);
+       if (ctx->state != AUDIT_STATE_RECORD) {
+               kfree(ctx->filterkey);
+               ctx->filterkey = NULL;
+       }
+       audit_free_aux(ctx);
+       kfree(ctx->sockaddr);
+       ctx->sockaddr = NULL;
+       ctx->sockaddr_len = 0;
+       ctx->ppid = 0;
+       ctx->uid = ctx->euid = ctx->suid = ctx->fsuid = KUIDT_INIT(0);
+       ctx->gid = ctx->egid = ctx->sgid = ctx->fsgid = KGIDT_INIT(0);
+       ctx->personality = 0;
+       ctx->arch = 0;
+       ctx->target_pid = 0;
+       ctx->target_auid = ctx->target_uid = KUIDT_INIT(0);
+       ctx->target_sessionid = 0;
+       ctx->target_sid = 0;
+       ctx->target_comm[0] = '\0';
+       unroll_tree_refs(ctx, NULL, 0);
+       WARN_ON(!list_empty(&ctx->killed_trees));
+       audit_free_module(ctx);
+       ctx->fds[0] = -1;
+       ctx->type = 0; /* reset last for audit_free_*() */
 }
 
 static inline struct audit_context *audit_alloc_context(enum audit_state state)
@@ -879,10 +1033,13 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state)
        context = kzalloc(sizeof(*context), GFP_KERNEL);
        if (!context)
                return NULL;
+       context->context = AUDIT_CTX_UNUSED;
        context->state = state;
-       context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
+       context->prio = state == AUDIT_STATE_RECORD ? ~0ULL : 0;
        INIT_LIST_HEAD(&context->killed_trees);
        INIT_LIST_HEAD(&context->names_list);
+       context->fds[0] = -1;
+       context->return_valid = AUDITSC_INVALID;
        return context;
 }
 
@@ -902,15 +1059,16 @@ int audit_alloc(struct task_struct *tsk)
        char *key = NULL;
 
        if (likely(!audit_ever_enabled))
-               return 0; /* Return if not auditing. */
+               return 0;
 
        state = audit_filter_task(tsk, &key);
-       if (state == AUDIT_DISABLED) {
-               clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
+       if (state == AUDIT_STATE_DISABLED) {
+               clear_task_syscall_work(tsk, SYSCALL_AUDIT);
                return 0;
        }
 
-       if (!(context = audit_alloc_context(state))) {
+       context = audit_alloc_context(state);
+       if (!context) {
                kfree(key);
                audit_log_lost("out of memory in audit_alloc");
                return -ENOMEM;
@@ -918,20 +1076,17 @@ int audit_alloc(struct task_struct *tsk)
        context->filterkey = key;
 
        audit_set_context(tsk, context);
-       set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
+       set_task_syscall_work(tsk, SYSCALL_AUDIT);
        return 0;
 }
 
 static inline void audit_free_context(struct audit_context *context)
 {
-       audit_free_module(context);
-       audit_free_names(context);
-       unroll_tree_refs(context, NULL, 0);
+       /* resetting is extra work, but it is likely just noise */
+       audit_reset_context(context);
+       audit_proctitle_free(context);
        free_tree_refs(context);
-       audit_free_aux(context);
        kfree(context->filterkey);
-       kfree(context->sockaddr);
-       audit_proctitle_free(context);
        kfree(context);
 }
 
@@ -1144,15 +1299,11 @@ out:
 static void audit_log_cap(struct audit_buffer *ab, char *prefix,
                          kernel_cap_t *cap)
 {
-       int i;
-
        if (cap_isclear(*cap)) {
                audit_log_format(ab, " %s=0", prefix);
                return;
        }
-       audit_log_format(ab, " %s=", prefix);
-       CAP_FOR_EACH_U32(i)
-               audit_log_format(ab, "%08x", cap->cap[CAP_LAST_U32 - i]);
+       audit_log_format(ab, " %s=%016llx", prefix, cap->val);
 }
 
 static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
@@ -1168,6 +1319,53 @@ static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name)
                         from_kuid(&init_user_ns, name->fcap.rootid));
 }
 
+static void audit_log_time(struct audit_context *context, struct audit_buffer **ab)
+{
+       const struct audit_ntp_data *ntp = &context->time.ntp_data;
+       const struct timespec64 *tk = &context->time.tk_injoffset;
+       static const char * const ntp_name[] = {
+               "offset",
+               "freq",
+               "status",
+               "tai",
+               "tick",
+               "adjust",
+       };
+       int type;
+
+       if (context->type == AUDIT_TIME_ADJNTPVAL) {
+               for (type = 0; type < AUDIT_NTP_NVALS; type++) {
+                       if (ntp->vals[type].newval != ntp->vals[type].oldval) {
+                               if (!*ab) {
+                                       *ab = audit_log_start(context,
+                                                       GFP_KERNEL,
+                                                       AUDIT_TIME_ADJNTPVAL);
+                                       if (!*ab)
+                                               return;
+                               }
+                               audit_log_format(*ab, "op=%s old=%lli new=%lli",
+                                                ntp_name[type],
+                                                ntp->vals[type].oldval,
+                                                ntp->vals[type].newval);
+                               audit_log_end(*ab);
+                               *ab = NULL;
+                       }
+               }
+       }
+       if (tk->tv_sec != 0 || tk->tv_nsec != 0) {
+               if (!*ab) {
+                       *ab = audit_log_start(context, GFP_KERNEL,
+                                             AUDIT_TIME_INJOFFSET);
+                       if (!*ab)
+                               return;
+               }
+               audit_log_format(*ab, "sec=%lli nsec=%li",
+                                (long long)tk->tv_sec, tk->tv_nsec);
+               audit_log_end(*ab);
+               *ab = NULL;
+       }
+}
+
 static void show_special(struct audit_context *context, int *call_panic)
 {
        struct audit_buffer *ab;
@@ -1180,6 +1378,7 @@ static void show_special(struct audit_context *context, int *call_panic)
        switch (context->type) {
        case AUDIT_SOCKETCALL: {
                int nargs = context->socketcall.nargs;
+
                audit_log_format(ab, "nargs=%d", nargs);
                for (i = 0; i < nargs; i++)
                        audit_log_format(ab, " a%d=%lx", i,
@@ -1195,6 +1394,7 @@ static void show_special(struct audit_context *context, int *call_panic)
                if (osid) {
                        char *ctx = NULL;
                        u32 len;
+
                        if (security_secid_to_secctx(osid, &ctx, &len)) {
                                audit_log_format(ab, " osid=%u", osid);
                                *call_panic = 1;
@@ -1244,6 +1444,7 @@ static void show_special(struct audit_context *context, int *call_panic)
                break;
        case AUDIT_MQ_GETSETATTR: {
                struct mq_attr *attr = &context->mq_getsetattr.mqstat;
+
                audit_log_format(ab,
                        "mqdes=%d mq_flags=0x%lx mq_maxmsg=%ld mq_msgsize=%ld "
                        "mq_curmsgs=%ld ",
@@ -1262,6 +1463,12 @@ static void show_special(struct audit_context *context, int *call_panic)
                audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd,
                                 context->mmap.flags);
                break;
+       case AUDIT_OPENAT2:
+               audit_log_format(ab, "oflag=0%llo mode=0%llo resolve=0x%llx",
+                                context->openat2.flags,
+                                context->openat2.mode,
+                                context->openat2.resolve);
+               break;
        case AUDIT_EXECVE:
                audit_log_execve_info(context, &ab);
                break;
@@ -1273,6 +1480,11 @@ static void show_special(struct audit_context *context, int *call_panic)
                        audit_log_format(ab, "(null)");
 
                break;
+       case AUDIT_TIME_ADJNTPVAL:
+       case AUDIT_TIME_INJOFFSET:
+               /* this call deviates from the rest, eating the buffer */
+               audit_log_time(context, &ab);
+               break;
        }
        audit_log_end(ab);
 }
@@ -1280,6 +1492,7 @@ static void show_special(struct audit_context *context, int *call_panic)
 static inline int audit_proctitle_rtrim(char *proctitle, int len)
 {
        char *end = proctitle + len - 1;
+
        while (end > proctitle && !isprint(*end))
                end--;
 
@@ -1321,7 +1534,10 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
                        /* name was specified as a relative path and the
                         * directory component is the cwd
                         */
-                       audit_log_d_path(ab, " name=", &context->pwd);
+                       if (context->pwd.dentry && context->pwd.mnt)
+                               audit_log_d_path(ab, " name=", &context->pwd);
+                       else
+                               audit_log_format(ab, " name=(null)");
                        break;
                default:
                        /* log the name's directory component */
@@ -1389,9 +1605,6 @@ static void audit_log_proctitle(void)
        struct audit_context *context = audit_context();
        struct audit_buffer *ab;
 
-       if (!context || context->dummy)
-               return;
-
        ab = audit_log_start(context, GFP_KERNEL, AUDIT_PROCTITLE);
        if (!ab)
                return; /* audit_panic or being filtered */
@@ -1424,6 +1637,44 @@ out:
        audit_log_end(ab);
 }
 
+/**
+ * audit_log_uring - generate a AUDIT_URINGOP record
+ * @ctx: the audit context
+ */
+static void audit_log_uring(struct audit_context *ctx)
+{
+       struct audit_buffer *ab;
+       const struct cred *cred;
+
+       ab = audit_log_start(ctx, GFP_ATOMIC, AUDIT_URINGOP);
+       if (!ab)
+               return;
+       cred = current_cred();
+       audit_log_format(ab, "uring_op=%d", ctx->uring_op);
+       if (ctx->return_valid != AUDITSC_INVALID)
+               audit_log_format(ab, " success=%s exit=%ld",
+                                (ctx->return_valid == AUDITSC_SUCCESS ?
+                                 "yes" : "no"),
+                                ctx->return_code);
+       audit_log_format(ab,
+                        " items=%d"
+                        " ppid=%d pid=%d uid=%u gid=%u euid=%u suid=%u"
+                        " fsuid=%u egid=%u sgid=%u fsgid=%u",
+                        ctx->name_count,
+                        task_ppid_nr(current), task_tgid_nr(current),
+                        from_kuid(&init_user_ns, cred->uid),
+                        from_kgid(&init_user_ns, cred->gid),
+                        from_kuid(&init_user_ns, cred->euid),
+                        from_kuid(&init_user_ns, cred->suid),
+                        from_kuid(&init_user_ns, cred->fsuid),
+                        from_kgid(&init_user_ns, cred->egid),
+                        from_kgid(&init_user_ns, cred->sgid),
+                        from_kgid(&init_user_ns, cred->fsgid));
+       audit_log_task_context(ab);
+       audit_log_key(ab, ctx->filterkey);
+       audit_log_end(ab);
+}
+
 static void audit_log_exit(void)
 {
        int i, call_panic = 0;
@@ -1434,29 +1685,38 @@ static void audit_log_exit(void)
 
        context->personality = current->personality;
 
-       ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
-       if (!ab)
-               return;         /* audit_panic has been called */
-       audit_log_format(ab, "arch=%x syscall=%d",
-                        context->arch, context->major);
-       if (context->personality != PER_LINUX)
-               audit_log_format(ab, " per=%lx", context->personality);
-       if (context->return_valid)
-               audit_log_format(ab, " success=%s exit=%ld",
-                                (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
-                                context->return_code);
-
-       audit_log_format(ab,
-                        " a0=%lx a1=%lx a2=%lx a3=%lx items=%d",
-                        context->argv[0],
-                        context->argv[1],
-                        context->argv[2],
-                        context->argv[3],
-                        context->name_count);
-
-       audit_log_task_info(ab);
-       audit_log_key(ab, context->filterkey);
-       audit_log_end(ab);
+       switch (context->context) {
+       case AUDIT_CTX_SYSCALL:
+               ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL);
+               if (!ab)
+                       return;
+               audit_log_format(ab, "arch=%x syscall=%d",
+                                context->arch, context->major);
+               if (context->personality != PER_LINUX)
+                       audit_log_format(ab, " per=%lx", context->personality);
+               if (context->return_valid != AUDITSC_INVALID)
+                       audit_log_format(ab, " success=%s exit=%ld",
+                                        (context->return_valid == AUDITSC_SUCCESS ?
+                                         "yes" : "no"),
+                                        context->return_code);
+               audit_log_format(ab,
+                                " a0=%lx a1=%lx a2=%lx a3=%lx items=%d",
+                                context->argv[0],
+                                context->argv[1],
+                                context->argv[2],
+                                context->argv[3],
+                                context->name_count);
+               audit_log_task_info(ab);
+               audit_log_key(ab, context->filterkey);
+               audit_log_end(ab);
+               break;
+       case AUDIT_CTX_URING:
+               audit_log_uring(context);
+               break;
+       default:
+               BUG();
+               break;
+       }
 
        for (aux = context->aux; aux; aux = aux->next) {
 
@@ -1468,6 +1728,7 @@ static void audit_log_exit(void)
 
                case AUDIT_BPRM_FCAPS: {
                        struct audit_aux_data_bprm_fcaps *axs = (void *)aux;
+
                        audit_log_format(ab, "fver=%x", axs->fcap_ver);
                        audit_log_cap(ab, "fp", &axs->fcap.permitted);
                        audit_log_cap(ab, "fi", &axs->fcap.inheritable);
@@ -1546,21 +1807,22 @@ static void audit_log_exit(void)
                audit_log_name(context, n, NULL, i++, &call_panic);
        }
 
-       audit_log_proctitle();
+       if (context->context == AUDIT_CTX_SYSCALL)
+               audit_log_proctitle();
 
        /* Send end of event record to help user space know we are finished */
        ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
        if (ab)
                audit_log_end(ab);
        if (call_panic)
-               audit_panic("error converting sid to string");
+               audit_panic("error in audit_log_exit()");
 }
 
 /**
  * __audit_free - free a per-task audit context
  * @tsk: task whose audit context block to free
  *
- * Called from copy_process and do_exit
+ * Called from copy_process, do_exit, and the io_uring code
  */
 void __audit_free(struct task_struct *tsk)
 {
@@ -1569,29 +1831,167 @@ void __audit_free(struct task_struct *tsk)
        if (!context)
                return;
 
+       /* this may generate CONFIG_CHANGE records */
        if (!list_empty(&context->killed_trees))
                audit_kill_trees(context);
 
        /* We are called either by do_exit() or the fork() error handling code;
         * in the former case tsk == current and in the latter tsk is a
-        * random task_struct that doesn't doesn't have any meaningful data we
+        * random task_struct that doesn't have any meaningful data we
         * need to log via audit_log_exit().
         */
-       if (tsk == current && !context->dummy && context->in_syscall) {
-               context->return_valid = 0;
+       if (tsk == current && !context->dummy) {
+               context->return_valid = AUDITSC_INVALID;
                context->return_code = 0;
-
-               audit_filter_syscall(tsk, context,
-                                    &audit_filter_list[AUDIT_FILTER_EXIT]);
-               audit_filter_inodes(tsk, context);
-               if (context->current_state == AUDIT_RECORD_CONTEXT)
-                       audit_log_exit();
+               if (context->context == AUDIT_CTX_SYSCALL) {
+                       audit_filter_syscall(tsk, context);
+                       audit_filter_inodes(tsk, context);
+                       if (context->current_state == AUDIT_STATE_RECORD)
+                               audit_log_exit();
+               } else if (context->context == AUDIT_CTX_URING) {
+                       /* TODO: verify this case is real and valid */
+                       audit_filter_uring(tsk, context);
+                       audit_filter_inodes(tsk, context);
+                       if (context->current_state == AUDIT_STATE_RECORD)
+                               audit_log_uring(context);
+               }
        }
 
        audit_set_context(tsk, NULL);
        audit_free_context(context);
 }
 
+/**
+ * audit_return_fixup - fixup the return codes in the audit_context
+ * @ctx: the audit_context
+ * @success: true/false value to indicate if the operation succeeded or not
+ * @code: operation return code
+ *
+ * We need to fixup the return code in the audit logs if the actual return
+ * codes are later going to be fixed by the arch specific signal handlers.
+ */
+static void audit_return_fixup(struct audit_context *ctx,
+                              int success, long code)
+{
+       /*
+        * This is actually a test for:
+        * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) ||
+        * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK)
+        *
+        * but is faster than a bunch of ||
+        */
+       if (unlikely(code <= -ERESTARTSYS) &&
+           (code >= -ERESTART_RESTARTBLOCK) &&
+           (code != -ENOIOCTLCMD))
+               ctx->return_code = -EINTR;
+       else
+               ctx->return_code  = code;
+       ctx->return_valid = (success ? AUDITSC_SUCCESS : AUDITSC_FAILURE);
+}
+
+/**
+ * __audit_uring_entry - prepare the kernel task's audit context for io_uring
+ * @op: the io_uring opcode
+ *
+ * This is similar to audit_syscall_entry() but is intended for use by io_uring
+ * operations.  This function should only ever be called from
+ * audit_uring_entry() as we rely on the audit context checking present in that
+ * function.
+ */
+void __audit_uring_entry(u8 op)
+{
+       struct audit_context *ctx = audit_context();
+
+       if (ctx->state == AUDIT_STATE_DISABLED)
+               return;
+
+       /*
+        * NOTE: It's possible that we can be called from the process' context
+        *       before it returns to userspace, and before audit_syscall_exit()
+        *       is called.  In this case there is not much to do, just record
+        *       the io_uring details and return.
+        */
+       ctx->uring_op = op;
+       if (ctx->context == AUDIT_CTX_SYSCALL)
+               return;
+
+       ctx->dummy = !audit_n_rules;
+       if (!ctx->dummy && ctx->state == AUDIT_STATE_BUILD)
+               ctx->prio = 0;
+
+       ctx->context = AUDIT_CTX_URING;
+       ctx->current_state = ctx->state;
+       ktime_get_coarse_real_ts64(&ctx->ctime);
+}
+
+/**
+ * __audit_uring_exit - wrap up the kernel task's audit context after io_uring
+ * @success: true/false value to indicate if the operation succeeded or not
+ * @code: operation return code
+ *
+ * This is similar to audit_syscall_exit() but is intended for use by io_uring
+ * operations.  This function should only ever be called from
+ * audit_uring_exit() as we rely on the audit context checking present in that
+ * function.
+ */
+void __audit_uring_exit(int success, long code)
+{
+       struct audit_context *ctx = audit_context();
+
+       if (ctx->dummy) {
+               if (ctx->context != AUDIT_CTX_URING)
+                       return;
+               goto out;
+       }
+
+       audit_return_fixup(ctx, success, code);
+       if (ctx->context == AUDIT_CTX_SYSCALL) {
+               /*
+                * NOTE: See the note in __audit_uring_entry() about the case
+                *       where we may be called from process context before we
+                *       return to userspace via audit_syscall_exit().  In this
+                *       case we simply emit a URINGOP record and bail, the
+                *       normal syscall exit handling will take care of
+                *       everything else.
+                *       It is also worth mentioning that when we are called,
+                *       the current process creds may differ from the creds
+                *       used during the normal syscall processing; keep that
+                *       in mind if/when we move the record generation code.
+                */
+
+               /*
+                * We need to filter on the syscall info here to decide if we
+                * should emit a URINGOP record.  I know it seems odd but this
+                * solves the problem where users have a filter to block *all*
+                * syscall records in the "exit" filter; we want to preserve
+                * the behavior here.
+                */
+               audit_filter_syscall(current, ctx);
+               if (ctx->current_state != AUDIT_STATE_RECORD)
+                       audit_filter_uring(current, ctx);
+               audit_filter_inodes(current, ctx);
+               if (ctx->current_state != AUDIT_STATE_RECORD)
+                       return;
+
+               audit_log_uring(ctx);
+               return;
+       }
+
+       /* this may generate CONFIG_CHANGE records */
+       if (!list_empty(&ctx->killed_trees))
+               audit_kill_trees(ctx);
+
+       /* run through both filters to ensure we set the filterkey properly */
+       audit_filter_uring(current, ctx);
+       audit_filter_inodes(current, ctx);
+       if (ctx->current_state != AUDIT_STATE_RECORD)
+               goto out;
+       audit_log_exit();
+
+out:
+       audit_reset_context(ctx);
+}
+
 /**
  * __audit_syscall_entry - fill in an audit record at syscall entry
  * @major: major syscall type (function)
@@ -1603,7 +2003,7 @@ void __audit_free(struct task_struct *tsk)
  * Fill in audit context at syscall entry.  This only happens if the
  * audit context was created when the task was created and the state or
  * filters demand the audit context be built.  If the state from the
- * per-task filter or from the per-syscall filter is AUDIT_RECORD_CONTEXT,
+ * per-task filter or from the per-syscall filter is AUDIT_STATE_RECORD,
  * then the record will be written at syscall exit time (otherwise, it
  * will only be written if another part of the kernel requests that it
  * be written).
@@ -1617,14 +2017,19 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
        if (!audit_enabled || !context)
                return;
 
-       BUG_ON(context->in_syscall || context->name_count);
+       WARN_ON(context->context != AUDIT_CTX_UNUSED);
+       WARN_ON(context->name_count);
+       if (context->context != AUDIT_CTX_UNUSED || context->name_count) {
+               audit_panic("unrecoverable error in audit_syscall_entry()");
+               return;
+       }
 
        state = context->state;
-       if (state == AUDIT_DISABLED)
+       if (state == AUDIT_STATE_DISABLED)
                return;
 
        context->dummy = !audit_n_rules;
-       if (!context->dummy && state == AUDIT_BUILD_CONTEXT) {
+       if (!context->dummy && state == AUDIT_STATE_BUILD) {
                context->prio = 0;
                if (auditd_test_task(current))
                        return;
@@ -1636,10 +2041,8 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
        context->argv[1]    = a2;
        context->argv[2]    = a3;
        context->argv[3]    = a4;
-       context->serial     = 0;
-       context->in_syscall = 1;
+       context->context = AUDIT_CTX_SYSCALL;
        context->current_state  = state;
-       context->ppid       = 0;
        ktime_get_coarse_real_ts64(&context->ctime);
 }
 
@@ -1649,71 +2052,34 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,
  * @return_code: return value of the syscall
  *
  * Tear down after system call.  If the audit context has been marked as
- * auditable (either because of the AUDIT_RECORD_CONTEXT state from
+ * auditable (either because of the AUDIT_STATE_RECORD state from
  * filtering, or because some other part of the kernel wrote an audit
  * message), then write out the syscall information.  In call cases,
  * free the names stored from getname().
  */
 void __audit_syscall_exit(int success, long return_code)
 {
-       struct audit_context *context;
+       struct audit_context *context = audit_context();
 
-       context = audit_context();
-       if (!context)
-               return;
+       if (!context || context->dummy ||
+           context->context != AUDIT_CTX_SYSCALL)
+               goto out;
 
+       /* this may generate CONFIG_CHANGE records */
        if (!list_empty(&context->killed_trees))
                audit_kill_trees(context);
 
-       if (!context->dummy && context->in_syscall) {
-               if (success)
-                       context->return_valid = AUDITSC_SUCCESS;
-               else
-                       context->return_valid = AUDITSC_FAILURE;
+       audit_return_fixup(context, success, return_code);
+       /* run through both filters to ensure we set the filterkey properly */
+       audit_filter_syscall(current, context);
+       audit_filter_inodes(current, context);
+       if (context->current_state != AUDIT_STATE_RECORD)
+               goto out;
 
-               /*
-                * we need to fix up the return code in the audit logs if the
-                * actual return codes are later going to be fixed up by the
-                * arch specific signal handlers
-                *
-                * This is actually a test for:
-                * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) ||
-                * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK)
-                *
-                * but is faster than a bunch of ||
-                */
-               if (unlikely(return_code <= -ERESTARTSYS) &&
-                   (return_code >= -ERESTART_RESTARTBLOCK) &&
-                   (return_code != -ENOIOCTLCMD))
-                       context->return_code = -EINTR;
-               else
-                       context->return_code  = return_code;
-
-               audit_filter_syscall(current, context,
-                                    &audit_filter_list[AUDIT_FILTER_EXIT]);
-               audit_filter_inodes(current, context);
-               if (context->current_state == AUDIT_RECORD_CONTEXT)
-                       audit_log_exit();
-       }
-
-       context->in_syscall = 0;
-       context->prio = context->state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;
-
-       audit_free_module(context);
-       audit_free_names(context);
-       unroll_tree_refs(context, NULL, 0);
-       audit_free_aux(context);
-       context->aux = NULL;
-       context->aux_pids = NULL;
-       context->target_pid = 0;
-       context->target_sid = 0;
-       context->sockaddr_len = 0;
-       context->type = 0;
-       context->fds[0] = -1;
-       if (context->state != AUDIT_RECORD_CONTEXT) {
-               kfree(context->filterkey);
-               context->filterkey = NULL;
-       }
+       audit_log_exit();
+
+out:
+       audit_reset_context(context);
 }
 
 static inline void handle_one(const struct inode *inode)
@@ -1722,6 +2088,7 @@ static inline void handle_one(const struct inode *inode)
        struct audit_tree_refs *p;
        struct audit_chunk *chunk;
        int count;
+
        if (likely(!inode->i_fsnotify_marks))
                return;
        context = audit_context();
@@ -1761,10 +2128,12 @@ retry:
        d = dentry;
        rcu_read_lock();
        seq = read_seqbegin(&rename_lock);
-       for(;;) {
+       for (;;) {
                struct inode *inode = d_backing_inode(d);
+
                if (inode && unlikely(inode->i_fsnotify_marks)) {
                        struct audit_chunk *chunk;
+
                        chunk = audit_tree_lookup(inode);
                        if (chunk) {
                                if (unlikely(!put_tree_ref(context, chunk))) {
@@ -1820,6 +2189,8 @@ static struct audit_names *audit_alloc_name(struct audit_context *context,
        list_add_tail(&aname->list, &context->names_list);
 
        context->name_count++;
+       if (!context->pwd.dentry)
+               get_fs_pwd(current->fs, &context->pwd);
        return aname;
 }
 
@@ -1841,7 +2212,7 @@ __audit_reusename(const __user char *uptr)
                if (!n->name)
                        continue;
                if (n->name->uptr == uptr) {
-                       n->name->refcnt++;
+                       atomic_inc(&n->name->refcnt);
                        return n->name;
                }
        }
@@ -1860,7 +2231,7 @@ void __audit_getname(struct filename *name)
        struct audit_context *context = audit_context();
        struct audit_names *n;
 
-       if (!context->in_syscall)
+       if (context->context == AUDIT_CTX_UNUSED)
                return;
 
        n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
@@ -1870,10 +2241,7 @@ void __audit_getname(struct filename *name)
        n->name = name;
        n->name_len = AUDIT_NAME_FULL;
        name->aname = n;
-       name->refcnt++;
-
-       if (!context->pwd.dentry)
-               get_fs_pwd(current->fs, &context->pwd);
+       atomic_inc(&name->refcnt);
 }
 
 static inline int audit_copy_fcaps(struct audit_names *name,
@@ -1885,7 +2253,7 @@ static inline int audit_copy_fcaps(struct audit_names *name,
        if (!dentry)
                return 0;
 
-       rc = get_vfs_caps_from_disk(dentry, &caps);
+       rc = get_vfs_caps_from_disk(&nop_mnt_idmap, dentry, &caps);
        if (rc)
                return rc;
 
@@ -1935,7 +2303,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
        struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS];
        int i;
 
-       if (!context->in_syscall)
+       if (context->context == AUDIT_CTX_UNUSED)
                return;
 
        rcu_read_lock();
@@ -2005,7 +2373,7 @@ out_alloc:
                return;
        if (name) {
                n->name = name;
-               name->refcnt++;
+               atomic_inc(&name->refcnt);
        }
 
 out:
@@ -2053,7 +2421,7 @@ void __audit_inode_child(struct inode *parent,
        struct list_head *list = &audit_filter_list[AUDIT_FILTER_FS];
        int i;
 
-       if (!context->in_syscall)
+       if (context->context == AUDIT_CTX_UNUSED)
                return;
 
        rcu_read_lock();
@@ -2092,6 +2460,8 @@ void __audit_inode_child(struct inode *parent,
                }
        }
 
+       cond_resched();
+
        /* is there a matching child entry? */
        list_for_each_entry(n, &context->names_list, list) {
                /* can only match entries that have a name */
@@ -2130,7 +2500,7 @@ void __audit_inode_child(struct inode *parent,
                if (found_parent) {
                        found_child->name = found_parent->name;
                        found_child->name_len = AUDIT_NAME_FULL;
-                       found_child->name->refcnt++;
+                       atomic_inc(&found_child->name->refcnt);
                }
        }
 
@@ -2152,7 +2522,7 @@ EXPORT_SYMBOL_GPL(__audit_inode_child);
 int auditsc_get_stamp(struct audit_context *ctx,
                       struct timespec64 *t, unsigned int *serial)
 {
-       if (!ctx->in_syscall)
+       if (ctx->context == AUDIT_CTX_UNUSED)
                return 0;
        if (!ctx->serial)
                ctx->serial = audit_serial();
@@ -2161,7 +2531,7 @@ int auditsc_get_stamp(struct audit_context *ctx,
        *serial    = ctx->serial;
        if (!ctx->prio) {
                ctx->prio = 1;
-               ctx->current_state = AUDIT_RECORD_CONTEXT;
+               ctx->current_state = AUDIT_STATE_RECORD;
        }
        return 1;
 }
@@ -2243,6 +2613,7 @@ void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification)
 void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
 {
        struct audit_context *context = audit_context();
+
        context->mq_getsetattr.mqdes = mqdes;
        context->mq_getsetattr.mqstat = *mqstat;
        context->type = AUDIT_MQ_GETSETATTR;
@@ -2256,6 +2627,7 @@ void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
 void __audit_ipc_obj(struct kern_ipc_perm *ipcp)
 {
        struct audit_context *context = audit_context();
+
        context->ipc.uid = ipcp->uid;
        context->ipc.gid = ipcp->gid;
        context->ipc.mode = ipcp->mode;
@@ -2320,6 +2692,7 @@ int __audit_socketcall(int nargs, unsigned long *args)
 void __audit_fd_pair(int fd1, int fd2)
 {
        struct audit_context *context = audit_context();
+
        context->fds[0] = fd1;
        context->fds[1] = fd2;
 }
@@ -2337,6 +2710,7 @@ int __audit_sockaddr(int len, void *a)
 
        if (!context->sockaddr) {
                void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL);
+
                if (!p)
                        return -ENOMEM;
                context->sockaddr = p;
@@ -2355,35 +2729,22 @@ void __audit_ptrace(struct task_struct *t)
        context->target_auid = audit_get_loginuid(t);
        context->target_uid = task_uid(t);
        context->target_sessionid = audit_get_sessionid(t);
-       security_task_getsecid(t, &context->target_sid);
+       security_task_getsecid_obj(t, &context->target_sid);
        memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
 }
 
 /**
- * audit_signal_info - record signal info for shutting down audit subsystem
- * @sig: signal value
+ * audit_signal_info_syscall - record signal info for syscalls
  * @t: task being signaled
  *
  * If the audit subsystem is being terminated, record the task (pid)
  * and uid that is doing that.
  */
-int audit_signal_info(int sig, struct task_struct *t)
+int audit_signal_info_syscall(struct task_struct *t)
 {
        struct audit_aux_data_pids *axp;
        struct audit_context *ctx = audit_context();
-       kuid_t uid = current_uid(), auid, t_uid = task_uid(t);
-
-       if (auditd_test_task(t) &&
-           (sig == SIGTERM || sig == SIGHUP ||
-            sig == SIGUSR1 || sig == SIGUSR2)) {
-               audit_sig_pid = task_tgid_nr(current);
-               auid = audit_get_loginuid(current);
-               if (uid_valid(auid))
-                       audit_sig_uid = auid;
-               else
-                       audit_sig_uid = uid;
-               security_task_getsecid(current, &audit_sig_sid);
-       }
+       kuid_t t_uid = task_uid(t);
 
        if (!audit_signals || audit_dummy_context())
                return 0;
@@ -2395,7 +2756,7 @@ int audit_signal_info(int sig, struct task_struct *t)
                ctx->target_auid = audit_get_loginuid(t);
                ctx->target_uid = t_uid;
                ctx->target_sessionid = audit_get_sessionid(t);
-               security_task_getsecid(t, &ctx->target_sid);
+               security_task_getsecid_obj(t, &ctx->target_sid);
                memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
                return 0;
        }
@@ -2416,7 +2777,7 @@ int audit_signal_info(int sig, struct task_struct *t)
        axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
        axp->target_uid[axp->pid_count] = t_uid;
        axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
-       security_task_getsecid(t, &axp->target_sid[axp->pid_count]);
+       security_task_getsecid_obj(t, &axp->target_sid[axp->pid_count]);
        memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
        axp->pid_count++;
 
@@ -2449,7 +2810,8 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
        ax->d.next = context->aux;
        context->aux = (void *)ax;
 
-       get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps);
+       get_vfs_caps_from_disk(&nop_mnt_idmap,
+                              bprm->file->f_path.dentry, &vcaps);
 
        ax->fcap.permitted = vcaps.permitted;
        ax->fcap.inheritable = vcaps.inheritable;
@@ -2480,6 +2842,7 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
 void __audit_log_capset(const struct cred *new, const struct cred *old)
 {
        struct audit_context *context = audit_context();
+
        context->capset.pid = task_tgid_nr(current);
        context->capset.cap.effective   = new->cap_effective;
        context->capset.cap.inheritable = new->cap_effective;
@@ -2491,11 +2854,22 @@ void __audit_log_capset(const struct cred *new, const struct cred *old)
 void __audit_mmap_fd(int fd, int flags)
 {
        struct audit_context *context = audit_context();
+
        context->mmap.fd = fd;
        context->mmap.flags = flags;
        context->type = AUDIT_MMAP;
 }
 
+void __audit_openat2_how(struct open_how *how)
+{
+       struct audit_context *context = audit_context();
+
+       context->openat2.flags = how->flags;
+       context->openat2.mode = how->mode;
+       context->openat2.resolve = how->resolve;
+       context->type = AUDIT_OPENAT2;
+}
+
 void __audit_log_kern_module(char *name)
 {
        struct audit_context *context = audit_context();
@@ -2506,40 +2880,66 @@ void __audit_log_kern_module(char *name)
        context->type = AUDIT_KERN_MODULE;
 }
 
-void __audit_fanotify(unsigned int response)
+void __audit_fanotify(u32 response, struct fanotify_response_info_audit_rule *friar)
 {
-       audit_log(audit_context(), GFP_KERNEL,
-               AUDIT_FANOTIFY, "resp=%u", response);
+       /* {subj,obj}_trust values are {0,1,2}: no,yes,unknown */
+       switch (friar->hdr.type) {
+       case FAN_RESPONSE_INFO_NONE:
+               audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
+                         "resp=%u fan_type=%u fan_info=0 subj_trust=2 obj_trust=2",
+                         response, FAN_RESPONSE_INFO_NONE);
+               break;
+       case FAN_RESPONSE_INFO_AUDIT_RULE:
+               audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
+                         "resp=%u fan_type=%u fan_info=%X subj_trust=%u obj_trust=%u",
+                         response, friar->hdr.type, friar->rule_number,
+                         friar->subj_trust, friar->obj_trust);
+       }
 }
 
 void __audit_tk_injoffset(struct timespec64 offset)
 {
-       audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_INJOFFSET,
-                 "sec=%lli nsec=%li",
-                 (long long)offset.tv_sec, offset.tv_nsec);
+       struct audit_context *context = audit_context();
+
+       /* only set type if not already set by NTP */
+       if (!context->type)
+               context->type = AUDIT_TIME_INJOFFSET;
+       memcpy(&context->time.tk_injoffset, &offset, sizeof(offset));
 }
 
-static void audit_log_ntp_val(const struct audit_ntp_data *ad,
-                             const char *op, enum audit_ntp_type type)
+void __audit_ntp_log(const struct audit_ntp_data *ad)
 {
-       const struct audit_ntp_val *val = &ad->vals[type];
-
-       if (val->newval == val->oldval)
-               return;
+       struct audit_context *context = audit_context();
+       int type;
 
-       audit_log(audit_context(), GFP_KERNEL, AUDIT_TIME_ADJNTPVAL,
-                 "op=%s old=%lli new=%lli", op, val->oldval, val->newval);
+       for (type = 0; type < AUDIT_NTP_NVALS; type++)
+               if (ad->vals[type].newval != ad->vals[type].oldval) {
+                       /* unconditionally set type, overwriting TK */
+                       context->type = AUDIT_TIME_ADJNTPVAL;
+                       memcpy(&context->time.ntp_data, ad, sizeof(*ad));
+                       break;
+               }
 }
 
-void __audit_ntp_log(const struct audit_ntp_data *ad)
+void __audit_log_nfcfg(const char *name, u8 af, unsigned int nentries,
+                      enum audit_nfcfgop op, gfp_t gfp)
 {
-       audit_log_ntp_val(ad, "offset", AUDIT_NTP_OFFSET);
-       audit_log_ntp_val(ad, "freq",   AUDIT_NTP_FREQ);
-       audit_log_ntp_val(ad, "status", AUDIT_NTP_STATUS);
-       audit_log_ntp_val(ad, "tai",    AUDIT_NTP_TAI);
-       audit_log_ntp_val(ad, "tick",   AUDIT_NTP_TICK);
-       audit_log_ntp_val(ad, "adjust", AUDIT_NTP_ADJUST);
+       struct audit_buffer *ab;
+       char comm[sizeof(current->comm)];
+
+       ab = audit_log_start(audit_context(), gfp, AUDIT_NETFILTER_CFG);
+       if (!ab)
+               return;
+       audit_log_format(ab, "table=%s family=%u entries=%u op=%s",
+                        name, af, nentries, audit_nfcfgs[op].s);
+
+       audit_log_format(ab, " pid=%u", task_pid_nr(current));
+       audit_log_task_context(ab); /* subj= */
+       audit_log_format(ab, " comm=");
+       audit_log_untrustedstring(ab, get_task_comm(comm, current));
+       audit_log_end(ab);
 }
+EXPORT_SYMBOL_GPL(__audit_log_nfcfg);
 
 static void audit_log_task(struct audit_buffer *ab)
 {
@@ -2636,7 +3036,7 @@ void audit_seccomp_actions_logged(const char *names, const char *old_names,
 struct list_head *audit_killed_trees(void)
 {
        struct audit_context *ctx = audit_context();
-       if (likely(!ctx || !ctx->in_syscall))
+       if (likely(!ctx || ctx->context == AUDIT_CTX_UNUSED))
                return NULL;
        return &ctx->killed_trees;
 }