From patchwork Fri May 21 17:24:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Wood X-Patchwork-Id: 12273473 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2497BC4707A for ; Fri, 21 May 2021 17:45:12 +0000 (UTC) Received: from mother.openwall.net (mother.openwall.net [195.42.179.200]) by mail.kernel.org (Postfix) with SMTP id D7F5E6135C for ; Fri, 21 May 2021 17:45:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D7F5E6135C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmx.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernel-hardening-return-21264-kernel-hardening=archiver.kernel.org@lists.openwall.com Received: (qmail 28009 invoked by uid 550); 21 May 2021 17:45:04 -0000 Mailing-List: contact kernel-hardening-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-ID: Received: (qmail 27974 invoked from network); 21 May 2021 17:45:03 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1621619081; bh=NR7CetDZEJKb4urZklHxpJH9CQk1kXh04lqUmzV2VFQ=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=LIKmMCBqqVRET39SSM0370jbmdCYupse/pATJDXGAt9BgYsN+IrUzCiS/kMFOXeZf QkG/tomfiuQipPlYovQ2/1zKi31S6znfNUGpTx/U0O4krKGXl+RM6QcUEObdK9FPSn q/aDdkdwt6gokF8mG8u0JVYiMEhcEOpVZiS/0neU= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c From: John Wood To: Kees Cook , Jann Horn , Jonathan Corbet , James Morris , "Serge E. Hallyn" , Shuah Khan Cc: John Wood , Andi Kleen , valdis.kletnieks@vt.edu, Greg Kroah-Hartman , Randy Dunlap , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-hardening@vger.kernel.org, kernel-hardening@lists.openwall.com Subject: [PATCH v7 2/7] security/brute: Define a LSM and add sysctl attributes Date: Fri, 21 May 2021 19:24:09 +0200 Message-Id: <20210521172414.69456-3-john.wood@gmx.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210521172414.69456-1-john.wood@gmx.com> References: <20210521172414.69456-1-john.wood@gmx.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:dHBeZqKBH5p0TcaXbrstKdGyyd/PDgfJ4pllDUkxJomNf1zrhQS wEwmAdIcTPVCLq5r85oIJzyvZiXhzvdfFQG6rQcpAFsqkKAY65ukfTL0amIk33gCswxD7uo HFgOO0hlvXZSXkvcwhrKixek/fZE9+DKCifW73SO6lE1X/1HVhCDhXag/9axuiYVrzaSlj8 ZxeGZMHpJqbnVUpk+pnug== X-UI-Out-Filterresults: notjunk:1;V03:K0:SLwDhqiwQPo=:NncsFwf/hAeSlE45N0sg2O 2sgmkBoIdegPQSagAZCIIqH4k1dy8NMENnN9xJ5p+GOH9fNPmb3xK7qqEIgHthB5MjsW7FZHy WZVTU5vUSjz5IXaKfkYEROf9HsXHw3mHXVYcnkE9I1FFH5Sx7eAydmN1irjeNETQOeSIl6r/K tGJEHRnRmvySjBPocVh8FVhplTrkEpaLGcDv9YQ8ZKKVkoTOH18svj3voUR/rW5Xo15Fx+ThO ipqy9lljKXtzSML6cu4Av2+o5WDwTuOOlDhY6xd0uJ2+iW17GNHU21JDBnBNenzNO3OPTE53y OZpAmARmh87jlYPjtTR98jJGQaZZ1ZwzXxe7bT1IwZTZHCGWxmuiOQzfJY9qIsfaAgKcmTtYz nH6Bh6DZSn+E6NloAHsaADCks3Zl7GxyXNjl/+V7QeSUqr3WMPqy4i2nimZd3ijCSrcmZH6Fv Wwf5C7pXwhPB3yp10fKJp/piPSG5R7uDAshAC90YlVpzMz4Iu6XUNzIkCiVZXwnxg0+YBYzsU tz2PMqoNaZcdy4ZfVqPunp8XdHL4XCQXCxsMbZuYFMOV4PV8uq6fzgiELuUOSrkb1uqI403RI WioE8j5YvDgnQcXIgIoPyAgP2gZi6/QeMhvwsy4jWOFBh9T67qnUtUVQSVyGbqz+evpUZx7eB h++SehlSLLTtJKY8o8ieE+HuKNRJgszIuxUB+QoSJN9GaIE6JHyULZW4zksGJlHI0yJ8X7Qg7 zpL69bUZAMZPklsyqwUcLG8XL9O9mcRYIVsL7w7JlwWYTHOsLKoYYvgxv85QR3+nRfD+ZdOUg GY7q51YX24Q853NfkMiRtFiG3SYJT+X7ON41mimP3MDtckeXG81cgh6ESVbww0SIL/0HcIzuG DAZTtPPnca1of3cMilIrRhYmo1lGbhsFlvAzxjZRIau6BPQksMSyjBbt87vYSv59WBAjYcfZ7 tq/XP/v9z0p+A35FbLgdVxmta+w7c9glpZCN98EHEBeP0dTtmjcVGxe6aapvKGZYuq70VxNXG uLPLGyKLOSuyA3bucSookEaQlKYfheQKkiy9XSIsOgfFHK3paIFo4w9BpRE36RrHlh7MJ4Awj JWthOKHZSKOCkUdqqo7IVcSuC9MAixs4XV+ Add a new Kconfig file to define a menu entry under "Security options" to enable the "Fork brute force attack detection and mitigation" feature. The detection of a brute force attack can be based on the number of faults per application and its crash rate. There are two types of brute force attacks that can be detected. The first one is a slow brute force attack that is detected if the maximum number of faults per fork hierarchy is reached. The second type is a fast brute force attack that is detected if the application crash period falls below a certain threshold. The application crash period must be a value that is not prone to change due to spurious data and follows the real crash period. So, to compute it, the exponential moving average (EMA) will be used. This kind of average defines a weight (between 0 and 1) for the new value to add and applies the remainder of the weight to the current average value. This way, some spurious data will not excessively modify the average and only if the new values are persistent, the moving average will tend towards them. Mathematically the application crash period's EMA can be expressed as follows: period_ema = period * weight + period_ema * (1 - weight) Moreover, it is important to note that a minimum number of faults is needed to guarantee a trend in the crash period when the EMA is used. So, based on all the previous information define a LSM with five sysctl attributes that will be used to fine tune the attack detection. ema_weight_numerator ema_weight_denominator max_faults min_faults crash_period_threshold This patch is a previous step on the way to fine tune the attack detection. Signed-off-by: John Wood --- security/Kconfig | 11 +-- security/Makefile | 2 + security/brute/Kconfig | 14 ++++ security/brute/Makefile | 2 + security/brute/brute.c | 147 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 security/brute/Kconfig create mode 100644 security/brute/Makefile create mode 100644 security/brute/brute.c -- 2.25.1 diff --git a/security/Kconfig b/security/Kconfig index 0ced7fd33e4d..2df1727f2c2c 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -241,6 +241,7 @@ source "security/lockdown/Kconfig" source "security/landlock/Kconfig" source "security/integrity/Kconfig" +source "security/brute/Kconfig" choice prompt "First legacy 'major LSM' to be initialized" @@ -278,11 +279,11 @@ endchoice config LSM string "Ordered list of enabled LSMs" - default "landlock,lockdown,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK - default "landlock,lockdown,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR - default "landlock,lockdown,yama,loadpin,safesetid,integrity,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO - default "landlock,lockdown,yama,loadpin,safesetid,integrity,bpf" if DEFAULT_SECURITY_DAC - default "landlock,lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf" + default "landlock,lockdown,brute,yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor,bpf" if DEFAULT_SECURITY_SMACK + default "landlock,lockdown,brute,yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo,bpf" if DEFAULT_SECURITY_APPARMOR + default "landlock,lockdown,brute,yama,loadpin,safesetid,integrity,tomoyo,bpf" if DEFAULT_SECURITY_TOMOYO + default "landlock,lockdown,brute,yama,loadpin,safesetid,integrity,bpf" if DEFAULT_SECURITY_DAC + default "landlock,lockdown,brute,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor,bpf" help A comma-separated list of LSMs, in initialization order. Any LSMs left off this list will be ignored. This can be diff --git a/security/Makefile b/security/Makefile index 47e432900e24..94d325256413 100644 --- a/security/Makefile +++ b/security/Makefile @@ -14,6 +14,7 @@ subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid subdir-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown subdir-$(CONFIG_BPF_LSM) += bpf subdir-$(CONFIG_SECURITY_LANDLOCK) += landlock +subdir-$(CONFIG_SECURITY_FORK_BRUTE) += brute # always enable default capabilities obj-y += commoncap.o @@ -34,6 +35,7 @@ obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/ obj-$(CONFIG_CGROUPS) += device_cgroup.o obj-$(CONFIG_BPF_LSM) += bpf/ obj-$(CONFIG_SECURITY_LANDLOCK) += landlock/ +obj-$(CONFIG_SECURITY_FORK_BRUTE) += brute/ # Object integrity file lists subdir-$(CONFIG_INTEGRITY) += integrity diff --git a/security/brute/Kconfig b/security/brute/Kconfig new file mode 100644 index 000000000000..5da314d221aa --- /dev/null +++ b/security/brute/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0 +config SECURITY_FORK_BRUTE + bool "Fork brute force attack detection and mitigation" + depends on SECURITY + help + This is an LSM that stops any fork brute force attack against + vulnerable userspace processes. The detection method is based on + the application crash period and as a mitigation procedure all the + offending tasks are killed. Also, the executable file involved in the + attack will be marked as "not allowed" and new execve system calls + using this file will fail. Like capabilities, this security module + stacks with other LSMs. + + If you are unsure how to answer this question, answer N. diff --git a/security/brute/Makefile b/security/brute/Makefile new file mode 100644 index 000000000000..d3f233a132a9 --- /dev/null +++ b/security/brute/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_SECURITY_FORK_BRUTE) += brute.o diff --git a/security/brute/brute.c b/security/brute/brute.c new file mode 100644 index 000000000000..0edb89a58ab0 --- /dev/null +++ b/security/brute/brute.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include + +/** + * DOC: brute_ema_weight_numerator + * + * Weight's numerator of EMA. + */ +static unsigned int brute_ema_weight_numerator __read_mostly = 7; + +/** + * DOC: brute_ema_weight_denominator + * + * Weight's denominator of EMA. + */ +static unsigned int brute_ema_weight_denominator __read_mostly = 10; + +/** + * DOC: brute_max_faults + * + * Maximum number of faults. + * + * If a brute force attack is running slowly for a long time, the application + * crash period's EMA is not suitable for the detection. This type of attack + * must be detected using a maximum number of faults. + */ +static unsigned int brute_max_faults __read_mostly = 200; + +/** + * DOC: brute_min_faults + * + * Minimum number of faults. + * + * The application crash period's EMA cannot be used until a minimum number of + * data has been applied to it. This constraint allows getting a trend when this + * moving average is used. + */ +static unsigned int brute_min_faults __read_mostly = 5; + +/** + * DOC: brute_crash_period_threshold + * + * Application crash period threshold. + * + * A fast brute force attack is detected when the application crash period falls + * below this threshold. The units are expressed in seconds. + */ +static unsigned int brute_crash_period_threshold __read_mostly = 30; + +#ifdef CONFIG_SYSCTL +static unsigned int uint_max = UINT_MAX; +#define SYSCTL_UINT_MAX (&uint_max) + +/* + * brute_sysctl_path - Sysctl attributes path. + */ +static struct ctl_path brute_sysctl_path[] = { + { .procname = "kernel", }, + { .procname = "brute", }, + { } +}; + +/* + * brute_sysctl_table - Sysctl attributes. + */ +static struct ctl_table brute_sysctl_table[] = { + { + .procname = "ema_weight_numerator", + .data = &brute_ema_weight_numerator, + .maxlen = sizeof(brute_ema_weight_numerator), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = &brute_ema_weight_denominator, + }, + { + .procname = "ema_weight_denominator", + .data = &brute_ema_weight_denominator, + .maxlen = sizeof(brute_ema_weight_denominator), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = &brute_ema_weight_numerator, + .extra2 = SYSCTL_UINT_MAX, + }, + { + .procname = "max_faults", + .data = &brute_max_faults, + .maxlen = sizeof(brute_max_faults), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = &brute_min_faults, + .extra2 = SYSCTL_UINT_MAX, + }, + { + .procname = "min_faults", + .data = &brute_min_faults, + .maxlen = sizeof(brute_min_faults), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = SYSCTL_ONE, + .extra2 = &brute_max_faults, + }, + { + .procname = "crash_period_threshold", + .data = &brute_crash_period_threshold, + .maxlen = sizeof(brute_crash_period_threshold), + .mode = 0644, + .proc_handler = proc_douintvec_minmax, + .extra1 = SYSCTL_ONE, + .extra2 = SYSCTL_UINT_MAX, + }, + { } +}; + +/** + * brute_init_sysctl() - Initialize the sysctl interface. + */ +static void __init brute_init_sysctl(void) +{ + if (!register_sysctl_paths(brute_sysctl_path, brute_sysctl_table)) + panic("sysctl registration failed\n"); +} + +#else +static inline void brute_init_sysctl(void) { } +#endif /* CONFIG_SYSCTL */ + +/** + * brute_init() - Initialize the brute LSM. + * + * Return: Always returns zero. + */ +static int __init brute_init(void) +{ + pr_info("becoming mindful\n"); + brute_init_sysctl(); + return 0; +} + +DEFINE_LSM(brute) = { + .name = KBUILD_MODNAME, + .init = brute_init, +};