Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20201025134540.3770-7-john.wood@gmx.com>
Date: Sun, 25 Oct 2020 14:45:38 +0100
From: John Wood <john.wood@....com>
To: Kees Cook <keescook@...omium.org>,
	Jann Horn <jannh@...gle.com>
Cc: John Wood <john.wood@....com>,
	Jonathan Corbet <corbet@....net>,
	James Morris <jmorris@...ei.org>,
	"Serge E. Hallyn" <serge@...lyn.com>,
	linux-doc@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	linux-security-module@...r.kernel.org,
	kernel-hardening@...ts.openwall.com
Subject: [PATCH v2 6/8] security/brute: Add prctls to enable/disable the fork attack detection

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@....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

diff --git a/include/brute/brute.h b/include/brute/brute.h
new file mode 100644
index 000000000000..da6fca04f16b
--- /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/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_ */
+
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 07b4f8131e36..01f5033210d0 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.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 */
diff --git a/kernel/sys.c b/kernel/sys.c
index ab6c409b1159..35dae4e2f59a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -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;
diff --git a/security/brute/brute.c b/security/brute/brute.c
index a1bdf25ffcf9..6f85e137553c 100644
--- a/security/brute/brute.c
+++ b/security/brute/brute.c
@@ -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(&timestamp->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;
+}
+
--
2.25.1

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.