mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
BACKPORT: seccomp: release filter after task is fully dead
The seccomp filter used to be released in free_task() which is called asynchronously via call_rcu() and assorted mechanisms. Since we need to inform tasks waiting on the seccomp notifier when a filter goes empty we will notify them as soon as a task has been marked fully dead in release_task(). To not split seccomp cleanup into two parts, move filter release out of free_task() and into release_task() after we've unhashed struct task from struct pid, exited signals, and unlinked it from the threadgroups' thread list. We'll put the empty filter notification infrastructure into it in a follow up patch. This also renames put_seccomp_filter() to seccomp_filter_release() which is a more descriptive name of what we're doing here especially once we've added the empty filter notification mechanism in there. We're also NULL-ing the task's filter tree entrypoint which seems cleaner than leaving a dangling pointer in there. Note that this shouldn't need any memory barriers since we're calling this when the task is in release_task() which means it's EXIT_DEAD. So it can't modify its seccomp filters anymore. You can also see this from the point where we're calling seccomp_filter_release(). It's after __exit_signal() and at this point, tsk->sighand will already have been NULLed which is required for thread-sync and filter installation alike. Cc: Tycho Andersen <[email protected]> Cc: Kees Cook <[email protected]> Cc: Matt Denton <[email protected]> Cc: Sargun Dhillon <[email protected]> Cc: Jann Horn <[email protected]> Cc: Chris Palmer <[email protected]> Cc: Aleksa Sarai <[email protected]> Cc: Robert Sesek <[email protected]> Cc: Jeffrey Vander Stoep <[email protected]> Cc: Linux Containers <[email protected]> Signed-off-by: Christian Brauner <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kees Cook <[email protected]> (cherry picked from commit 3a15fb6ed92cb32b0a83f406aa4a96f28c9adbc3) Signed-off-by: Jeff Vander Stoep <[email protected]> Bug: 176068146 Resolved minor merge conflict in kernel/exit.c where 5.4 does not have commits 7bc3e6e55acf0 and 6ade99ec6175a. Change-Id: I4a0113f3f64a86937ba5c9ac6e2537926e2827be
This commit is contained in:
parent
07bd1e5332
commit
31e7b9c9d8
4 changed files with 40 additions and 28 deletions
|
|
@ -380,6 +380,42 @@ static inline pid_t seccomp_can_sync_threads(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void seccomp_filter_free(struct seccomp_filter *filter)
|
||||
{
|
||||
if (filter) {
|
||||
bpf_prog_destroy(filter->prog);
|
||||
kfree(filter);
|
||||
}
|
||||
}
|
||||
|
||||
static void __put_seccomp_filter(struct seccomp_filter *orig)
|
||||
{
|
||||
/* Clean up single-reference branches iteratively. */
|
||||
while (orig && refcount_dec_and_test(&orig->refs)) {
|
||||
struct seccomp_filter *freeme = orig;
|
||||
orig = orig->prev;
|
||||
seccomp_filter_free(freeme);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* seccomp_filter_release - Detach the task from its filter tree
|
||||
* and drop its reference count during
|
||||
* exit.
|
||||
*
|
||||
* This function should only be called when the task is exiting as
|
||||
* it detaches it from its filter tree. As such, READ_ONCE() and
|
||||
* barriers are not needed here, as would normally be needed.
|
||||
*/
|
||||
void seccomp_filter_release(struct task_struct *tsk)
|
||||
{
|
||||
struct seccomp_filter *orig = tsk->seccomp.filter;
|
||||
|
||||
/* Detach task from its filter tree. */
|
||||
tsk->seccomp.filter = NULL;
|
||||
__put_seccomp_filter(orig);
|
||||
}
|
||||
|
||||
/**
|
||||
* seccomp_sync_threads: sets all threads to use current's filter
|
||||
*
|
||||
|
|
@ -409,7 +445,7 @@ static inline void seccomp_sync_threads(unsigned long flags)
|
|||
* current's path will hold a reference. (This also
|
||||
* allows a put before the assignment.)
|
||||
*/
|
||||
put_seccomp_filter(thread);
|
||||
__put_seccomp_filter(thread->seccomp.filter);
|
||||
smp_store_release(&thread->seccomp.filter,
|
||||
caller->seccomp.filter);
|
||||
atomic_set(&thread->seccomp.filter_count,
|
||||
|
|
@ -578,30 +614,6 @@ void get_seccomp_filter(struct task_struct *tsk)
|
|||
__get_seccomp_filter(orig);
|
||||
}
|
||||
|
||||
static inline void seccomp_filter_free(struct seccomp_filter *filter)
|
||||
{
|
||||
if (filter) {
|
||||
bpf_prog_destroy(filter->prog);
|
||||
kfree(filter);
|
||||
}
|
||||
}
|
||||
|
||||
static void __put_seccomp_filter(struct seccomp_filter *orig)
|
||||
{
|
||||
/* Clean up single-reference branches iteratively. */
|
||||
while (orig && refcount_dec_and_test(&orig->refs)) {
|
||||
struct seccomp_filter *freeme = orig;
|
||||
orig = orig->prev;
|
||||
seccomp_filter_free(freeme);
|
||||
}
|
||||
}
|
||||
|
||||
/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
|
||||
void put_seccomp_filter(struct task_struct *tsk)
|
||||
{
|
||||
__put_seccomp_filter(tsk->seccomp.filter);
|
||||
}
|
||||
|
||||
static void seccomp_init_siginfo(kernel_siginfo_t *info, int syscall, int reason)
|
||||
{
|
||||
clear_siginfo(info);
|
||||
|
|
|
|||
Loading…
Reference in a new issue