new file mode 100644
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _BRUTE_H_
+#define _BRUTE_H_
+
+#include <linux/errno.h>
+
+#ifdef CONFIG_SECURITY_FORK_BRUTE
+int brute_prctl_enable(void);
+int brute_prctl_disable(void);
+#else
+static inline int brute_prctl_enable(void) { return -EINVAL; }
+static inline int brute_prctl_disable(void) { return -EINVAL; }
+#endif
+
+#endif /* _BRUTE_H_ */
+
@@ -238,4 +238,8 @@ struct prctl_mm_map {
#define PR_SET_IO_FLUSHER 57
#define PR_GET_IO_FLUSHER 58
+/* Enable/disable the detection and mitigation of a fork brute force attack */
+#define PR_SECURITY_FORK_BRUTE_ENABLE 59
+#define PR_SECURITY_FORK_BRUTE_DISABLE 60
+
#endif /* _LINUX_PRCTL_H */
@@ -72,6 +72,8 @@
#include <asm/io.h>
#include <asm/unistd.h>
+#include <brute/brute.h>
+
#include "uid16.h"
#ifndef SET_UNALIGN_CTL
@@ -2530,6 +2532,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
error = (current->flags & PR_IO_FLUSHER) == PR_IO_FLUSHER;
break;
+ case PR_SECURITY_FORK_BRUTE_ENABLE:
+ error = brute_prctl_enable();
+ break;
+ case PR_SECURITY_FORK_BRUTE_DISABLE:
+ error = brute_prctl_disable();
+ break;
default:
error = -EINVAL;
break;
@@ -676,3 +676,74 @@ DEFINE_LSM(brute) = {
.blobs = &brute_blob_sizes,
};
+/**
+ * brute_prctl_enable() - Enable the fork brute force attack detection.
+ *
+ * To enable the fork brute force attack detection the last crashes timestamps
+ * list must not be empty. So, if this list already contains entries nothing
+ * needs to be done. Otherwise, initialize the last crashes timestamps list with
+ * one entry set to now. This way, the application crash period can be computed
+ * at the next fault.
+ *
+ * It's mandatory to disable interrupts before acquiring the lock since the
+ * task_free hook can be called from an IRQ context during the execution of the
+ * prctl syscall.
+ *
+ * Return: -EFAULT if the current task doesn't have statistical data. -ENOMEM if
+ * the allocation of the new timestamp structure fails. Zero otherwise.
+ */
+int brute_prctl_enable(void)
+{
+ struct brute_stats **stats;
+ struct brute_timestamp *timestamp;
+ unsigned long flags;
+
+ stats = brute_stats_ptr(current);
+ if (!*stats)
+ return -EFAULT;
+
+ timestamp = brute_new_timestamp();
+ if (!timestamp)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&(*stats)->lock, flags);
+
+ if (!list_empty(&(*stats)->timestamps)) {
+ kfree(timestamp);
+ goto unlock;
+ }
+
+ list_add_tail(×tamp->node, &(*stats)->timestamps);
+ (*stats)->timestamps_size = 1;
+
+unlock:
+ spin_unlock_irqrestore(&(*stats)->lock, flags);
+ return 0;
+}
+
+/**
+ * brute_prctl_disable() - Disable the fork brute force attack detection.
+ *
+ * It's mandatory to disable interrupts before acquiring the lock since the
+ * task_free hook can be called from an IRQ context during the execution of the
+ * prctl syscall.
+ *
+ * Return: -EFAULT if the current task doesn't have statistical data. Zero
+ * otherwise.
+ */
+int brute_prctl_disable(void)
+{
+ struct brute_stats **stats;
+ unsigned long flags;
+
+ stats = brute_stats_ptr(current);
+ if (!*stats)
+ return -EFAULT;
+
+ spin_lock_irqsave(&(*stats)->lock, flags);
+ brute_disable(*stats);
+ spin_unlock_irqrestore(&(*stats)->lock, flags);
+
+ return 0;
+}
+
To allow that a process can turn off or turn on the detection and mitigation of a fork brute force attack when required, add two new defines to the prctl interface. All the arguments passed to the prctl system call are ignored for the two new cases. To enable the attack detection make the last crashes timestamps list not empty. To disable the detection use the already created brute_disable() function. Signed-off-by: John Wood <john.wood@gmx.com> --- include/brute/brute.h | 16 +++++++++ include/uapi/linux/prctl.h | 4 +++ kernel/sys.c | 8 +++++ security/brute/brute.c | 71 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 include/brute/brute.h -- 2.25.1