diff mbox series

[v3] audit: don't take task_lock() in audit_exe_compare() code path

Message ID 20231024183828.209525-2-paul@paul-moore.com (mailing list archive)
State Accepted
Delegated to: Paul Moore
Headers show
Series [v3] audit: don't take task_lock() in audit_exe_compare() code path | expand

Commit Message

Paul Moore Oct. 24, 2023, 6:38 p.m. UTC
The get_task_exe_file() function locks the given task with task_lock()
which when used inside audit_exe_compare() can cause deadlocks on
systems that generate audit records when the task_lock() is held. We
resolve this problem with two changes: ignoring those cases where the
task being audited is not the current task, and changing our approach
to obtaining the executable file struct to not require task_lock().

With the intent of the audit exe filter being to filter on audit events
generated by processes started by the specified executable, it makes
sense that we would only want to use the exe filter on audit records
associated with the currently executing process, e.g. @current.  If
we are asked to filter records using a non-@current task_struct we can
safely ignore the exe filter without negatively impacting the admin's
expectations for the exe filter.

Knowing that we only have to worry about filtering the currently
executing task in audit_exe_compare() we can do away with the
task_lock() and call get_mm_exe_file() with @current->mm directly.

Cc: <stable@vger.kernel.org>
Fixes: 5efc244346f9 ("audit: fix exe_file access in audit_exe_compare")
Reported-by: Andreas Steinmetz <anstein99@googlemail.com>
Reviewed-by: John Johansen <john.johanse@canonical.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
- v3
* added a !current->mm check
- v2
* dropped mmget()/mmput()
- v1
* initial revision
---
 kernel/audit_watch.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

Comments

Paul Moore Oct. 24, 2023, 6:40 p.m. UTC | #1
On Tue, Oct 24, 2023 at 2:39 PM Paul Moore <paul@paul-moore.com> wrote:
>
> The get_task_exe_file() function locks the given task with task_lock()
> which when used inside audit_exe_compare() can cause deadlocks on
> systems that generate audit records when the task_lock() is held. We
> resolve this problem with two changes: ignoring those cases where the
> task being audited is not the current task, and changing our approach
> to obtaining the executable file struct to not require task_lock().
>
> With the intent of the audit exe filter being to filter on audit events
> generated by processes started by the specified executable, it makes
> sense that we would only want to use the exe filter on audit records
> associated with the currently executing process, e.g. @current.  If
> we are asked to filter records using a non-@current task_struct we can
> safely ignore the exe filter without negatively impacting the admin's
> expectations for the exe filter.
>
> Knowing that we only have to worry about filtering the currently
> executing task in audit_exe_compare() we can do away with the
> task_lock() and call get_mm_exe_file() with @current->mm directly.
>
> Cc: <stable@vger.kernel.org>
> Fixes: 5efc244346f9 ("audit: fix exe_file access in audit_exe_compare")
> Reported-by: Andreas Steinmetz <anstein99@googlemail.com>
> Reviewed-by: John Johansen <john.johanse@canonical.com>

John, I took the liberty of preserving your 'Reviewed-by' tag since I
felt the current->mm check was a minor addition, but if you feel
otherwise let me know and I'll remove it.

> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
> - v3
> * added a !current->mm check
> - v2
> * dropped mmget()/mmput()
> - v1
> * initial revision
> ---
>  kernel/audit_watch.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)
Mateusz Guzik Oct. 24, 2023, 6:48 p.m. UTC | #2
This does fix the bug, and with the caveat I can't vouch for ignoring
non-current in the routine:

Reviewed-by: Mateusz Guzik <mjguzik@gmail.com>

Thanks for fixing the bug. Pretty weird it took this long for it to surface.

On 10/24/23, Paul Moore <paul@paul-moore.com> wrote:
> On Tue, Oct 24, 2023 at 2:39 PM Paul Moore <paul@paul-moore.com> wrote:
>>
>> The get_task_exe_file() function locks the given task with task_lock()
>> which when used inside audit_exe_compare() can cause deadlocks on
>> systems that generate audit records when the task_lock() is held. We
>> resolve this problem with two changes: ignoring those cases where the
>> task being audited is not the current task, and changing our approach
>> to obtaining the executable file struct to not require task_lock().
>>
>> With the intent of the audit exe filter being to filter on audit events
>> generated by processes started by the specified executable, it makes
>> sense that we would only want to use the exe filter on audit records
>> associated with the currently executing process, e.g. @current.  If
>> we are asked to filter records using a non-@current task_struct we can
>> safely ignore the exe filter without negatively impacting the admin's
>> expectations for the exe filter.
>>
>> Knowing that we only have to worry about filtering the currently
>> executing task in audit_exe_compare() we can do away with the
>> task_lock() and call get_mm_exe_file() with @current->mm directly.
>>
>> Cc: <stable@vger.kernel.org>
>> Fixes: 5efc244346f9 ("audit: fix exe_file access in audit_exe_compare")
>> Reported-by: Andreas Steinmetz <anstein99@googlemail.com>
>> Reviewed-by: John Johansen <john.johanse@canonical.com>
>
> John, I took the liberty of preserving your 'Reviewed-by' tag since I
> felt the current->mm check was a minor addition, but if you feel
> otherwise let me know and I'll remove it.
>
>> Signed-off-by: Paul Moore <paul@paul-moore.com>
>> ---
>> - v3
>> * added a !current->mm check
>> - v2
>> * dropped mmget()/mmput()
>> - v1
>> * initial revision
>> ---
>>  kernel/audit_watch.c | 9 ++++++++-
>>  1 file changed, 8 insertions(+), 1 deletion(-)
>
> --
> paul-moore.com
>
Paul Moore Oct. 24, 2023, 10:14 p.m. UTC | #3
On Tue, Oct 24, 2023 at 2:48 PM Mateusz Guzik <mjguzik@gmail.com> wrote:
>
> This does fix the bug, and with the caveat I can't vouch for ignoring
> non-current in the routine:

Understood, I'm vouching for that bit.

> Reviewed-by: Mateusz Guzik <mjguzik@gmail.com>
>
> Thanks for fixing the bug. Pretty weird it took this long for it to surface.

Yeah, I thought the same thing.  Regardless, thanks for taking the
time to review the fix.

> On 10/24/23, Paul Moore <paul@paul-moore.com> wrote:
> > On Tue, Oct 24, 2023 at 2:39 PM Paul Moore <paul@paul-moore.com> wrote:
> >>
> >> The get_task_exe_file() function locks the given task with task_lock()
> >> which when used inside audit_exe_compare() can cause deadlocks on
> >> systems that generate audit records when the task_lock() is held. We
> >> resolve this problem with two changes: ignoring those cases where the
> >> task being audited is not the current task, and changing our approach
> >> to obtaining the executable file struct to not require task_lock().
> >>
> >> With the intent of the audit exe filter being to filter on audit events
> >> generated by processes started by the specified executable, it makes
> >> sense that we would only want to use the exe filter on audit records
> >> associated with the currently executing process, e.g. @current.  If
> >> we are asked to filter records using a non-@current task_struct we can
> >> safely ignore the exe filter without negatively impacting the admin's
> >> expectations for the exe filter.
> >>
> >> Knowing that we only have to worry about filtering the currently
> >> executing task in audit_exe_compare() we can do away with the
> >> task_lock() and call get_mm_exe_file() with @current->mm directly.
> >>
> >> Cc: <stable@vger.kernel.org>
> >> Fixes: 5efc244346f9 ("audit: fix exe_file access in audit_exe_compare")
> >> Reported-by: Andreas Steinmetz <anstein99@googlemail.com>
> >> Reviewed-by: John Johansen <john.johanse@canonical.com>
> >
> > John, I took the liberty of preserving your 'Reviewed-by' tag since I
> > felt the current->mm check was a minor addition, but if you feel
> > otherwise let me know and I'll remove it.
> >
> >> Signed-off-by: Paul Moore <paul@paul-moore.com>
> >> ---
> >> - v3
> >> * added a !current->mm check
> >> - v2
> >> * dropped mmget()/mmput()
> >> - v1
> >> * initial revision
> >> ---
> >>  kernel/audit_watch.c | 9 ++++++++-
> >>  1 file changed, 8 insertions(+), 1 deletion(-)
> >
> > --
> > paul-moore.com
>
> --
> Mateusz Guzik <mjguzik gmail.com>
Paul Moore Oct. 26, 2023, 2:32 a.m. UTC | #4
On Tue, Oct 24, 2023 at 2:39 PM Paul Moore <paul@paul-moore.com> wrote:
>
> The get_task_exe_file() function locks the given task with task_lock()
> which when used inside audit_exe_compare() can cause deadlocks on
> systems that generate audit records when the task_lock() is held. We
> resolve this problem with two changes: ignoring those cases where the
> task being audited is not the current task, and changing our approach
> to obtaining the executable file struct to not require task_lock().
>
> With the intent of the audit exe filter being to filter on audit events
> generated by processes started by the specified executable, it makes
> sense that we would only want to use the exe filter on audit records
> associated with the currently executing process, e.g. @current.  If
> we are asked to filter records using a non-@current task_struct we can
> safely ignore the exe filter without negatively impacting the admin's
> expectations for the exe filter.
>
> Knowing that we only have to worry about filtering the currently
> executing task in audit_exe_compare() we can do away with the
> task_lock() and call get_mm_exe_file() with @current->mm directly.
>
> Cc: <stable@vger.kernel.org>
> Fixes: 5efc244346f9 ("audit: fix exe_file access in audit_exe_compare")
> Reported-by: Andreas Steinmetz <anstein99@googlemail.com>
> Reviewed-by: John Johansen <john.johanse@canonical.com>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
> - v3
> * added a !current->mm check
> - v2
> * dropped mmget()/mmput()
> - v1
> * initial revision
> ---
>  kernel/audit_watch.c | 9 ++++++++-
>  1 file changed, 8 insertions(+), 1 deletion(-)

Considering that we are only a few days away from v6.6, I've gone and
merged this into audit/dev and will send this up to Linus during the
merge window next week.
diff mbox series

Patch

diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 65075f1e4ac8..91e82e34b51e 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -527,11 +527,18 @@  int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
 	unsigned long ino;
 	dev_t dev;
 
-	exe_file = get_task_exe_file(tsk);
+	/* only do exe filtering if we are recording @current events/records */
+	if (tsk != current)
+		return 0;
+
+	if (WARN_ON_ONCE(!current->mm))
+		return 0;
+	exe_file = get_mm_exe_file(current->mm);
 	if (!exe_file)
 		return 0;
 	ino = file_inode(exe_file)->i_ino;
 	dev = file_inode(exe_file)->i_sb->s_dev;
 	fput(exe_file);
+
 	return audit_mark_compare(mark, ino, dev);
 }