Skip to content

Commit

Permalink
security/brute: Notify to userspace "task killed"
Browse files Browse the repository at this point in the history
Add a new SIGCHLD si_code to notify to userspace, using the "waitid"
system call, that a task has been killed by Brute LSM to mitigate a
brute force attack.

This is useful to supervisors in order to decide if a process that has
been killed to avoid an attack needs to be respawned. This way, it is
possible to avoid the scenario where a brute force attack can be
continued due to the respawn of a process. Although the xattr of the
executable is accessible from userspace, in complex daemons this file
may not be visible directly by the supervisor as it may be run through
some wrapper. So, the waitid notification is necessary.

To achieve this, use the task_struct security blob to hold a flag that
shows when a task has been killed by Brute LSM, and also, test this flag
in the "wait_task_zombie" and "do_notify_parent" functions.

Suggested-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: John Wood <john.wood@gmx.com>
  • Loading branch information
johwood authored and xanmod committed Jun 29, 2021
1 parent ae4be95 commit 1efb7f3
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 5 deletions.
2 changes: 1 addition & 1 deletion arch/x86/kernel/signal_compat.c
Expand Up @@ -30,7 +30,7 @@ static inline void signal_compat_build_tests(void)
BUILD_BUG_ON(NSIGSEGV != 9);
BUILD_BUG_ON(NSIGBUS != 5);
BUILD_BUG_ON(NSIGTRAP != 6);
BUILD_BUG_ON(NSIGCHLD != 6);
BUILD_BUG_ON(NSIGCHLD != 7);
BUILD_BUG_ON(NSIGSYS != 2);

/* This is part of the ABI and can never change in size: */
Expand Down
16 changes: 16 additions & 0 deletions include/brute/brute.h
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _BRUTE_H_
#define _BRUTE_H_

#include <linux/sched.h>

#ifdef CONFIG_SECURITY_FORK_BRUTE
bool brute_task_killed(const struct task_struct *task);
#else
static inline bool brute_task_killed(const struct task_struct *task)
{
return false;
}
#endif

#endif /* _BRUTE_H_ */
3 changes: 2 additions & 1 deletion include/uapi/asm-generic/siginfo.h
Expand Up @@ -274,7 +274,8 @@ typedef struct siginfo {
#define CLD_TRAPPED 4 /* traced child has trapped */
#define CLD_STOPPED 5 /* child has stopped */
#define CLD_CONTINUED 6 /* stopped child has continued */
#define NSIGCHLD 6
#define CLD_BRUTE 7 /* child was killed by brute LSM */
#define NSIGCHLD 7

/*
* SIGPOLL (or any other signal without signal specific si_codes) si_codes
Expand Down
6 changes: 5 additions & 1 deletion kernel/exit.c
Expand Up @@ -69,6 +69,8 @@
#include <asm/unistd.h>
#include <asm/mmu_context.h>

#include <brute/brute.h>

static void __unhash_process(struct task_struct *p, bool group_dead)
{
nr_threads--;
Expand Down Expand Up @@ -1001,6 +1003,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
pid_t pid = task_pid_vnr(p);
uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
struct waitid_info *infop;
bool killed_by_brute = brute_task_killed(p);

if (!likely(wo->wo_flags & WEXITED))
return 0;
Expand Down Expand Up @@ -1114,7 +1117,8 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
infop->cause = CLD_EXITED;
infop->status = status >> 8;
} else {
infop->cause = (status & 0x80) ? CLD_DUMPED : CLD_KILLED;
infop->cause = (status & 0x80) ? CLD_DUMPED :
killed_by_brute ? CLD_BRUTE : CLD_KILLED;
infop->status = status & 0x7f;
}
infop->pid = pid;
Expand Down
4 changes: 3 additions & 1 deletion kernel/signal.c
Expand Up @@ -55,6 +55,8 @@
#include <asm/siginfo.h>
#include <asm/cacheflush.h>

#include <brute/brute.h>

/*
* SLAB caches for signal bits.
*/
Expand Down Expand Up @@ -1972,7 +1974,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
if (tsk->exit_code & 0x80)
info.si_code = CLD_DUMPED;
else if (tsk->exit_code & 0x7f)
info.si_code = CLD_KILLED;
info.si_code = brute_task_killed(tsk) ? CLD_BRUTE : CLD_KILLED;
else {
info.si_code = CLD_EXITED;
info.si_status = tsk->exit_code >> 8;
Expand Down
59 changes: 58 additions & 1 deletion security/brute/brute.c
Expand Up @@ -56,6 +56,59 @@ struct brute_raw_stats {
u8 flags;
} __packed;

/**
* struct brute_task - Task info.
* @killed: Task killed to mitigate a brute force attack.
*/
struct brute_task {
u8 killed : 1;
};

/*
* brute_blob_sizes - LSM blob sizes.
*/
static struct lsm_blob_sizes brute_blob_sizes __lsm_ro_after_init = {
.lbs_task = sizeof(struct brute_task),
};

/**
* brute_task() - Get the task info.
* @task: The task to get the info.
*
* Return: A pointer to the brute_task structure.
*/
static inline struct brute_task *brute_task(const struct task_struct *task)
{
return task->security + brute_blob_sizes.lbs_task;
}

/**
* brute_set_task_killed() - Set task killed to mitigate a brute force attack.
* @task: The task to set.
*/
static inline void brute_set_task_killed(struct task_struct *task)
{
struct brute_task *task_info;

task_info = brute_task(task);
task_info->killed = true;
}

/**
* brute_task_killed() - Test if a task has been killed to mitigate an attack.
* @task: The task to test.
*
* Return: True if the task has been killed to mitigate a brute force attack.
* False otherwise.
*/
inline bool brute_task_killed(const struct task_struct *task)
{
struct brute_task *task_info;

task_info = brute_task(task);
return task_info->killed;
}

/**
* brute_get_current_exe_file() - Get the current task's executable file.
*
Expand Down Expand Up @@ -296,8 +349,10 @@ static void brute_kill_offending_tasks(const struct file *file)

read_lock(&tasklist_lock);
for_each_process(task) {
if (task->group_leader == current->group_leader)
if (task->group_leader == current->group_leader) {
brute_set_task_killed(task);
continue;
}

exe_file = get_task_exe_file(task);
if (!exe_file)
Expand All @@ -311,6 +366,7 @@ static void brute_kill_offending_tasks(const struct file *file)
do_send_sig_info(SIGKILL, SEND_SIG_PRIV, task, PIDTYPE_PID);
pr_warn_ratelimited("offending process %d [%s] killed\n",
task->pid, task->comm);
brute_set_task_killed(task);
}
read_unlock(&tasklist_lock);
}
Expand Down Expand Up @@ -735,4 +791,5 @@ static int __init brute_init(void)
DEFINE_LSM(brute) = {
.name = KBUILD_MODNAME,
.init = brute_init,
.blobs = &brute_blob_sizes,
};

0 comments on commit 1efb7f3

Please sign in to comment.