diff --git a/arch/x86/kernel/signal_compat.c b/arch/x86/kernel/signal_compat.c
index 06743ec054d2..d4656f1b6341 100644
--- a/arch/x86/kernel/signal_compat.c
+++ b/arch/x86/kernel/signal_compat.c
@@ -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: */
diff --git a/include/brute/brute.h b/include/brute/brute.h
new file mode 100644
index 000000000000..8531a7038711
--- /dev/null
+++ b/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_ */diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index 5a3c221f4c9d..ffc3ed2d4bce 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -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_codesdiff --git a/kernel/exit.c b/kernel/exit.c
index fd1c04193e18..69bcbd00d277 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -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--;@@ -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;
@@ -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;diff --git a/kernel/signal.c b/kernel/signal.c
index 4380763b3d8d..c85c091ecc27 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -55,6 +55,8 @@
#include <asm/siginfo.h>
#include <asm/cacheflush.h>
+#include <brute/brute.h>
+
/*
* SLAB caches for signal bits.
*/
@@ -2012,7 +2014,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;diff --git a/security/brute/brute.c b/security/brute/brute.c
index 4e0fd23990c8..e5c9098addf9 100644
--- a/security/brute/brute.c
+++ b/security/brute/brute.c
@@ -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.
*@@ -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)@@ -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);
}@@ -735,4 +791,5 @@ static int __init brute_init(void)
DEFINE_LSM(brute) = {
.name = KBUILD_MODNAME,
.init = brute_init,
+ .blobs = &brute_blob_sizes,
};
--