diff options
Diffstat (limited to 'kernel/auditsc.c')
| -rw-r--r-- | kernel/auditsc.c | 521 | 
1 files changed, 398 insertions, 123 deletions
| diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 8dd73a64f921..b517947bfa48 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -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 <[email protected]>   *   * Many of the ideas implemented here are from Stephen C. Tweedie, @@ -76,6 +63,7 @@  #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 "audit.h" @@ -166,7 +154,7 @@ static int audit_match_perm(struct audit_context *ctx, int mask)  	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; @@ -177,7 +165,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; @@ -188,14 +176,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)((struct open_how *)ctx->argv[2])->flags);  	default:  		return 0;  	} @@ -480,6 +470,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++) { @@ -657,7 +650,7 @@ static int audit_filter_rules(struct task_struct *tsk,  			result = audit_comparator(audit_loginuid_set(tsk), f->op, f->val);  			break;  		case AUDIT_SADDR_FAM: -			if (ctx->sockaddr) +			if (ctx && ctx->sockaddr)  				result = audit_comparator(ctx->sockaddr->ss_family,  							  f->op, f->val);  			break; @@ -747,8 +740,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); @@ -805,6 +796,34 @@ static int audit_in_mask(const struct audit_krule *rule, unsigned long val)  	return rule->mask[word] & bit;  } +/** + * 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) +{ +	struct audit_entry *e; +	enum audit_state state; + +	if (auditd_test_task(tsk)) +		return; + +	rcu_read_lock(); +	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_URING_EXIT], +				list) { +		if (audit_in_mask(&e->rule, ctx->uring_op) && +		    audit_filter_rules(tsk, &e->rule, ctx, NULL, &state, +				       false)) { +			rcu_read_unlock(); +			ctx->current_state = state; +			return; +		} +	} +	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 @@ -915,10 +934,81 @@ 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->state" 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->pid = 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)); +	ctx->type = 0; +	audit_free_module(ctx); +	ctx->fds[0] = -1; +	audit_proctitle_free(ctx);  }  static inline struct audit_context *audit_alloc_context(enum audit_state state) @@ -928,6 +1018,7 @@ 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_STATE_RECORD ? ~0ULL : 0;  	INIT_LIST_HEAD(&context->killed_trees); @@ -953,7 +1044,7 @@ 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_STATE_DISABLED) { @@ -973,16 +1064,37 @@ int audit_alloc(struct task_struct *tsk)  	return 0;  } +/** + * audit_alloc_kernel - allocate an audit_context for a kernel task + * @tsk: the kernel task + * + * Similar to the audit_alloc() function, but intended for kernel private + * threads.  Returns zero on success, negative values on failure. + */ +int audit_alloc_kernel(struct task_struct *tsk) +{ +	/* +	 * At the moment we are just going to call into audit_alloc() to +	 * simplify the code, but there two things to keep in mind with this +	 * approach: +	 * +	 * 1. Filtering internal kernel tasks is a bit laughable in almost all +	 * cases, but there is at least one case where there is a benefit: +	 * the '-a task,never' case allows the admin to effectively disable +	 * task auditing at runtime. +	 * +	 * 2. The {set,clear}_task_syscall_work() ops likely have zero effect +	 * on these internal kernel tasks, but they probably don't hurt either. +	 */ +	return audit_alloc(tsk); +} +  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);  	free_tree_refs(context); -	audit_free_aux(context);  	kfree(context->filterkey); -	kfree(context->sockaddr); -	audit_proctitle_free(context);  	kfree(context);  } @@ -1316,6 +1428,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; @@ -1479,6 +1597,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; @@ -1489,29 +1645,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 != 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); +	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) { @@ -1602,21 +1767,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)  { @@ -1625,6 +1791,7 @@ 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); @@ -1633,14 +1800,21 @@ void __audit_free(struct task_struct *tsk)  	 * random task_struct that doesn't doesn't have any meaningful data we  	 * need to log via audit_log_exit().  	 */ -	if (tsk == current && !context->dummy && context->in_syscall) { +	if (tsk == current && !context->dummy) {  		context->return_valid = AUDITSC_INVALID;  		context->return_code = 0; - -		audit_filter_syscall(tsk, context); -		audit_filter_inodes(tsk, context); -		if (context->current_state == AUDIT_STATE_RECORD) -			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); @@ -1648,6 +1822,131 @@ void __audit_free(struct task_struct *tsk)  }  /** + * 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->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_return_fixup(ctx, success, code); +	audit_log_exit(); + +out: +	audit_reset_context(ctx); +} + +/**   * __audit_syscall_entry - fill in an audit record at syscall entry   * @major: major syscall type (function)   * @a1: additional syscall register 1 @@ -1672,7 +1971,12 @@ 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_STATE_DISABLED) @@ -1691,10 +1995,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);  } @@ -1711,63 +2013,27 @@ void __audit_syscall_entry(int major, unsigned long a1, unsigned long a2,   */  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; +	/* 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_inodes(current, context); -		if (context->current_state == AUDIT_STATE_RECORD) -			audit_log_exit(); -	} - -	context->in_syscall = 0; -	context->prio = context->state == AUDIT_STATE_RECORD ? ~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_STATE_RECORD) { -		kfree(context->filterkey); -		context->filterkey = NULL; -	} +	audit_return_fixup(context, success, return_code); +	audit_log_exit(); + +out: +	audit_reset_context(context);  }  static inline void handle_one(const struct inode *inode) @@ -1919,7 +2185,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); @@ -1991,7 +2257,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(); @@ -2109,7 +2375,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(); @@ -2208,7 +2474,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(); @@ -2546,6 +2812,16 @@ void __audit_mmap_fd(int fd, int 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(); @@ -2706,8 +2982,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;  } |