From patchwork Sat Jul 6 10:54:42 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033579 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8CE5613BD for ; Sat, 6 Jul 2019 10:55:14 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7BE0F2881B for ; Sat, 6 Jul 2019 10:55:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7038328A27; Sat, 6 Jul 2019 10:55:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,GAPPY_SUBJECT,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 795A12881B for ; Sat, 6 Jul 2019 10:55:13 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 8F60A6B0006; Sat, 6 Jul 2019 06:55:12 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 8A61C8E0003; Sat, 6 Jul 2019 06:55:12 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 7957F8E0001; Sat, 6 Jul 2019 06:55:12 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by kanga.kvack.org (Postfix) with ESMTP id 2BE7C6B0006 for ; Sat, 6 Jul 2019 06:55:12 -0400 (EDT) Received: by mail-wr1-f71.google.com with SMTP id w11so5002885wrl.7 for ; Sat, 06 Jul 2019 03:55:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=LSDyibP1XVZpeGT3DZYqEdlxulsdBlWaxtrr4VNl6oY=; b=P6PEbDTnHWiNEXFPoeYn6Ll9RuhM2cw2BFb23ijOiO1s61gUf1QcoN+hFXuujendvK IxsLdj1nNK2x8oShp4wHd8kSxTN15o4a1ScMxFJbOQBB5Ri+GVqAyLkOn5WstNXc6w4E lyMds18ydquakNCG3jPIRa8J/DaEwlD91bmC7uRTF/lTt7Cqf+9ViLGs/gIidwOrhMyB dWmNJaneyPcu5be1fOaJ3NtKqOqkzpCW3pA9TZ08RqW/d2tPvF6W+cLEPt7OryaqrLR2 F1fodGLar3StzMWnSoLSau/SttysRMQOugLrwAiEg2qvflpxD7xGkyA8IcgApQiVfuTO Ziog== X-Gm-Message-State: APjAAAWTUtEw28oO+9tvpieuLlEv3GGAKkVa2DLvFT+j5xNO+xzGPsZ3 vQyrwiJHfSSgGVsHsV7vLwdi9NyU//1tp2HOAsT4awpdidst5UtL5nKu5T5k0RniJHGx6qNr2ED qIRJRXznoslUGm5IH19v6Ud+e1BH/Pq56PcOkJY6hSKEmqwzEFv9gvmZqHFX2j6v78A== X-Received: by 2002:a1c:f102:: with SMTP id p2mr7589864wmh.126.1562410511698; Sat, 06 Jul 2019 03:55:11 -0700 (PDT) X-Received: by 2002:a1c:f102:: with SMTP id p2mr7589717wmh.126.1562410509794; Sat, 06 Jul 2019 03:55:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410509; cv=none; d=google.com; s=arc-20160816; b=RGxlwj0Vz8vaI4crFXRbLWL8vYFeUy71DSUcNdQmDDkt2RBTwt1pYiaHuAt/Oe6oAa Y4aAIASLPxb69YePNUeEwjIrYR9fLFyMKitYzc0iWcbCyvZ0MkTjXNey+v8RTlikSPzt J/7ZHIDXilqgm8kPfc31wKcY0Ji/qT20Pm/QysAEmJPb2HQCoLKseg+n/5GJemSShZg3 WKpmOouO1N/3QzXKkq0fMHLyXF5JjOnDCn0MBVditZQfiUvCqQxyfeCkRQtAFB7o3qqd w8ydYzlkMY2hjmeuHn9rbjJqBHp/R0lQRhl3S44q581ZkoS5nOSpX1+vscKDsP9ZTo8j ZWkg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=LSDyibP1XVZpeGT3DZYqEdlxulsdBlWaxtrr4VNl6oY=; b=wI5hAKrjMBRwT3ox4ZAIim422AIBfRtpfXNWh6/JuuIhYlL+PbYVbZNQkmQQkHROf/ 7o+mwAuXDULwYivy4f+XXezxmH+EwnlYRxmAmWLCGiXgouon0aLd9rzrN55/Jvi/0D0y GnbNoGRdaUwA7aF8Yy9L3v4QH2GZXkpQPYRxV7u6FCqPoRdgL2RywYpYHISS6RM0zaXm y3EXSck6XZFjm7ou9oYAudbbFAJpfcboBvdRQgP2Lvm6jk5C29s8cetQZ30nsFdQI86E VkeeCEyGdsoZH3CfCoyw+ZValKSigEvIH35IiE0ulAUp2SNQ23VzPOFAX9GVpFrXPKT8 7pew== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=c02v5eGe; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id p2sor6319362wma.27.2019.07.06.03.55.09 for (Google Transport Security); Sat, 06 Jul 2019 03:55:09 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=c02v5eGe; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=LSDyibP1XVZpeGT3DZYqEdlxulsdBlWaxtrr4VNl6oY=; b=c02v5eGeCj5HbIEAdudQQjgbzUrq82XXgqCQ02NBUHo1JB4D/SfUo+Z7GnKdKCG/Av 1TtgEsaynVkfr+x9paW1rL3z7p2ESzYOOaqNhFI3/QxVW7oCHm6H+PtJF20Bz7JZfP96 tvXanRd/k0QIHCtd/nmbdcG4n/dA95D7A8BhmxrBxtmLrkg/W+EbSrV62ApXeI4qX1X+ tFRNas3NgtrAATMdKmVNQC/UT5t4rXrFeF7rSbH390TA/WC2eUBLRgq8Z8p/F/YVkew9 LJ0Nt0lHbZakmefJNnCwKjtqkdNRKOHI5AA2BtLw7ifnr7IRYZ2GZWFiBYXeytfe6PS+ o3dw== X-Google-Smtp-Source: APXvYqyxuovPbriEIhLSokjppZ1C87fwAjiJaQfHFYTH//jwFs40w+Dju5jKKRQe/vcnd9FsB8CHMA== X-Received: by 2002:a7b:c954:: with SMTP id i20mr6912798wml.169.1562410509333; Sat, 06 Jul 2019 03:55:09 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:08 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 01/12] S.A.R.A.: add documentation Date: Sat, 6 Jul 2019 12:54:42 +0200 Message-Id: <1562410493-8661-2-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Adding documentation for S.A.R.A. LSM. Signed-off-by: Salvatore Mesoraca --- Documentation/admin-guide/LSM/SARA.rst | 177 ++++++++++++++++++++++++ Documentation/admin-guide/LSM/index.rst | 1 + Documentation/admin-guide/kernel-parameters.txt | 24 ++++ 3 files changed, 202 insertions(+) create mode 100644 Documentation/admin-guide/LSM/SARA.rst diff --git a/Documentation/admin-guide/LSM/SARA.rst b/Documentation/admin-guide/LSM/SARA.rst new file mode 100644 index 0000000..fdde04c --- /dev/null +++ b/Documentation/admin-guide/LSM/SARA.rst @@ -0,0 +1,177 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======== +S.A.R.A. +======== + +S.A.R.A. (S.A.R.A. is Another Recursive Acronym) is a stacked Linux Security +Module that aims to collect heterogeneous security measures, providing a common +interface to manage them. +As of today it consists of one submodule: + +- WX Protection + + +The kernel-space part is complemented by its user-space counterpart: `saractl` +[2]_. +A test suite for WX Protection, called `sara-test` [4]_, is also available. +More information about where to find these tools and the full S.A.R.A. +documentation are in the `External Links and Documentation`_ section. + +------------------------------------------------------------------------------- + +S.A.R.A.'s Submodules +===================== + +WX Protection +------------- +WX Protection aims to improve user-space programs security by applying: + +- `W^X enforcement`_ +- `W!->X (once writable never executable) mprotect restriction`_ +- `Executable MMAP prevention`_ + +All of the above features can be enabled or disabled both system wide +or on a per executable basis through the use of configuration files managed by +`saractl` [2]_. + +It is important to note that some programs may have issues working with +WX Protection. In particular: + +- **W^X enforcement** will cause problems to any programs that needs + memory pages mapped both as writable and executable at the same time e.g. + programs with executable stack markings in the *PT_GNU_STACK* segment. +- **W!->X mprotect restriction** will cause problems to any program that + needs to generate executable code at run time or to modify executable + pages e.g. programs with a *JIT* compiler built-in or linked against a + *non-PIC* library. +- **Executable MMAP prevention** can work only with programs that have at least + partial *RELRO* support. It's disabled automatically for programs that + lack this feature. It will cause problems to any program that uses *dlopen* + or tries to do an executable mmap. Unfortunately this feature is the one + that could create most problems and should be enabled only after careful + evaluation. + +To extend the scope of the above features, despite the issues that they may +cause, they are complemented by **/proc/PID/attr/sara/wxprot** interface +and **trampoline emulation**. + +At the moment, WX Protection (unless specified otherwise) should work on +any architecture supporting the NX bit, including, but not limited to: +`x86_64`, `x86_32` (with PAE), `ARM` and `ARM64`. + +Parts of WX Protection are inspired by some of the features available in PaX. + +For further information about configuration file format and user-space +utilities please take a look at the full documentation [1]_. + +W^X enforcement +^^^^^^^^^^^^^^^ +W^X means that a program can't have a page of memory that is marked, at the +same time, writable and executable. This also allow to detect many bad +behaviours that make life much more easy for attackers. Programs running with +this feature enabled will be more difficult to exploit in the case they are +affected by some vulnerabilities, because the attacker will be forced +to make more steps in order to exploit them. +This feature also blocks accesses to /proc/*/mem files that would allow to +write the current process read-only memory, bypassing any protection. + +W!->X (once writable never executable) mprotect restriction +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +"Once writable never executable" means that any page that could have been +marked as writable in the past won't ever be allowed to be marked (e.g. via +an mprotect syscall) as executable. +This goes on the same track as W^X, but is much stricter and prevents +the runtime creation of new executable code in memory. +Obviously, this feature does not prevent a program from creating a new file and +*mmapping* it as executable, however, it will be way more difficult for +attackers to exploit vulnerabilities if this feature is enabled. + +Executable MMAP prevention +^^^^^^^^^^^^^^^^^^^^^^^^^^ +This feature prevents the creation of new executable mmaps after the dynamic +libraries have been loaded. When used in combination with **W!->X mprotect +restriction** this feature will completely prevent the creation of new +executable code from the current thread. +Obviously, this feature does not prevent cases in which an attacker uses an +*execve* to start a completely new program. This kind of restriction, if +needed, can be applied using one of the other LSM that focuses on MAC. +Please be aware that this feature can break many programs and so it should be +enabled after careful evaluation. + +/proc/PID/attr/sara/wxprot interface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The `procattr` interface can be used by a thread to discover which +WX Protection features are enabled and/or to tighten them: protection +can't be softened via procattr. +The interface is simple: it's a text file with an hexadecimal +number in it representing enabled features (more information can be +found in the `Flags values`_ section). Via this interface it is also +possible to perform a complete memory scan to remove the write permission +from pages that are both writable and executable, please note that this +change will also affect other threads of the same process. + +Protections that prevent the runtime creation of executable code +can be troublesome for all those programs that actually need to do it +e.g. programs shipping with a JIT compiler built-in. +This feature can be use to run the JIT compiler with few restrictions +while enforcing full WX Protection in the rest of the program. + +The preferred way to access this interface is via `libsara` [3]_. +If you don't want it as a dependency, you can just statically link it +in your project or copy/paste parts of it. +To make things simpler `libsara` is the only part of S.A.R.A. released under +*CC0 - No Rights Reserved* license. + +Trampoline emulation +^^^^^^^^^^^^^^^^^^^^ +Some programs need to generate part of their code at runtime. Luckily enough, +in some cases they only generate well-known code sequences (the +*trampolines*) that can be easily recognized and emulated by the kernel. +This way WX Protection can still be active, so a potential attacker won't be +able to generate arbitrary sequences of code, but just those that are +explicitly allowed. This is not ideal, but it's still better than having WX +Protection completely disabled. + +In particular S.A.R.A. is able to recognize trampolines used by GCC for nested +C functions and libffi's trampolines. +This feature is available only on `x86_32` and `x86_64`. + +Flags values +^^^^^^^^^^^^ +Flags are represented as a 16 bit unsigned integer in which every bit indicates +the status of a given feature: + ++------------------------------+----------+ +| Feature | Value | ++==============================+==========+ +| W!->X Heap | 0x0001 | ++------------------------------+----------+ +| W!->X Stack | 0x0002 | ++------------------------------+----------+ +| W!->X Other memory | 0x0004 | ++------------------------------+----------+ +| W^X | 0x0008 | ++------------------------------+----------+ +| Don't enforce, just complain | 0x0010 | ++------------------------------+----------+ +| Be Verbose | 0x0020 | ++------------------------------+----------+ +| Executable MMAP prevention | 0x0040 | ++------------------------------+----------+ +| Force W^X on setprocattr | 0x0080 | ++------------------------------+----------+ +| Trampoline emulation | 0x0100 | ++------------------------------+----------+ +| Children will inherit flags | 0x0200 | ++------------------------------+----------+ + +------------------------------------------------------------------------------- + +External Links and Documentation +================================ + +.. [1] `Documentation `_ +.. [2] `saractl `_ +.. [3] `libsara `_ +.. [4] `sara-test `_ diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst index a6ba95f..81b50e4 100644 --- a/Documentation/admin-guide/LSM/index.rst +++ b/Documentation/admin-guide/LSM/index.rst @@ -47,3 +47,4 @@ subdirectories. tomoyo Yama SafeSetID + SARA diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 138f666..3d6e86d 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4230,6 +4230,30 @@ 1 -- enable. Default value is set via kernel config option. + sara.enabled= [SARA] Disable or enable S.A.R.A. at boot time. + If disabled this way S.A.R.A. can't be enabled + again. + Format: { "0" | "1" } + See security/sara/Kconfig help text + 0 -- disable. + 1 -- enable. + Default value is set via kernel config option. + + sara.wxprot_enabled= [SARA] + Disable or enable S.A.R.A. WX Protection + at boot time. + Format: { "0" | "1" } + See security/sara/Kconfig help text + 0 -- disable. + 1 -- enable. + Default value is set via kernel config option. + + sara.wxprot_default_flags= [SARA] + Set S.A.R.A. WX Protection default flags. + Format: + See S.A.R.A. documentation. + Default value is set via kernel config option. + serialnumber [BUGS=X86-32] shapers= [NET] From patchwork Sat Jul 6 10:54:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033589 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1030914F6 for ; Sat, 6 Jul 2019 10:55:24 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EF8502881B for ; Sat, 6 Jul 2019 10:55:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E0D9D28A26; Sat, 6 Jul 2019 10:55:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,GAPPY_SUBJECT,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AC4AC2881B for ; Sat, 6 Jul 2019 10:55:21 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 720806B0008; Sat, 6 Jul 2019 06:55:18 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 6D3BE8E0003; Sat, 6 Jul 2019 06:55:18 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 526EA8E0001; Sat, 6 Jul 2019 06:55:18 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by kanga.kvack.org (Postfix) with ESMTP id E3CEF6B0008 for ; Sat, 6 Jul 2019 06:55:17 -0400 (EDT) Received: by mail-wr1-f72.google.com with SMTP id b1so5020183wru.4 for ; Sat, 06 Jul 2019 03:55:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=BW+8xpyQbi7Tl8ElYIH8BHwSiQojAb3nUmPsO54K1pU=; b=QLDvR/mr0B9fpGyRmFVen0UpHS0vGT3lPI5to+dgbKIa3xcM6rvtIuc2IQBnfF6L80 eWMYclSZO296I11Q2HnnAKMndid/9AW3Kb4u7Hq0CUrxOzwaV5OQSYMvCHL5T9LOzhFG QORj3gTS73sLr0cWnJYyEjvo/QFiwJOkSBpp3uHLlSsShk+BLtCkQYKXvrRj56KdvCMJ 9qCsDn49gQyqa1PM20QEa8GlMBrSLG0yiHda47HxPFRCJyO1/p8AfIFZpwltFanv4ayd La1/RBtrG5FwnHFRkERJX+TtUvK5kIoaEEnqJvpHTiB2G1IV6K1LUAkTSXycqHDD2DY3 dqNw== X-Gm-Message-State: APjAAAVqNW73ZGW03GzQa0JJs1Vzth6pHO6I1cqmsyceSaBwgde7oufl rmvr8k8zvqiCq0+eY4VLlxV2HkavVVSaC4XUjPq2QukKCyLGaSA9bKq8P7qty7zH75z49BMwfp8 o/ue4KDok9KqXDPv9AJ1xaBGMyvLf9CUCgVx7TbBs4oXPuExnWuqAvoyJ2ZMvkkcFhQ== X-Received: by 2002:a7b:cc04:: with SMTP id f4mr8027692wmh.125.1562410517407; Sat, 06 Jul 2019 03:55:17 -0700 (PDT) X-Received: by 2002:a7b:cc04:: with SMTP id f4mr8027469wmh.125.1562410514746; Sat, 06 Jul 2019 03:55:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410514; cv=none; d=google.com; s=arc-20160816; b=Jn/vjDpac6NKt5ay7iCJk+issvNaD0Lgmh3hNdMp4y616FfaUJTK28k7pr92Hg7Iz8 SJc4JfQPp+Vh0P5wsgLmO5kavL+jgy/GhYd+SCKimhZNRUh1sszljpZqHRkhN7Sk0lt9 0lqYxmyEKZWoZwKE/BmKvGA81ad7drvEzbH5z5YVlh+xOYOvzhzwq7qufmfc1kk9jCGU foeIhXzQcRER1QWJC+pgG6VK879wDXYcS9R3x1zHGZod0+Ax65t8To4egxGB+Dd5lgid zCFnWShbPm/wtU+uy/APRS6eCJI1IebDN/A0gSSEVOBZvL5hdROMmDKd3cyFLgK8gUm5 Ilow== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=BW+8xpyQbi7Tl8ElYIH8BHwSiQojAb3nUmPsO54K1pU=; b=OmHtxloDh/JuEqTXnpmOPOc5wQAtdd45RbWpwIzGavQPpCS8qYFdPsYQs2A1BUiBbp 0KaJGPnAiLHw772Hbk8BxgeK1HwoJD7ebsK5W8QvP7ar7KRQAapD1XYHwv1OkUe47yey VB10Iv9HjH5+c0ZUexKNGQ0by96pfmKIUq2tGZvl6wvQ0ki2vDEuzXfhKTGs2zqAR/X3 irUrDFFuvd6/htlNwToBmYfyFIvyHG8z8LTWAalcRjlYfgHcFRvCGgDnUdLnR9yHiFkV AkXzPlhSnjE9/3MGvUxP2ee2nmYyErZ+GDnZo0yAYjODCK9nEXydWIXv3sqN1aslrAy+ 002Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b="Gy5TPt6/"; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id q14sor8520936wro.49.2019.07.06.03.55.14 for (Google Transport Security); Sat, 06 Jul 2019 03:55:14 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b="Gy5TPt6/"; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=BW+8xpyQbi7Tl8ElYIH8BHwSiQojAb3nUmPsO54K1pU=; b=Gy5TPt6/txGbLsMhEqym/m39JJLOPOcUp33pKsBXIoOfib1/thpFoahS2bYRfcTk3z YNCV71Qgi/dESSZ5Cid+OeLB1kL5AdVmRTO1vtsKAzliLqu7E7guphMsmUBivmlCBN9g xXzIOQiEkfK/fwXB37ZloNWywr4ijHxf18F1oIlU9mdS91Ib1dAwG4QSrlNu3fnRfpnt 3p7hdKEu8kHcCxudsUWLovvcISlvkL1gmsmZp3MnaoXR7hhnPpsk7hzk0La7U/SOhyJv xup3QV0T0CwQ7M6Z2iZnyYkyuKJsml23601/JLFeKW/SNDL3jpiboPC6IzfY0EGKVst3 ko2g== X-Google-Smtp-Source: APXvYqy1ogO8dZ6NgaXXKK6DDQbYjudAU/lxFkXrHqpSoq4/f+IV71mZjPvf6fXPReqkMC7l8mLNCQ== X-Received: by 2002:a5d:468a:: with SMTP id u10mr8850925wrq.177.1562410514014; Sat, 06 Jul 2019 03:55:14 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:13 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 02/12] S.A.R.A.: create framework Date: Sat, 6 Jul 2019 12:54:43 +0200 Message-Id: <1562410493-8661-3-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Initial S.A.R.A. framework setup. Creation of a simplified interface to securityfs API to store and retrieve configurations and flags from user-space. Creation of some generic functions and macros to handle concurrent access to configurations, memory allocation and path resolution. Signed-off-by: Salvatore Mesoraca --- security/Kconfig | 11 +- security/Makefile | 2 + security/sara/Kconfig | 40 +++ security/sara/Makefile | 3 + security/sara/include/sara.h | 29 ++ security/sara/include/securityfs.h | 61 ++++ security/sara/include/utils.h | 80 ++++++ security/sara/main.c | 115 ++++++++ security/sara/securityfs.c | 565 +++++++++++++++++++++++++++++++++++++ security/sara/utils.c | 92 ++++++ 10 files changed, 993 insertions(+), 5 deletions(-) create mode 100644 security/sara/Kconfig create mode 100644 security/sara/Makefile create mode 100644 security/sara/include/sara.h create mode 100644 security/sara/include/securityfs.h create mode 100644 security/sara/include/utils.h create mode 100644 security/sara/main.c create mode 100644 security/sara/securityfs.c create mode 100644 security/sara/utils.c diff --git a/security/Kconfig b/security/Kconfig index 466cc1f..4cae0ec 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -237,6 +237,7 @@ source "security/apparmor/Kconfig" source "security/loadpin/Kconfig" source "security/yama/Kconfig" source "security/safesetid/Kconfig" +source "security/sara/Kconfig" source "security/integrity/Kconfig" @@ -276,11 +277,11 @@ endchoice config LSM string "Ordered list of enabled LSMs" - default "yama,loadpin,safesetid,integrity,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK - default "yama,loadpin,safesetid,integrity,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR - default "yama,loadpin,safesetid,integrity,tomoyo" if DEFAULT_SECURITY_TOMOYO - default "yama,loadpin,safesetid,integrity" if DEFAULT_SECURITY_DAC - default "yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" + default "yama,loadpin,safesetid,integrity,sara,smack,selinux,tomoyo,apparmor" if DEFAULT_SECURITY_SMACK + default "yama,loadpin,safesetid,integrity,sara,apparmor,selinux,smack,tomoyo" if DEFAULT_SECURITY_APPARMOR + default "yama,loadpin,safesetid,integrity,sara,tomoyo" if DEFAULT_SECURITY_TOMOYO + default "yama,loadpin,safesetid,integrity,sara" if DEFAULT_SECURITY_DAC + default "yama,loadpin,safesetid,integrity,sara,selinux,smack,tomoyo,apparmor" 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 c598b90..4b0fd11 100644 --- a/security/Makefile +++ b/security/Makefile @@ -11,6 +11,7 @@ subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor subdir-$(CONFIG_SECURITY_YAMA) += yama subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid +subdir-$(CONFIG_SECURITY_SARA) += sara # always enable default capabilities obj-y += commoncap.o @@ -27,6 +28,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/ +obj-$(CONFIG_SECURITY_SARA) += sara/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists diff --git a/security/sara/Kconfig b/security/sara/Kconfig new file mode 100644 index 0000000..0456220 --- /dev/null +++ b/security/sara/Kconfig @@ -0,0 +1,40 @@ +menuconfig SECURITY_SARA + bool "S.A.R.A." + depends on SECURITY + select SECURITYFS + default n + help + This selects S.A.R.A. LSM which aims to collect heterogeneous + security measures providing a common interface to manage them. + This LSM will always be stacked with the selected primary LSM and + other stacked LSMs. + Further information can be found in + Documentation/admin-guide/LSM/SARA.rst. + + If unsure, answer N. + +config SECURITY_SARA_DEFAULT_DISABLED + bool "S.A.R.A. will be disabled at boot." + depends on SECURITY_SARA + default n + help + If you say Y here, S.A.R.A. will not be enabled at startup. You can + override this option at boot time via "sara.enabled=[1|0]" kernel + parameter or via user-space utilities. + This option is useful for distro kernels. + + If unsure, answer N. + +config SECURITY_SARA_NO_RUNTIME_ENABLE + bool "S.A.R.A. can be turn on only at boot time." + depends on SECURITY_SARA_DEFAULT_DISABLED + default y + help + By enabling this option it won't be possible to turn on S.A.R.A. + at runtime via user-space utilities. However it can still be + turned on at boot time via the "sara.enabled=1" kernel parameter. + This option is functionally equivalent to "sara.enabled=0" kernel + parameter. This option is useful for distro kernels. + + If unsure, answer Y. + diff --git a/security/sara/Makefile b/security/sara/Makefile new file mode 100644 index 0000000..8acd291 --- /dev/null +++ b/security/sara/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_SECURITY_SARA) := sara.o + +sara-y := main.o securityfs.o utils.o diff --git a/security/sara/include/sara.h b/security/sara/include/sara.h new file mode 100644 index 0000000..cd12f52 --- /dev/null +++ b/security/sara/include/sara.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#ifndef __SARA_H +#define __SARA_H + +#include +#include + +#define SARA_VERSION 0 +#define SARA_PATH_MAX PATH_MAX + +#undef pr_fmt +#define pr_fmt(fmt) "SARA: " fmt + +extern int sara_config_locked __read_mostly; +extern int sara_enabled __read_mostly; + +#endif /* __SARA_H */ diff --git a/security/sara/include/securityfs.h b/security/sara/include/securityfs.h new file mode 100644 index 0000000..92d6180 --- /dev/null +++ b/security/sara/include/securityfs.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#ifndef __SARA_SECURITYFS_H +#define __SARA_SECURITYFS_H + +#include + +#define SARA_SUBTREE_NN_LEN 24 +#define SARA_CONFIG_HASH_LEN 20 + +struct sara_secfs_node; + +int sara_secfs_init(void) __init; +int sara_secfs_subtree_register(const char *subtree_name, + const struct sara_secfs_node *nodes, + size_t size) __init; + +enum sara_secfs_node_type { + SARA_SECFS_BOOL, + SARA_SECFS_READONLY_INT, + SARA_SECFS_CONFIG_LOAD, + SARA_SECFS_CONFIG_DUMP, + SARA_SECFS_CONFIG_HASH, +}; + +struct sara_secfs_node { + const enum sara_secfs_node_type type; + void *const data; + const size_t dir_contents_len; + const char name[SARA_SUBTREE_NN_LEN]; +}; + +struct sara_secfs_fptrs { + int (*const load)(const char *, size_t); + ssize_t (*const dump)(char **); + int (*const hash)(char **); +}; + +struct sara_secfs_bool_flag { + const char notice_line[SARA_SUBTREE_NN_LEN]; + int *const flag; +}; + +#define DEFINE_SARA_SECFS_BOOL_FLAG(NAME, VAR) \ +const struct sara_secfs_bool_flag NAME = { \ + .notice_line = #VAR, \ + .flag = &(VAR), \ +} + +#endif /* __SARA_SECURITYFS_H */ diff --git a/security/sara/include/utils.h b/security/sara/include/utils.h new file mode 100644 index 0000000..ce9d5fb --- /dev/null +++ b/security/sara/include/utils.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#ifndef __SARA_UTILS_H +#define __SARA_UTILS_H + +#include +#include +#include + +char *get_absolute_path(const struct path *spath, char **buf); +char *get_current_path(char **buf); + +static inline void release_entry(struct kref *ref) +{ + /* All work is done after the return from kref_put(). */ +} + + +/* + * The following macros must be used to access S.A.R.A. configuration + * structures. + * They are thread-safe under the assumption that a configuration + * won't ever be deleted but just replaced using SARA_CONFIG_REPLACE, + * possibly using an empty configuration. + * i.e. every call to SARA_CONFIG_PUT *must* be preceded by a matching + * SARA_CONFIG_GET invocation. + */ + +#define SARA_CONFIG_GET_RCU(DEST, CONFIG) do { \ + rcu_read_lock(); \ + (DEST) = rcu_dereference(CONFIG); \ +} while (0) + +#define SARA_CONFIG_PUT_RCU(DATA) do { \ + rcu_read_unlock(); \ + (DATA) = NULL; \ +} while (0) + +#define SARA_CONFIG_GET(DEST, CONFIG) do { \ + rcu_read_lock(); \ + do { \ + (DEST) = rcu_dereference(CONFIG); \ + } while ((DEST) && !kref_get_unless_zero(&(DEST)->refcount)); \ + rcu_read_unlock(); \ +} while (0) + +#define SARA_CONFIG_PUT(DATA, FREE) do { \ + if (kref_put(&(DATA)->refcount, release_entry)) { \ + synchronize_rcu(); \ + (FREE)(DATA); \ + } \ + (DATA) = NULL; \ +} while (0) + +#define SARA_CONFIG_REPLACE(CONFIG, NEW, FREE, LOCK) do { \ + typeof(NEW) tmp; \ + spin_lock(LOCK); \ + tmp = rcu_dereference_protected(CONFIG, \ + lockdep_is_held(LOCK)); \ + rcu_assign_pointer(CONFIG, NEW); \ + if (kref_put(&tmp->refcount, release_entry)) { \ + spin_unlock(LOCK); \ + synchronize_rcu(); \ + FREE(tmp); \ + } else \ + spin_unlock(LOCK); \ +} while (0) + +#endif /* __SARA_UTILS_H */ diff --git a/security/sara/main.c b/security/sara/main.c new file mode 100644 index 0000000..52e6d18 --- /dev/null +++ b/security/sara/main.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include + +#include "include/sara.h" +#include "include/securityfs.h" + +static const int sara_version = SARA_VERSION; + +#ifdef CONFIG_SECURITY_SARA_NO_RUNTIME_ENABLE +int sara_config_locked __read_mostly = true; +#else +int sara_config_locked __read_mostly; +#endif + +#ifdef CONFIG_SECURITY_SARA_DEFAULT_DISABLED +int sara_enabled __read_mostly; +#else +int sara_enabled __read_mostly = true; +#endif + +static DEFINE_SARA_SECFS_BOOL_FLAG(sara_enabled_data, sara_enabled); +static DEFINE_SARA_SECFS_BOOL_FLAG(sara_config_locked_data, sara_config_locked); + +static int param_set_senabled(const char *val, const struct kernel_param *kp) +{ + if (!val) + return 0; + if (strtobool(val, kp->arg)) + return -EINVAL; + /* config must by locked when S.A.R.A. is disabled at boot + * and unlocked when it's enabled + */ + sara_config_locked = !(*(int *) kp->arg); + return 0; +} + +static struct kernel_param_ops param_ops_senabled = { + .set = param_set_senabled, +}; + +#define param_check_senabled(name, p) __param_check(name, p, int) + +module_param_named(enabled, sara_enabled, senabled, 0000); +MODULE_PARM_DESC(enabled, "Disable or enable S.A.R.A. at boot time. If disabled this way S.A.R.A. can't be enabled again."); + +static const struct sara_secfs_node main_fs[] __initconst = { + { + .name = "enabled", + .type = SARA_SECFS_BOOL, + .data = (void *) &sara_enabled_data, + }, + { + .name = "locked", + .type = SARA_SECFS_BOOL, + .data = (void *) &sara_config_locked_data, + }, + { + .name = "version", + .type = SARA_SECFS_READONLY_INT, + .data = (int *) &sara_version, + }, +}; + +static int __init sara_init(void) +{ + if (!sara_enabled && sara_config_locked) { + pr_notice("permanently disabled.\n"); + return 0; + } + + pr_debug("initializing...\n"); + + if (sara_secfs_subtree_register("main", + main_fs, + ARRAY_SIZE(main_fs))) { + pr_crit("impossible to register main fs.\n"); + goto error; + } + + pr_debug("initialized.\n"); + + if (sara_enabled) + pr_info("enabled\n"); + else + pr_notice("disabled\n"); + return 0; + +error: + sara_enabled = false; + sara_config_locked = true; + pr_crit("permanently disabled.\n"); + return 1; +} + +DEFINE_LSM(sara) = { + .name = "sara", + .enabled = &sara_enabled, + .init = sara_init, +}; diff --git a/security/sara/securityfs.c b/security/sara/securityfs.c new file mode 100644 index 0000000..f6b152c --- /dev/null +++ b/security/sara/securityfs.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "include/sara.h" +#include "include/utils.h" +#include "include/securityfs.h" + +#define __SARA_STR_HELPER(x) #x +#define SARA_STR(x) __SARA_STR_HELPER(x) + +static struct dentry *fs_root; + +static inline bool check_config_write_access(void) +{ + if (unlikely(sara_config_locked)) { + pr_warn("config write access blocked.\n"); + return false; + } + return true; +} + +static bool check_config_access(const struct file *file) +{ + if (!capable(CAP_MAC_ADMIN)) + return false; + if (file->f_flags & O_WRONLY || file->f_flags & O_RDWR) + if (unlikely(!check_config_write_access())) + return false; + return true; +} + +static int file_flag_show(struct seq_file *seq, void *v) +{ + int *flag = ((struct sara_secfs_bool_flag *)seq->private)->flag; + + seq_printf(seq, "%d\n", *flag); + return 0; +} + +static ssize_t file_flag_write(struct file *file, + const char __user *ubuf, + size_t buf_size, + loff_t *offset) +{ + struct sara_secfs_bool_flag *bool_flag = + ((struct seq_file *) file->private_data)->private; + char kbuf[2] = {'A', '\n'}; + int nf; + + if (unlikely(*offset != 0)) + return -ESPIPE; + + if (unlikely(buf_size != 1 && buf_size != 2)) + return -EPERM; + + if (unlikely(copy_from_user(kbuf, ubuf, buf_size))) + return -EFAULT; + + if (unlikely(kbuf[1] != '\n')) + return -EPERM; + + switch (kbuf[0]) { + case '0': + nf = false; + break; + case '1': + nf = true; + break; + default: + return -EPERM; + } + + *bool_flag->flag = nf; + + if (strlen(bool_flag->notice_line) > 0) + pr_notice("flag \"%s\" set to %d\n", + bool_flag->notice_line, + nf); + + return buf_size; +} + +static int file_flag_open(struct inode *inode, struct file *file) +{ + if (unlikely(!check_config_access(file))) + return -EACCES; + return single_open(file, file_flag_show, inode->i_private); +} + +static const struct file_operations file_flag = { + .owner = THIS_MODULE, + .open = file_flag_open, + .write = file_flag_write, + .read = seq_read, + .release = single_release, +}; + +static int file_readonly_int_show(struct seq_file *seq, void *v) +{ + int *flag = seq->private; + + seq_printf(seq, "%d\n", *flag); + return 0; +} + +static int file_readonly_int_open(struct inode *inode, struct file *file) +{ + if (unlikely(!check_config_access(file))) + return -EACCES; + return single_open(file, file_readonly_int_show, inode->i_private); +} + +static const struct file_operations file_readonly_int = { + .owner = THIS_MODULE, + .open = file_readonly_int_open, + .read = seq_read, + .release = single_release, +}; + +static ssize_t file_config_loader_write(struct file *file, + const char __user *ubuf, + size_t buf_size, + loff_t *offset) +{ + const struct sara_secfs_fptrs *fptrs = file->private_data; + char *kbuf = NULL; + ssize_t ret; + + ret = -ESPIPE; + if (unlikely(*offset != 0)) + goto out; + + ret = -ENOMEM; + kbuf = kvmalloc(buf_size, GFP_KERNEL_ACCOUNT); + if (unlikely(kbuf == NULL)) + goto out; + + ret = -EFAULT; + if (unlikely(copy_from_user(kbuf, ubuf, buf_size))) + goto out; + + ret = fptrs->load(kbuf, buf_size); + + if (unlikely(ret)) + goto out; + + ret = buf_size; + +out: + kvfree(kbuf); + return ret; +} + +static int file_config_loader_open(struct inode *inode, struct file *file) +{ + if (unlikely(!check_config_access(file))) + return -EACCES; + file->private_data = inode->i_private; + return 0; +} + +static const struct file_operations file_config_loader = { + .owner = THIS_MODULE, + .open = file_config_loader_open, + .write = file_config_loader_write, +}; + +static int file_config_show(struct seq_file *seq, void *v) +{ + const struct sara_secfs_fptrs *fptrs = seq->private; + char *buf = NULL; + ssize_t ret; + + ret = fptrs->dump(&buf); + if (unlikely(ret <= 0)) + goto out; + seq_write(seq, buf, ret); + kvfree(buf); + ret = 0; +out: + return ret; +} + +static int file_dumper_open(struct inode *inode, struct file *file) +{ + if (unlikely(!check_config_access(file))) + return -EACCES; + return single_open(file, file_config_show, inode->i_private); +} + +static const struct file_operations file_config_dumper = { + .owner = THIS_MODULE, + .open = file_dumper_open, + .read = seq_read, + .release = single_release, +}; + +static int file_hash_show(struct seq_file *seq, void *v) +{ + const struct sara_secfs_fptrs *fptrs = seq->private; + char *buf = NULL; + int ret; + + ret = fptrs->hash(&buf); + if (unlikely(ret)) + goto out; + seq_printf(seq, "%" SARA_STR(SARA_CONFIG_HASH_LEN) "phN\n", buf); + kvfree(buf); + ret = 0; +out: + return ret; +} + +static int file_hash_open(struct inode *inode, struct file *file) +{ + if (unlikely(!check_config_access(file))) + return -EACCES; + return single_open(file, file_hash_show, inode->i_private); +} + +static const struct file_operations file_hash = { + .owner = THIS_MODULE, + .open = file_hash_open, + .read = seq_read, + .release = single_release, +}; + +static int mk_dir(struct dentry *parent, + const char *dir_name, + struct dentry **dir_out) +{ + int ret = 0; + + *dir_out = securityfs_create_dir(dir_name, parent); + if (IS_ERR(*dir_out)) { + ret = -PTR_ERR(*dir_out); + *dir_out = NULL; + } + return ret; +} + +static int mk_bool_flag(struct dentry *parent, + const char *file_name, + struct dentry **dir_out, + void *flag) +{ + int ret = 0; + + *dir_out = securityfs_create_file(file_name, + 0600, + parent, + flag, + &file_flag); + if (IS_ERR(*dir_out)) { + ret = -PTR_ERR(*dir_out); + *dir_out = NULL; + } + return ret; +} + +static int mk_readonly_int(struct dentry *parent, + const char *file_name, + struct dentry **dir_out, + void *readonly_int) +{ + int ret = 0; + + *dir_out = securityfs_create_file(file_name, + 0400, + parent, + readonly_int, + &file_readonly_int); + if (IS_ERR(*dir_out)) { + ret = -PTR_ERR(*dir_out); + *dir_out = NULL; + } + return ret; +} + +static int mk_config_loader(struct dentry *parent, + const char *file_name, + struct dentry **dir_out, + void *fptrs) +{ + int ret = 0; + + *dir_out = securityfs_create_file(file_name, + 0200, + parent, + fptrs, + &file_config_loader); + if (IS_ERR(*dir_out)) { + ret = -PTR_ERR(*dir_out); + *dir_out = NULL; + } + return ret; +} + +static int mk_config_dumper(struct dentry *parent, + const char *file_name, + struct dentry **dir_out, + void *fptrs) +{ + int ret = 0; + + *dir_out = securityfs_create_file(file_name, + 0400, + parent, + fptrs, + &file_config_dumper); + if (IS_ERR(*dir_out)) { + ret = -PTR_ERR(*dir_out); + *dir_out = NULL; + } + return ret; +} + +static int mk_config_hash(struct dentry *parent, + const char *file_name, + struct dentry **dir_out, + void *fptrs) +{ + int ret = 0; + + *dir_out = securityfs_create_file(file_name, + 0400, + parent, + fptrs, + &file_hash); + if (IS_ERR(*dir_out)) { + ret = -PTR_ERR(*dir_out); + *dir_out = NULL; + } + return ret; +} + +struct sara_secfs_subtree { + char name[SARA_SUBTREE_NN_LEN]; + size_t size; + struct dentry **nodes; + const struct sara_secfs_node *nodes_description; + struct list_head subtree_list; +}; + +static LIST_HEAD(subtree_list); + +int __init sara_secfs_subtree_register(const char *subtree_name, + const struct sara_secfs_node *nodes, + size_t size) +{ + int ret; + struct sara_secfs_subtree *subtree = NULL; + + ret = -EINVAL; + if (unlikely(size < 1)) + goto error; + ret = -ENOMEM; + subtree = kmalloc(sizeof(*subtree), GFP_KERNEL); + if (unlikely(subtree == NULL)) + goto error; + strncpy(subtree->name, + subtree_name, + sizeof(subtree->name)); + subtree->name[sizeof(subtree->name)-1] = '\0'; + subtree->size = size+1; + subtree->nodes = kcalloc(subtree->size, + sizeof(*subtree->nodes), + GFP_KERNEL); + if (unlikely(subtree->nodes == NULL)) + goto error; + subtree->nodes_description = nodes; + INIT_LIST_HEAD(&subtree->subtree_list); + list_add(&subtree->subtree_list, &subtree_list); + return 0; + +error: + kfree(subtree); + pr_warn("SECFS: Impossible to register '%s' (%d).\n", + subtree_name, ret); + return ret; +} + +static inline int __init create_node(enum sara_secfs_node_type type, + struct dentry *parent, + const char *name, + struct dentry **output, + void *data) +{ + switch (type) { + case SARA_SECFS_BOOL: + return mk_bool_flag(parent, name, output, data); + case SARA_SECFS_READONLY_INT: + return mk_readonly_int(parent, name, output, data); + case SARA_SECFS_CONFIG_LOAD: + return mk_config_loader(parent, name, output, data); + case SARA_SECFS_CONFIG_DUMP: + return mk_config_dumper(parent, name, output, data); + case SARA_SECFS_CONFIG_HASH: + return mk_config_hash(parent, name, output, data); + default: + return -EINVAL; + } +} + +static void subtree_unplug(struct sara_secfs_subtree *subtree) +{ + int i; + + for (i = 0; i < subtree->size; ++i) { + if (subtree->nodes[i] != NULL) { + securityfs_remove(subtree->nodes[i]); + subtree->nodes[i] = NULL; + } + } +} + +static int __init subtree_plug(struct sara_secfs_subtree *subtree) +{ + int ret; + int i; + const struct sara_secfs_node *nodes = subtree->nodes_description; + + ret = -EINVAL; + if (unlikely(fs_root == NULL)) + goto out; + ret = mk_dir(fs_root, + subtree->name, + &subtree->nodes[subtree->size-1]); + if (unlikely(ret)) + goto out_unplug; + for (i = 0; i < subtree->size-1; ++i) { + ret = create_node(nodes[i].type, + subtree->nodes[subtree->size-1], + nodes[i].name, + &subtree->nodes[i], + nodes[i].data); + if (unlikely(ret)) + goto out_unplug; + } + return 0; + +out_unplug: + subtree_unplug(subtree); +out: + pr_warn("SECFS: Impossible to plug '%s' (%d).\n", subtree->name, ret); + return ret; +} + +static int __init subtree_plug_all(void) +{ + int ret; + struct list_head *position; + struct sara_secfs_subtree *subtree; + + ret = -EINVAL; + if (unlikely(fs_root == NULL)) + goto out; + ret = 0; + list_for_each(position, &subtree_list) { + subtree = list_entry(position, + struct sara_secfs_subtree, + subtree_list); + if (subtree->nodes[0] == NULL) { + ret = subtree_plug(subtree); + if (unlikely(ret)) + goto out; + } + } +out: + if (unlikely(ret)) + pr_warn("SECFS: Impossible to plug subtrees (%d).\n", ret); + return ret; +} + +static void __init subtree_free_all(bool unplug) +{ + struct list_head *position; + struct list_head *next; + struct sara_secfs_subtree *subtree; + + list_for_each_safe(position, next, &subtree_list) { + subtree = list_entry(position, + struct sara_secfs_subtree, + subtree_list); + list_del(position); + if (unplug) + subtree_unplug(subtree); + kfree(subtree->nodes); + kfree(subtree); + } +} + +static int mk_root(void) +{ + int ret = -1; + + if (fs_root == NULL) + ret = mk_dir(NULL, "sara", &fs_root); + if (unlikely(ret || fs_root == NULL)) + pr_warn("SECFS: Impossible to create root (%d).\n", ret); + return ret; +} + +static inline void rm_root(void) +{ + if (likely(fs_root != NULL)) { + securityfs_remove(fs_root); + fs_root = NULL; + } +} + +static inline void __init sara_secfs_destroy(void) +{ + subtree_free_all(true); + rm_root(); +} + +int __init sara_secfs_init(void) +{ + int ret; + + if (!sara_enabled && sara_config_locked) + return 0; + + fs_root = NULL; + + ret = mk_root(); + if (unlikely(ret)) + goto error; + + ret = subtree_plug_all(); + if (unlikely(ret)) + goto error; + + subtree_free_all(false); + + pr_debug("securityfs initilaized.\n"); + return 0; + +error: + sara_secfs_destroy(); + pr_crit("impossible to build securityfs.\n"); + return ret; +} + +fs_initcall(sara_secfs_init); diff --git a/security/sara/utils.c b/security/sara/utils.c new file mode 100644 index 0000000..d63febb --- /dev/null +++ b/security/sara/utils.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "include/sara.h" +#include "include/utils.h" + +/** + * get_absolute_path - return the absolute path for a struct path + * @spath: the struct path to report + * @buf: double pointer where the newly allocated buffer will be placed + * + * Returns a pointer into @buf or an error code. + * + * The caller MUST kvfree @buf when finished using it. + */ +char *get_absolute_path(const struct path *spath, char **buf) +{ + size_t size = 128; + char *work_buf = NULL; + char *path = NULL; + + do { + kvfree(work_buf); + work_buf = NULL; + if (size > SARA_PATH_MAX) { + path = ERR_PTR(-ENAMETOOLONG); + goto error; + } + work_buf = kvmalloc(size, GFP_KERNEL); + if (unlikely(work_buf == NULL)) { + path = ERR_PTR(-ENOMEM); + goto error; + } + path = d_absolute_path(spath, work_buf, size); + size *= 2; + } while (PTR_ERR(path) == -ENAMETOOLONG); + if (!IS_ERR(path)) + goto out; + +error: + kvfree(work_buf); + work_buf = NULL; +out: + *buf = work_buf; + return path; +} + +/** + * get_current_path - return the absolute path for the exe_file + * in the current task_struct, falling back + * to the contents of the comm field. + * @buf: double pointer where the newly allocated buffer will be placed + * + * Returns a pointer into @buf or an error code. + * + * The caller MUST kvfree @buf when finished using it. + */ +char *get_current_path(char **buf) +{ + struct file *exe_file; + char *path = NULL; + + exe_file = get_task_exe_file(current); + if (exe_file) { + path = get_absolute_path(&exe_file->f_path, buf); + fput(exe_file); + } + if (IS_ERR_OR_NULL(path)) { + *buf = kzalloc(TASK_COMM_LEN, GFP_KERNEL); + __get_task_comm(*buf, TASK_COMM_LEN, current); + path = *buf; + } + return path; +} From patchwork Sat Jul 6 10:54:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033585 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B0BA013BD for ; Sat, 6 Jul 2019 10:55:19 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9F1812881B for ; Sat, 6 Jul 2019 10:55:19 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9335F28A26; Sat, 6 Jul 2019 10:55:19 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,GAPPY_SUBJECT,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D8D912881B for ; Sat, 6 Jul 2019 10:55:18 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id BDBCD6B0007; Sat, 6 Jul 2019 06:55:17 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id B65618E0003; Sat, 6 Jul 2019 06:55:17 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A54948E0001; Sat, 6 Jul 2019 06:55:17 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by kanga.kvack.org (Postfix) with ESMTP id 5808A6B0007 for ; Sat, 6 Jul 2019 06:55:17 -0400 (EDT) Received: by mail-wr1-f70.google.com with SMTP id b6so5004564wrp.21 for ; Sat, 06 Jul 2019 03:55:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=tntZg8r5S9LwiMO7vss45dOAl1fEVW4KEshHq7hSndk=; b=p74Ok4NozH7zinWgw418Re9wm2mFROPcCtAsjMZdRrP6d4qhhC4ld5gv8XdQStU1NU umLcUuCS1lux9ZRWosvGPXPnwC1/ieiUvDvjl1XisbPh9BjEeYj6xu6yk/DCncYHa0Q9 wnJnXFykpK7VnmqWYFBuZi6GD+63LAvxebl1tw1DQQQ9uncjmwE5fW96zMoq6uUA+zik /8GMsQCQjcxULKnEXAV2811FqbxWRD9Eu7sOtc57DxEI63LXH46L9ixb1XGwN/A5+Zam PDbCaAU3JBkkXCfYbDjbAOd0rr7r+dIdftVMATxqTYqjsC+Nhe/hsKwRwB5nItuFQUW7 pp0g== X-Gm-Message-State: APjAAAWubVJUEe8lWgGWspv45cW7ryC4UC/dP1ILXVp8R/StDjcg85X4 1eTcn70xKb4+3wbKFf+mZ2ORxOUsDCdIFIlPI6DnxDbY6WdixeKE39egnVdm5YtZZejUNOxzuvN 2eAnJ1f11xR/o5Dt3zaGeCZSFJscPzptECDkmAuCnrirdveS8pkS94CNqKtgh5+z+iQ== X-Received: by 2002:adf:c508:: with SMTP id q8mr8678107wrf.148.1562410516882; Sat, 06 Jul 2019 03:55:16 -0700 (PDT) X-Received: by 2002:adf:c508:: with SMTP id q8mr8677968wrf.148.1562410515320; Sat, 06 Jul 2019 03:55:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410515; cv=none; d=google.com; s=arc-20160816; b=J4r4zfJqgIdQiuMu8cA8DhmEPGFO5VNzWZvG/9j0YUusi4Krw5/bT7O9gU9CoZpGsp u/wwwX0b7QehVcmSIMceQaYTieSTcmmBKZxNGSI7OPygP2BOvR6OlQ/vXe4LmuPLLrSL oiZj+xxJ7HYe0OE+UWtMFGNIpKWxe+aUZy1YayIIva+jI33/0hJQKtlmTVRrwUoLzH4b vG+iJSzb2w7URlOI94s59Oc97Z+jCTD7q0Ag5cZduu5UqKZMhsANe8a0YSecU2m0KXLd NakjHhlyYiupx031AOeqHbMWDIqw4CjSEsU5cgFV4hBXep68z4gArXimMwyLj4ndtE6a edVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=tntZg8r5S9LwiMO7vss45dOAl1fEVW4KEshHq7hSndk=; b=pYC5F2sT14ELFkBsYwfSi2jWEIV00X3wcrPzS0kaqNcA1XJJucV/DZFYR0Aa3cQ5Tl ZzZNk8cN0ZWP7HZ1KNLLAAmDjXjRhdl7Zv9vNAGqeG3laLR/niZTlsS1hNzW5i2nS9+M V0BkH7Ubi1oSJVziyOU8z7UKp4/lYOEWWQ1Hi77hdMC6kL0ywDRFObYWnfo7eZbP+EBu 9xHysbzu9zOrhaxGROXou1z1rGJqpmqtWkoeg+pcRkQ2vdZAviC/sQkLwXQHhv7yAq9l /0zw/DBSjGs9VslfxtdCkHqddaYsgAzSfeiIgSPrRrTdo1a/OhHpXaG7q0wF9Lr3oqzK O5AA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=kc2cJKhD; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id v65sor6340925wme.16.2019.07.06.03.55.15 for (Google Transport Security); Sat, 06 Jul 2019 03:55:15 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=kc2cJKhD; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tntZg8r5S9LwiMO7vss45dOAl1fEVW4KEshHq7hSndk=; b=kc2cJKhDmxsorvbYBJN4L4LP1TLlMTnFPLFX6zgkZebJ/WsFIMzWWYWhtSgVtP7zMQ 0cOB3K0BaSp0V5QtNPW6SGBa+vrt3q/HL19vYWaeS7qrfH+dWKn9nfeK/a+K8xeUEotp 5ZmpQDndExIKqNYdSvxCEi9NPZMxIGZK9+ornVkxCqrBSuxArZeonMC6E7vUvtjhX4VT 5szWyZvmeouxknBYxB9Wbjm9LbY7t21Y+4zZ9LjC/eMDRTlMMT+GuGm2SSyALI9h5Hng oeLX0GzYFtaj78gVuuV1vufxWfJg/xwaAdrvfKBhwc/EYZdO2fu2pXy4SOCaITR4HIIa gRdw== X-Google-Smtp-Source: APXvYqyT5FvHevvfORCP5Opw4y7yO1x8K1YKmTYR/PUKpHFg48nVRxzDqlQiuBD7tLbShBXcjqdbVA== X-Received: by 2002:a1c:b706:: with SMTP id h6mr7598997wmf.119.1562410514962; Sat, 06 Jul 2019 03:55:14 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:14 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 03/12] S.A.R.A.: cred blob management Date: Sat, 6 Jul 2019 12:54:44 +0200 Message-Id: <1562410493-8661-4-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Creation of the S.A.R.A. cred blob management "API". In order to allow S.A.R.A. to be stackable with other LSMs, it doesn't use the "security" field of struct cred, instead it uses an ad hoc field named security_sara. This solution is probably not acceptable for upstream, so this part will be modified as soon as the LSM stackable cred blob management will be available. Signed-off-by: Salvatore Mesoraca --- security/sara/Makefile | 2 +- security/sara/include/sara_data.h | 84 +++++++++++++++++++++++++++++++++++++++ security/sara/main.c | 7 ++++ security/sara/sara_data.c | 69 ++++++++++++++++++++++++++++++++ 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 security/sara/include/sara_data.h create mode 100644 security/sara/sara_data.c diff --git a/security/sara/Makefile b/security/sara/Makefile index 8acd291..14bf7a8 100644 --- a/security/sara/Makefile +++ b/security/sara/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_SECURITY_SARA) := sara.o -sara-y := main.o securityfs.o utils.o +sara-y := main.o securityfs.o utils.o sara_data.o diff --git a/security/sara/include/sara_data.h b/security/sara/include/sara_data.h new file mode 100644 index 0000000..9216c47 --- /dev/null +++ b/security/sara/include/sara_data.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#ifndef __SARA_DATA_H +#define __SARA_DATA_H + +#include +#include +#include +#include + +int sara_data_init(void) __init; + +extern struct lsm_blob_sizes sara_blob_sizes __lsm_ro_after_init; + +#ifdef CONFIG_SECURITY_SARA_WXPROT + +struct sara_data { + unsigned long relro_page; + struct file *relro_file; + u16 wxp_flags; + u16 execve_flags; + bool relro_page_found; + bool mmap_blocked; +}; + +struct sara_shm_data { + bool no_exec; + bool no_write; + spinlock_t lock; +}; + + +static inline struct sara_data *get_sara_data(const struct cred *cred) +{ + return cred->security + sara_blob_sizes.lbs_cred; +} + +#define get_current_sara_data() get_sara_data(current_cred()) + +#define get_sara_wxp_flags(X) (get_sara_data((X))->wxp_flags) +#define get_current_sara_wxp_flags() get_sara_wxp_flags(current_cred()) + +#define get_sara_execve_flags(X) (get_sara_data((X))->execve_flags) +#define get_current_sara_execve_flags() get_sara_execve_flags(current_cred()) + +#define get_sara_relro_page(X) (get_sara_data((X))->relro_page) +#define get_current_sara_relro_page() get_sara_relro_page(current_cred()) + +#define get_sara_relro_file(X) (get_sara_data((X))->relro_file) +#define get_current_sara_relro_file() get_sara_relro_file(current_cred()) + +#define get_sara_relro_page_found(X) (get_sara_data((X))->relro_page_found) +#define get_current_sara_relro_page_found() \ + get_sara_relro_page_found(current_cred()) + +#define get_sara_mmap_blocked(X) (get_sara_data((X))->mmap_blocked) +#define get_current_sara_mmap_blocked() get_sara_mmap_blocked(current_cred()) + + +static inline struct sara_shm_data *get_sara_shm_data( + const struct kern_ipc_perm *ipc) +{ + return ipc->security + sara_blob_sizes.lbs_ipc; +} + +#define get_sara_shm_no_exec(X) (get_sara_shm_data((X))->no_exec) +#define get_sara_shm_no_write(X) (get_sara_shm_data((X))->no_write) +#define lock_sara_shm(X) (spin_lock(&get_sara_shm_data((X))->lock)) +#define unlock_sara_shm(X) (spin_unlock(&get_sara_shm_data((X))->lock)) + +#endif + +#endif /* __SARA_H */ diff --git a/security/sara/main.c b/security/sara/main.c index 52e6d18..dc5dda4 100644 --- a/security/sara/main.c +++ b/security/sara/main.c @@ -18,6 +18,7 @@ #include #include "include/sara.h" +#include "include/sara_data.h" #include "include/securityfs.h" static const int sara_version = SARA_VERSION; @@ -93,6 +94,11 @@ static int __init sara_init(void) goto error; } + if (sara_data_init()) { + pr_crit("impossible to initialize creds.\n"); + goto error; + } + pr_debug("initialized.\n"); if (sara_enabled) @@ -112,4 +118,5 @@ static int __init sara_init(void) .name = "sara", .enabled = &sara_enabled, .init = sara_init, + .blobs = &sara_blob_sizes, }; diff --git a/security/sara/sara_data.c b/security/sara/sara_data.c new file mode 100644 index 0000000..9afca37 --- /dev/null +++ b/security/sara/sara_data.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include "include/sara_data.h" + +#ifdef CONFIG_SECURITY_SARA_WXPROT +#include +#include +#include +#include + +static int sara_cred_prepare(struct cred *new, const struct cred *old, + gfp_t gfp) +{ + *get_sara_data(new) = *get_sara_data(old); + return 0; +} + +static void sara_cred_transfer(struct cred *new, const struct cred *old) +{ + *get_sara_data(new) = *get_sara_data(old); +} + +static int sara_shm_alloc_security(struct kern_ipc_perm *shp) +{ + struct sara_shm_data *d; + + d = get_sara_shm_data(shp); + spin_lock_init(&d->lock); + return 0; +} + +static struct security_hook_list data_hooks[] __lsm_ro_after_init = { + LSM_HOOK_INIT(cred_prepare, sara_cred_prepare), + LSM_HOOK_INIT(cred_transfer, sara_cred_transfer), + LSM_HOOK_INIT(shm_alloc_security, sara_shm_alloc_security), +}; + +struct lsm_blob_sizes sara_blob_sizes __lsm_ro_after_init = { + .lbs_cred = sizeof(struct sara_data), + .lbs_ipc = sizeof(struct sara_shm_data), +}; + +int __init sara_data_init(void) +{ + security_add_hooks(data_hooks, ARRAY_SIZE(data_hooks), "sara"); + return 0; +} + +#else /* CONFIG_SECURITY_SARA_WXPROT */ + +struct lsm_blob_sizes sara_blob_sizes __lsm_ro_after_init = { }; + +int __init sara_data_init(void) +{ + return 0; +} + +#endif From patchwork Sat Jul 6 10:54:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033593 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 42A2113BD for ; Sat, 6 Jul 2019 10:55:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 30DB92881B for ; Sat, 6 Jul 2019 10:55:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 24E8328994; Sat, 6 Jul 2019 10:55:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,GAPPY_SUBJECT,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CB7182881B for ; Sat, 6 Jul 2019 10:55:24 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id BB42A6B000C; Sat, 6 Jul 2019 06:55:19 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id B89DC6B000A; Sat, 6 Jul 2019 06:55:19 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A05598E0001; Sat, 6 Jul 2019 06:55:19 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by kanga.kvack.org (Postfix) with ESMTP id 41D966B000A for ; Sat, 6 Jul 2019 06:55:19 -0400 (EDT) Received: by mail-wr1-f70.google.com with SMTP id q2so4997551wrr.18 for ; Sat, 06 Jul 2019 03:55:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=HMLlUTvH7NymWaOjPDDSuVqGYq2w/v7gPHlts+YCCcY=; b=VO3LyC08BQlAPD0bTLTHlQHFUDYsrYtidTtdEGooZJBbtMdFRL71JX0J/ALGEp7TRp BtcmP8cKhOUeb6eYOKKqwVvshxs5WQdJEi4N7vYWsBgzA6VN1d1zelsobjBTzRGcRaBn q1mCuP4ZkU1yY1pA47hZLu9IwoJHr08uoJepcYqkspIcdoKWfq1UCyb9hlmeBIzdcT69 E3fUqs7/O0faltv2W2UoLrrJIVKI+PszdrqQFSp0mRv80fv5x7GF41239qae/IQTWIWX TrivTjx3y7YT4SPHAN6tWKqBncJMkF0u0e0kLokCiUa9yozm3HYJfSrjKryEXVKv95M1 RqpA== X-Gm-Message-State: APjAAAVNvQ3tyMxFIFu/aBwi02PNWAfz7qIUoT5Fy0WEal/PsUjegbqN Gxubfu3htXa3cezqhnee7LB696W0K7e6gLAk2+uv1JEtllRF7pNiMKirl5mrUdKD4KNhLy7bcDT mPR2/LaUAz6S0nsaj3wXll1Of4LtIONL2+yb3VGm72cST4vmMr4Mn1BHJKMcy5Ypehg== X-Received: by 2002:adf:ce82:: with SMTP id r2mr8397148wrn.223.1562410518785; Sat, 06 Jul 2019 03:55:18 -0700 (PDT) X-Received: by 2002:adf:ce82:: with SMTP id r2mr8396957wrn.223.1562410516484; Sat, 06 Jul 2019 03:55:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410516; cv=none; d=google.com; s=arc-20160816; b=kSqrRuNHd+YZ9EBKJHzjbDLPx6i8IjUTKkoRlseaS+arpn9t3Ig1d/KOeMYDaIqXYw SLSYQvhAWkyXRjAzlJFRxWrwOCq/QlF5kDZkvOyGVx3eHWZeFuVvAjwIdd2s4/IzWxkU 8P0YpS89AOMy1oR47Q6aessExf/7ffJTvY/46BRAGMNWsUR12BAQeuONMvG4kCdOaDEp Cr874W/p5MAflsL9h97rQfnZ7GWiE2hrDo1rageJ6e4yva9YwHcEsEPe8if1kr+e90fH 3s/cKC1cozJOoTgJGRkyJKUsoM5XLPy8R5J/y8dXDpPh9oWFU0RHMzdMhEPMvV7ehiD7 +thg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=HMLlUTvH7NymWaOjPDDSuVqGYq2w/v7gPHlts+YCCcY=; b=dZCJcpk/2BqPcK/RlBXSiBO+fapwmZAfrAiU3UeFlZl1XLu6XJEXzYHsP6Q5HnzY1O v5TtDMr76aVch76dg+hT721Csd3iPKH/v38gOGV7rf2FnGzHSxlY+9FAwSnbMZPHxwRT pSb6Oj34JhRIkwTWGeWH7JwwsSrSPfcWvfasPipMgQbwbceGGnDzjiq2Ykp54HtN7vSJ ragUY4T+VCCHFH0fbV8YJuIjRC4BTxhDysr7tyhjYaJacNC2ggQIrym4tL84aF22bAsz PjGUQbuSDH8oah9YJPlK2keoIBxhFXAh7X0oLxSekaJfiQ6D38sxmy5XEYLtm9iE7iRp UEKQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=K5QOWWJF; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id k1sor8525710wrp.9.2019.07.06.03.55.16 for (Google Transport Security); Sat, 06 Jul 2019 03:55:16 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=K5QOWWJF; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=HMLlUTvH7NymWaOjPDDSuVqGYq2w/v7gPHlts+YCCcY=; b=K5QOWWJF4uULt5fhx/WTlCd03sw83j2/BUkVXgohygderzW3Yt/f6QRhLm2eLDTQR3 xl+1XbsuQqiJAk4SXGU6K0j5eIrmywleN3fQ6cHF5HfkUqWwu1jZhobuDMpeV45Ffk6A vaZ1MOkxmFNd5+GEc+kizOsk+IvmkjVSn1xU+C4usl+oMLtBR1O1BuMEEPSsXl9sX6Rk FhwQMcRdiGIs38g45n1NmlKmC69JLrl7SoJBdFoN99AUiviKYx27dWS0XlOoqXpmSULf TLxKu1OgktRPTQAgODy06VNXmQ9MyDej9YHpgbswqpGwsZAATTgyXBskdkA4DXCQJ1sZ d8JQ== X-Google-Smtp-Source: APXvYqxjW7TL1355+CnHJ4vlClfGDq4A6u03xqUecwa9PCLIfnLUO69I+8Q4hEKf748yiZXv3SX3UA== X-Received: by 2002:a5d:6284:: with SMTP id k4mr8982680wru.179.1562410515966; Sat, 06 Jul 2019 03:55:15 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.15 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:15 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 04/12] S.A.R.A.: generic DFA for string matching Date: Sat, 6 Jul 2019 12:54:45 +0200 Message-Id: <1562410493-8661-5-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Creation of a generic Discrete Finite Automata implementation for string matching. The transition tables have to be produced in user-space. This allows us to possibly support advanced string matching patterns like regular expressions, but they need to be supported by user-space tools. Signed-off-by: Salvatore Mesoraca --- security/sara/Kconfig | 22 +++ security/sara/Makefile | 3 +- security/sara/dfa.c | 335 +++++++++++++++++++++++++++++++++++++++ security/sara/dfa_test.c | 135 ++++++++++++++++ security/sara/include/dfa.h | 52 ++++++ security/sara/include/dfa_test.h | 29 ++++ security/sara/main.c | 6 + 7 files changed, 581 insertions(+), 1 deletion(-) create mode 100644 security/sara/dfa.c create mode 100644 security/sara/dfa_test.c create mode 100644 security/sara/include/dfa.h create mode 100644 security/sara/include/dfa_test.h diff --git a/security/sara/Kconfig b/security/sara/Kconfig index 0456220..b98cf27 100644 --- a/security/sara/Kconfig +++ b/security/sara/Kconfig @@ -13,6 +13,28 @@ menuconfig SECURITY_SARA If unsure, answer N. +config SECURITY_SARA_DFA_32BIT + bool "Use 32 bits instead of 16 bits for DFA states' id" + depends on SECURITY_SARA + default n + help + If you say Y here S.A.R.A. will use more memory, but you will be + able to configure more rules. + See Documentation/admin-guide/LSM/SARA.rst. for further information. + + If unsure, answer N. + +config SECURITY_SARA_DFA_TEST + bool "Enable test interface for the internal DFA engine" + depends on SECURITY_SARA + default n + help + If you say Y here S.A.R.A. will enable a user-space interface + that can be used to test the DFA engine (e.g. via `saractl test`). + See Documentation/admin-guide/LSM/SARA.rst. for further information. + + If unsure, answer N. + config SECURITY_SARA_DEFAULT_DISABLED bool "S.A.R.A. will be disabled at boot." depends on SECURITY_SARA diff --git a/security/sara/Makefile b/security/sara/Makefile index 14bf7a8..ffa1be1 100644 --- a/security/sara/Makefile +++ b/security/sara/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_SECURITY_SARA) := sara.o -sara-y := main.o securityfs.o utils.o sara_data.o +sara-y := main.o securityfs.o utils.o sara_data.o dfa.o +sara-$(CONFIG_SECURITY_SARA_DFA_TEST) += dfa_test.o diff --git a/security/sara/dfa.c b/security/sara/dfa.c new file mode 100644 index 0000000..e39b27e --- /dev/null +++ b/security/sara/dfa.c @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include + +#include "include/sara.h" +#include "include/dfa.h" +#include "include/securityfs.h" + +#define DFA_MAGIC_SIZE 8 +#define DFA_MAGIC "SARADFAT" + +#define DFA_INPUTS 255 + +#ifndef CONFIG_SECURITY_SARA_DFA_32BIT +#define pr_err_dfa_size() \ + pr_err_ratelimited("DFA: too many states. Recompile kernel with CONFIG_SARA_DFA_32BIT.\n") +#else +#define pr_err_dfa_size() pr_err_ratelimited("DFA: too many states.\n") +#endif + +void sara_dfa_free_tables(struct sara_dfa_tables *dfa) +{ + if (dfa) { + kvfree(dfa->output); + kvfree(dfa->def); + kvfree(dfa->base); + kvfree(dfa->next); + kvfree(dfa->check); + kvfree(dfa); + } +} + +static struct sara_dfa_tables *sara_dfa_alloc_tables(sara_dfa_state states, + sara_dfa_state cmp_states) +{ + struct sara_dfa_tables *tmp = NULL; + + tmp = kvzalloc(sizeof(*tmp), GFP_KERNEL_ACCOUNT); + if (!tmp) + goto err; + tmp->output = kvcalloc(states, + sizeof(*tmp->output), + GFP_KERNEL_ACCOUNT); + if (!tmp->output) + goto err; + tmp->def = kvcalloc(states, + sizeof(*tmp->def), + GFP_KERNEL_ACCOUNT); + if (!tmp->def) + goto err; + tmp->base = kvcalloc(states, + sizeof(*tmp->base), + GFP_KERNEL_ACCOUNT); + if (!tmp->base) + goto err; + tmp->next = kvcalloc(cmp_states, + sizeof(*tmp->next) * DFA_INPUTS, + GFP_KERNEL_ACCOUNT); + if (!tmp->next) + goto err; + tmp->check = kvcalloc(cmp_states, + sizeof(*tmp->check) * DFA_INPUTS, + GFP_KERNEL_ACCOUNT); + if (!tmp->check) + goto err; + tmp->states = states; + tmp->cmp_states = cmp_states; + return tmp; + +err: + sara_dfa_free_tables(tmp); + return ERR_PTR(-ENOMEM); +} + +int sara_dfa_match(struct sara_dfa_tables *dfa, + const unsigned char *s, + sara_dfa_output *output) +{ + sara_dfa_state i, j; + sara_dfa_state c_state = 0; + + /* Max s[x] value must be == DFA_INPUTS */ + BUILD_BUG_ON((((1ULL << (sizeof(*s) * 8)) - 1) != DFA_INPUTS)); + + /* + * The DFA transition table is compressed using 5 linear arrays + * as shown in the Dragon Book. + * These arrays are: default, base, next, check and output. + * default, base and output have the same size and are indexed by + * state number. + * next and check tables have the same size and are indexed by + * the value from base for a given state and the input symbol. + * To match a string against this set of arrays we need to: + * - Use the base arrays to recover the index to use + * with check and next arrays for the current state and symbol. + * - If the value in the check array matches the current state + * number the next state should be retrieved from the next array, + * otherwise we take it from the default array. + * - If the next state is not valid we should return immediately + * - If the input sequence is over and the value in the output array + * is valid, the string matches, and we should return the output + * value. + */ + + for (i = 0; s[i]; i++) { + j = (dfa->base[c_state] * DFA_INPUTS) + s[i] - 1; + if (dfa->check[j] != c_state) + c_state = dfa->def[c_state]; + else + c_state = dfa->next[j]; + if (c_state == SARA_INVALID_DFA_VALUE) + return 0; + } + + if (dfa->output[c_state] != SARA_INVALID_DFA_VALUE) { + *output = dfa->output[c_state]; + return 1; + } + return 0; +} + +struct sara_dfa_tables *sara_dfa_make_null(void) +{ + int i; + struct sara_dfa_tables *dfa = NULL; + + dfa = sara_dfa_alloc_tables(1, 1); + if (unlikely(IS_ERR_OR_NULL(dfa))) + return NULL; + dfa->output[0] = SARA_INVALID_DFA_VALUE; + dfa->def[0] = SARA_INVALID_DFA_VALUE; + dfa->base[0] = 0; + for (i = 0; i < DFA_INPUTS; ++i) + dfa->next[i] = SARA_INVALID_DFA_VALUE; + for (i = 0; i < DFA_INPUTS; ++i) + dfa->check[i] = 0; + memset(dfa->hash, 0, SARA_CONFIG_HASH_LEN); + return dfa; +} + +struct binary_dfa_header { + char magic[DFA_MAGIC_SIZE]; + __le32 version; + __le32 states; + __le32 cmp_states; + char hash[SARA_CONFIG_HASH_LEN]; +} __packed; + +#define SARA_INVALID_DFA_VALUE_LOAD 0xffffffffu + +struct sara_dfa_tables *sara_dfa_load(const char *buf, + size_t buf_len, + bool (*is_valid)(sara_dfa_output)) +{ + int ret; + struct sara_dfa_tables *dfa = NULL; + struct binary_dfa_header *h = (struct binary_dfa_header *) buf; + __le32 *p; + uint64_t i; + u32 version, states, cmp_states, tmp; + + ret = -EINVAL; + if (unlikely(buf_len < sizeof(*h))) + goto out; + + ret = -EINVAL; + if (unlikely(memcmp(h->magic, DFA_MAGIC, DFA_MAGIC_SIZE) != 0)) + goto out; + version = le32_to_cpu(h->version); + states = le32_to_cpu(h->states); + cmp_states = le32_to_cpu(h->cmp_states); + if (unlikely(version != SARA_DFA_VERSION)) { + pr_err_ratelimited("DFA: unsupported version\n"); + goto out; + } + if (unlikely(states >= SARA_INVALID_DFA_VALUE || + cmp_states >= SARA_INVALID_DFA_VALUE)) { + pr_err_dfa_size(); + goto out; + } + if (unlikely(states == 0 || + cmp_states == 0)) + goto out; + if (unlikely(((states * sizeof(u32) * 3) + + (cmp_states * sizeof(u32) * 2 * DFA_INPUTS) + + sizeof(*h)) != buf_len)) + goto out; + + ret = -ENOMEM; + dfa = sara_dfa_alloc_tables(h->states, h->cmp_states); + if (unlikely(IS_ERR_OR_NULL(dfa))) + goto out; + + dfa->states = states; + dfa->cmp_states = cmp_states; + + ret = -EINVAL; + p = (__le32 *) (buf + sizeof(*h)); + for (i = 0; i < dfa->states; i++) { + tmp = le32_to_cpu(*p); + if (unlikely(tmp != SARA_INVALID_DFA_VALUE_LOAD && + tmp >= dfa->states)) + goto out_alloc; + dfa->def[i] = (sara_dfa_state) tmp; + ++p; + } + for (i = 0; i < dfa->states; i++) { + tmp = le32_to_cpu(*p); + if (unlikely(tmp >= dfa->cmp_states)) + goto out_alloc; + dfa->base[i] = (sara_dfa_state) tmp; + ++p; + } + for (i = 0; i < (dfa->cmp_states * DFA_INPUTS); i++) { + tmp = le32_to_cpu(*p); + if (unlikely(tmp != SARA_INVALID_DFA_VALUE_LOAD && + tmp >= dfa->states)) + goto out_alloc; + dfa->next[i] = (sara_dfa_state) tmp; + ++p; + } + for (i = 0; i < (dfa->cmp_states * DFA_INPUTS); i++) { + tmp = le32_to_cpu(*p); + if (unlikely(tmp != SARA_INVALID_DFA_VALUE_LOAD && + tmp >= dfa->states)) + goto out_alloc; + dfa->check[i] = (sara_dfa_state) tmp; + ++p; + } + for (i = 0; i < dfa->states; i++) { + tmp = le32_to_cpu(*p); + if (unlikely(tmp != SARA_INVALID_DFA_VALUE_LOAD && + !is_valid(tmp))) + goto out_alloc; + dfa->output[i] = (sara_dfa_state) tmp; + ++p; + } + if (unlikely((void *) p != (void *) (buf + buf_len))) + goto out_alloc; + + BUILD_BUG_ON(sizeof(dfa->hash) != sizeof(h->hash)); + memcpy(dfa->hash, h->hash, sizeof(dfa->hash)); + + return dfa; +out_alloc: + sara_dfa_free_tables(dfa); +out: + pr_err_ratelimited("DFA: invalid load\n"); + return ERR_PTR(ret); +} + +ssize_t sara_dfa_dump(const struct sara_dfa_tables *dfa, char **buffer) +{ + char *buf; + size_t buf_len = 0; + struct binary_dfa_header *h; + __le32 *p; + int i; + + buf_len = sizeof(*h) + + dfa->states * sizeof(__le32) * 3 + + dfa->cmp_states * sizeof(__le32) * DFA_INPUTS * 2; + buf = kvmalloc(buf_len, GFP_KERNEL_ACCOUNT); + if (unlikely(!buf)) + return -ENOMEM; + + h = (struct binary_dfa_header *) buf; + memcpy(h->magic, DFA_MAGIC, DFA_MAGIC_SIZE); + h->version = cpu_to_le32(SARA_DFA_VERSION); + h->states = cpu_to_le32(dfa->states); + h->cmp_states = cpu_to_le32(dfa->cmp_states); + BUILD_BUG_ON(sizeof(dfa->hash) != sizeof(h->hash)); + memcpy(h->hash, dfa->hash, sizeof(dfa->hash)); + + p = (__le32 *) (buf + sizeof(*h)); + for (i = 0; i < dfa->states; i++) { + if (dfa->def[i] == SARA_INVALID_DFA_VALUE) + *p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD); + else + *p++ = cpu_to_le32(dfa->def[i]); + } + for (i = 0; i < dfa->states; i++) { + if (dfa->base[i] == SARA_INVALID_DFA_VALUE) + *p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD); + else + *p++ = cpu_to_le32(dfa->base[i]); + } + for (i = 0; i < (dfa->cmp_states * DFA_INPUTS); i++) { + if (dfa->next[i] == SARA_INVALID_DFA_VALUE) + *p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD); + else + *p++ = cpu_to_le32(dfa->next[i]); + } + for (i = 0; i < (dfa->cmp_states * DFA_INPUTS); i++) { + if (dfa->check[i] == SARA_INVALID_DFA_VALUE) + *p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD); + else + *p++ = cpu_to_le32(dfa->check[i]); + } + for (i = 0; i < dfa->states; i++) { + if (dfa->output[i] == SARA_INVALID_DFA_VALUE) + *p++ = cpu_to_le32(SARA_INVALID_DFA_VALUE_LOAD); + else + *p++ = cpu_to_le32(dfa->output[i]); + } + + if (unlikely((void *) p != (void *) (buf + buf_len))) { + /* + * We can calculate the correct buffer size upfront. + * This should never happen. + */ + kvfree(buf); + pr_crit("memory corruption in %s\n", __func__); + return 0; + } + + *buffer = buf; + return buf_len; +} + +#undef SARA_INVALID_DFA_VALUE_LOAD diff --git a/security/sara/dfa_test.c b/security/sara/dfa_test.c new file mode 100644 index 0000000..9c06414 --- /dev/null +++ b/security/sara/dfa_test.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#include "include/dfa.h" +#include "include/securityfs.h" +#include +#include +#include + +#define SARA_DFA_MAX_RES_SIZE 20 + +struct sara_dfa_tables *table; + +static DEFINE_MUTEX(test_lock); +static sara_dfa_output result; + +static bool is_valid_output(sara_dfa_output output) +{ + return true; +} + +static int config_load(const char *buf, size_t buf_len) +{ + struct sara_dfa_tables *dfa, *tmp; + + dfa = sara_dfa_load(buf, buf_len, is_valid_output); + if (unlikely(IS_ERR_OR_NULL(dfa))) { + if (unlikely(dfa == NULL)) + return -EINVAL; + else + return PTR_ERR(dfa); + } + mutex_lock(&test_lock); + tmp = table; + table = dfa; + mutex_unlock(&test_lock); + sara_dfa_free_tables(tmp); + return 0; +} + +static int config_load_str(const char *buf, size_t buf_len) +{ + char *s; + + s = kmalloc(buf_len+1, GFP_KERNEL_ACCOUNT); + if (unlikely(s == NULL)) + return -ENOMEM; + s[buf_len] = '\0'; + memcpy(s, buf, buf_len); + + mutex_lock(&test_lock); + result = SARA_INVALID_DFA_VALUE; + sara_dfa_match(table, s, &result); + mutex_unlock(&test_lock); + + kfree(s); + + return 0; +} + +static ssize_t config_dump_result(char **buf) +{ + char *s; + + s = kzalloc(SARA_DFA_MAX_RES_SIZE, GFP_KERNEL_ACCOUNT); + if (unlikely(s == NULL)) + return -ENOMEM; + mutex_lock(&test_lock); + if (result == SARA_INVALID_DFA_VALUE) + snprintf(s, SARA_DFA_MAX_RES_SIZE, "%u\n", 0xffffffff); + else + snprintf(s, + SARA_DFA_MAX_RES_SIZE, + "%u\n", + (unsigned int) result); + mutex_unlock(&test_lock); + *buf = s; + return strlen(s); +} + +static struct sara_secfs_fptrs fptrs __lsm_ro_after_init = { + .load = config_load, +}; + +static struct sara_secfs_fptrs teststr __lsm_ro_after_init = { + .load = config_load_str, + .dump = config_dump_result, +}; + +static const struct sara_secfs_node dfa_test_fs[] __initconst = { + { + .name = ".load", + .type = SARA_SECFS_CONFIG_LOAD, + .data = &fptrs, + }, + { + .name = "test", + .type = SARA_SECFS_CONFIG_LOAD, + .data = &teststr, + }, + { + .name = "result", + .type = SARA_SECFS_CONFIG_DUMP, + .data = &teststr, + }, +}; + +int __init sara_dfa_test_init(void) +{ + int ret; + + table = sara_dfa_make_null(); + if (unlikely(!table)) + return -ENOMEM; + ret = sara_secfs_subtree_register("dfa_test", + dfa_test_fs, + ARRAY_SIZE(dfa_test_fs)); + if (unlikely(ret)) + goto out_fail; + return 0; + +out_fail: + sara_dfa_free_tables(table); + return ret; +} diff --git a/security/sara/include/dfa.h b/security/sara/include/dfa.h new file mode 100644 index 0000000..a536b60 --- /dev/null +++ b/security/sara/include/dfa.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#ifndef __SARA_DFA_H +#define __SARA_DFA_H + +#include "securityfs.h" + +#ifdef CONFIG_SARA_DFA_32BIT +typedef uint32_t sara_dfa_state; +typedef uint32_t sara_dfa_output; +#define SARA_INVALID_DFA_VALUE 0xffffffffu +#else +typedef uint16_t sara_dfa_state; +typedef uint16_t sara_dfa_output; +#define SARA_INVALID_DFA_VALUE 0xffffu +#endif + +#define SARA_DFA_VERSION 2 + +struct sara_dfa_tables { + sara_dfa_state states; + sara_dfa_state cmp_states; + sara_dfa_output *output; + sara_dfa_state *def; + sara_dfa_state *base; + sara_dfa_state *next; + sara_dfa_state *check; + char hash[SARA_CONFIG_HASH_LEN]; +}; + +int sara_dfa_match(struct sara_dfa_tables *dfa, + const unsigned char *s, + sara_dfa_output *output); +struct sara_dfa_tables *sara_dfa_make_null(void); +struct sara_dfa_tables *sara_dfa_load(const char *buf, + size_t buf_len, + bool (*is_valid)(sara_dfa_output)); +ssize_t sara_dfa_dump(const struct sara_dfa_tables *dfa, char **buffer); +void sara_dfa_free_tables(struct sara_dfa_tables *dfa); + +#endif /* __SARA_DFA_H */ diff --git a/security/sara/include/dfa_test.h b/security/sara/include/dfa_test.h new file mode 100644 index 0000000..f10f78a --- /dev/null +++ b/security/sara/include/dfa_test.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + */ + +#ifndef __SARA_DFA_TEST_H +#define __SARA_DFA_TEST_H + +#ifdef CONFIG_SECURITY_SARA_DFA_TEST + +#include +int sara_dfa_test_init(void) __init; + +#else /* CONFIG_SECURITY_SARA_DFA_TEST */ +inline int sara_dfa_test_init(void) +{ + return 0; +} +#endif /* CONFIG_SECURITY_SARA_DFA_TEST */ + +#endif /* __SARA_DFA_TEST_H */ diff --git a/security/sara/main.c b/security/sara/main.c index dc5dda4..6b09500 100644 --- a/security/sara/main.c +++ b/security/sara/main.c @@ -17,6 +17,7 @@ #include #include +#include "include/dfa_test.h" #include "include/sara.h" #include "include/sara_data.h" #include "include/securityfs.h" @@ -99,6 +100,11 @@ static int __init sara_init(void) goto error; } + if (sara_dfa_test_init()) { + pr_crit("impossible to initialize DFA test interface.\n"); + goto error; + } + pr_debug("initialized.\n"); if (sara_enabled) From patchwork Sat Jul 6 10:54:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033597 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 88E6C14F6 for ; Sat, 6 Jul 2019 10:55:28 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 77A572881B for ; Sat, 6 Jul 2019 10:55:28 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6BB2328994; Sat, 6 Jul 2019 10:55:28 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AF1432881B for ; Sat, 6 Jul 2019 10:55:27 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id E25DD8E0003; Sat, 6 Jul 2019 06:55:19 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id D8AF98E0001; Sat, 6 Jul 2019 06:55:19 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B41338E0003; Sat, 6 Jul 2019 06:55:19 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by kanga.kvack.org (Postfix) with ESMTP id 63FC76B000C for ; Sat, 6 Jul 2019 06:55:19 -0400 (EDT) Received: by mail-wr1-f70.google.com with SMTP id r4so5026535wrt.13 for ; Sat, 06 Jul 2019 03:55:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=tc9nxOt0YynZlg4DtgqDwIM4b55l1zqGz9yWCnOUqxc=; b=P6oXX3/Tk6KZi35NHpZ00hFFBccHogo1ZsZZjxZejGzAOLlkM3Aj32f1GLaUF4+8za vWURO5fF8RHR1/ySc+8fpP+hoQoTHi6sPptSN7UnZxSl4i5AfIxr31GOnHYGWSqiRvdl 7+mZszSqpC/oSMFX9A2uIOLqyxxYSMQvt5zyI8rg3CSSD8/zbu0XLXtLJrT8bDvuGHD/ TtMzB0hpFTJ5RDP8OPWJmlTtK8tmh9ukbHsI7MDwOciivpRUchSiDcVknTax6ouVfdQU D2k+xK80ZEtnSPYaPziWFrpA+4HEYH7ujqcde7gLiKegs3XpHYNkWX80xbxs6+D+LW/c r78A== X-Gm-Message-State: APjAAAXRaiSyxEjRiHLt0zthd6BFcPb225ZBCn0o5N8jvnEFk+HIPeNY FScXQWMs3IE9WRjUA/eKfR6gKDEjakfDvdbHGTkwiNdv0SVNh7B76z8POntwEl7a3Fqmbx8wK4w GWURP6xW5JrKBclBwz5AFD72XomQ7BfbrEqzC88AguvzGfddTdSxaGzZkOkyY7t2Gfg== X-Received: by 2002:adf:e751:: with SMTP id c17mr8987935wrn.98.1562410518960; Sat, 06 Jul 2019 03:55:18 -0700 (PDT) X-Received: by 2002:adf:e751:: with SMTP id c17mr8987792wrn.98.1562410517450; Sat, 06 Jul 2019 03:55:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410517; cv=none; d=google.com; s=arc-20160816; b=US+2BQ1dsdY1lS9XksfmzBIup532hMTXYTM9hs+1nXcH4iAYqja1K102SZ00vJi6ca q5SV1cOppj0wQHgZtf/5o3JBvxJUynUQbFVtRXROK/IQxoi5wmKU6GnxhchPMprfrdaK 1uY9Gx+VrjC312ImDHglt1l6YYo+YsxiuqQf7za90rkjN/7Hd4dpPNL/k388XH1OPVXR EdGaLqrkQ4rqX09E5uPLQ+sDHAnFZO+RkazDs7AW7udjmVESD4PjMU46Feuc3A+9XSmD VdwFidhUgF8MXK69v7WOspiF9g73ZrDonJ68GyS40ajISGyZ/QFOJkYP5gtxY5KwW3NH V7gQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=tc9nxOt0YynZlg4DtgqDwIM4b55l1zqGz9yWCnOUqxc=; b=f6fJNa2jvhqp9NvN/fdz2whQl9OJgBfJNijBMGze9NtAgHU8bpih9xXlJzRWh4Ub44 hTrKi7vpCQRbEaXpKIqKVSrihreExWGVWISW/MLhb6cJZRcwUl+aNVJg+obnR0ay4Pp1 xm/4kQBe8Gordnd1YvtU7yuSeplwg2xOi6BP9SwwaFSp3rQUwRerS7aberxR6t3tkF2b RkGsJNFE3/zLuUAkNmjgfti5cZDJlYNP3GWl1+yyxSLFzv/LsPiffS0VI0PivfJPPRSK ZS00cj+wmYVjkfgvUyXbwERMFzyYHXRU8FGJuvN58htzXBehx/XvOYDI3A74EeX8/G9C yBVA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b="H/hv3oql"; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id z139sor6286858wmc.25.2019.07.06.03.55.17 for (Google Transport Security); Sat, 06 Jul 2019 03:55:17 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b="H/hv3oql"; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tc9nxOt0YynZlg4DtgqDwIM4b55l1zqGz9yWCnOUqxc=; b=H/hv3oqlvBbndX96qLPf5yWClDQ6sRuTVt5tRUmkZdBjqfNT8QP6eSS48eMgnLnX3M WMQ4grRnDFsHfzcmJCa2NZW22qa3lXOGIluOW5jgh2LpcgL7DkJ54y1w0C6Xhkpp2ntZ I/av/JjLtKAzbQq7e3mH2IiGg67xxHpyAjtACqs2raUphqFhtSD3uoAU+89+iqorUH8i Taggjzu3zY8qh5GVcr/ruUdLkoTpT4zqR8vtjxaqQtGYSk/tQjq/DHcYhOTPMA3P0Zf2 4XSF8AjFUnGcVP26TnVi4uep/PBucOaPpgJiMZ2o/nHHHTtddc59KmP2z9DdGZLZZfYC 2KfA== X-Google-Smtp-Source: APXvYqwjn5IyS6SWM65IBzeh/bdnAqkvGqGa6i9TXN3uin56hMILK/3JcH3obevfA3uL9Qb6/jMB4g== X-Received: by 2002:a1c:4d6:: with SMTP id 205mr7201683wme.148.1562410517083; Sat, 06 Jul 2019 03:55:17 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.16 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:16 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 05/12] LSM: creation of "check_vmflags" LSM hook Date: Sat, 6 Jul 2019 12:54:46 +0200 Message-Id: <1562410493-8661-6-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Creation of a new LSM hook to check if a given configuration of vmflags, for a new memory allocation request, should be allowed or not. It's placed in "do_mmap", "do_brk_flags", "__install_special_mapping" and "setup_arg_pages". When loading an ELF, this hook is also used to determine what to do with an RWE PT_GNU_STACK header. This allows LSM to force the loader to silently ignore executable stack markings, which is useful a thing to do when trampoline emulation is available. Signed-off-by: Salvatore Mesoraca --- fs/binfmt_elf.c | 3 ++- fs/binfmt_elf_fdpic.c | 3 ++- fs/exec.c | 4 ++++ include/linux/lsm_hooks.h | 7 +++++++ include/linux/security.h | 6 ++++++ mm/mmap.c | 13 +++++++++++++ security/security.c | 5 +++++ 7 files changed, 39 insertions(+), 2 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 8264b46..1d98737 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -806,7 +806,8 @@ static int load_elf_binary(struct linux_binprm *bprm) for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) switch (elf_ppnt->p_type) { case PT_GNU_STACK: - if (elf_ppnt->p_flags & PF_X) + if (elf_ppnt->p_flags & PF_X && + !security_check_vmflags(VM_EXEC|VM_READ|VM_WRITE)) executable_stack = EXSTACK_ENABLE_X; else executable_stack = EXSTACK_DISABLE_X; diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index d86ebd0d..6e0dee1 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -163,7 +163,8 @@ static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *params, if (phdr->p_type != PT_GNU_STACK) continue; - if (phdr->p_flags & PF_X) + if (phdr->p_flags & PF_X && + !security_check_vmflags(VM_EXEC|VM_READ|VM_WRITE)) params->flags |= ELF_FDPIC_FLAG_EXEC_STACK; else params->flags |= ELF_FDPIC_FLAG_NOEXEC_STACK; diff --git a/fs/exec.c b/fs/exec.c index 89a500b..abf770a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -756,6 +756,10 @@ int setup_arg_pages(struct linux_binprm *bprm, vm_flags |= mm->def_flags; vm_flags |= VM_STACK_INCOMPLETE_SETUP; + ret = security_check_vmflags(vm_flags); + if (ret) + goto out_unlock; + ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end, vm_flags); if (ret) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 47f58cf..12ce609 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -513,6 +513,11 @@ * @reqprot contains the protection requested by the application. * @prot contains the protection that will be applied by the kernel. * Return 0 if permission is granted. + * @check_vmflags: + * Check if the requested @vmflags are allowed. + * @vmflags contains the requested vmflags. + * Return 0 if the operation is allowed to continue otherwise return + * the appropriate error code. * @file_lock: * Check permission before performing file locking operations. * Note the hook mediates both flock and fcntl style locks. @@ -1597,6 +1602,7 @@ unsigned long prot, unsigned long flags); int (*file_mprotect)(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot); + int (*check_vmflags)(vm_flags_t vmflags); int (*file_lock)(struct file *file, unsigned int cmd); int (*file_fcntl)(struct file *file, unsigned int cmd, unsigned long arg); @@ -1897,6 +1903,7 @@ struct security_hook_heads { struct hlist_head mmap_addr; struct hlist_head mmap_file; struct hlist_head file_mprotect; + struct hlist_head check_vmflags; struct hlist_head file_lock; struct hlist_head file_fcntl; struct hlist_head file_set_fowner; diff --git a/include/linux/security.h b/include/linux/security.h index 659071c..aed78eb 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -312,6 +312,7 @@ int security_mmap_file(struct file *file, unsigned long prot, int security_mmap_addr(unsigned long addr); int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot); +int security_check_vmflags(vm_flags_t vmflags); int security_file_lock(struct file *file, unsigned int cmd); int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg); void security_file_set_fowner(struct file *file); @@ -859,6 +860,11 @@ static inline int security_file_mprotect(struct vm_area_struct *vma, return 0; } +static inline int security_check_vmflags(vm_flags_t vmflags) +{ + return 0; +} + static inline int security_file_lock(struct file *file, unsigned int cmd) { return 0; diff --git a/mm/mmap.c b/mm/mmap.c index 7e8c3e8a..ec9c0e3d 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1390,6 +1390,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr, { struct mm_struct *mm = current->mm; int pkey = 0; + int error; *populate = 0; @@ -1453,6 +1454,10 @@ unsigned long do_mmap(struct file *file, unsigned long addr, vm_flags |= calc_vm_prot_bits(prot, pkey) | calc_vm_flag_bits(flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; + error = security_check_vmflags(vm_flags); + if (error) + return error; + if (flags & MAP_LOCKED) if (!can_do_mlock()) return -EPERM; @@ -2996,6 +3001,10 @@ static int do_brk_flags(unsigned long addr, unsigned long len, unsigned long fla return -EINVAL; flags |= VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; + error = security_check_vmflags(flags); + if (error) + return error; + error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED); if (offset_in_page(error)) return error; @@ -3393,6 +3402,10 @@ static struct vm_area_struct *__install_special_mapping( int ret; struct vm_area_struct *vma; + ret = security_check_vmflags(vm_flags); + if (ret) + return ERR_PTR(ret); + vma = vm_area_alloc(mm); if (unlikely(vma == NULL)) return ERR_PTR(-ENOMEM); diff --git a/security/security.c b/security/security.c index f493db0..3308e89 100644 --- a/security/security.c +++ b/security/security.c @@ -1421,6 +1421,11 @@ int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, return call_int_hook(file_mprotect, 0, vma, reqprot, prot); } +int security_check_vmflags(vm_flags_t vmflags) +{ + return call_int_hook(check_vmflags, 0, vmflags); +} + int security_file_lock(struct file *file, unsigned int cmd) { return call_int_hook(file_lock, 0, file, cmd); From patchwork Sat Jul 6 10:54:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033599 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A873F14F6 for ; Sat, 6 Jul 2019 10:55:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 982212881B for ; Sat, 6 Jul 2019 10:55:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8B7DE289D2; Sat, 6 Jul 2019 10:55:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C28982881B for ; Sat, 6 Jul 2019 10:55:30 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 6F7218E0005; Sat, 6 Jul 2019 06:55:22 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 6AACD8E0001; Sat, 6 Jul 2019 06:55:22 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 45F268E0005; Sat, 6 Jul 2019 06:55:22 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by kanga.kvack.org (Postfix) with ESMTP id E6F018E0001 for ; Sat, 6 Jul 2019 06:55:21 -0400 (EDT) Received: by mail-wr1-f69.google.com with SMTP id f9so2661323wrq.14 for ; Sat, 06 Jul 2019 03:55:21 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=HSNnsoi40sXC9a5NBIzV0J+z/SUw5gqWPuXVFawRMYc=; b=kFf0hnGlzxQWPogscXnBJlx7GaT7rV27AwqKl7cByq1m2LIB1ocShWRM3rTKefZAKp xsFQjdQJ6opMGArAUXs12hQR5X44z/yc9yF88SoB/truWgYOb/k4N59i2NeV9N+Sv/va b3CjVQJA7UagYIaz8BVecaWb+vKzVLP7u1aElJHbxeANGCyAh9nQLUckqVBP4eJpy5mt 3hopnLVLjh7h9uzXHrx7sZvE/CMlmoa2LOpVWt++OdJ2yBmTixVpGR9iXF0yzK3mo3nI +D1ZDXHEcTbFR5IL0Q8UUHCoNDjsIaB4dgN4fmiz73re2U99XdL14uc6Ua6R4aPsmIFz znWA== X-Gm-Message-State: APjAAAXpWdk5X8jKVhOibwfDutHf/j7Vx+Lj+y0PBRuhsPmeClIwrE/y Cn5GRnmCB/1mssKLAbCHvJzLRD2XjYVo5RHgBEDATGuajX18Jm3AkDPZIY/8kxNe46HbfJOt8Xu Njuk+JLTUTqXtvpf23yL9DU8NBDcMEg6l4d3haTK2kOXsTeQZoWVdRId6lBt461zwFA== X-Received: by 2002:a1c:a985:: with SMTP id s127mr7616590wme.163.1562410521484; Sat, 06 Jul 2019 03:55:21 -0700 (PDT) X-Received: by 2002:a1c:a985:: with SMTP id s127mr7616479wme.163.1562410520138; Sat, 06 Jul 2019 03:55:20 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410520; cv=none; d=google.com; s=arc-20160816; b=QWeJWTvEb0EvOknxoHneExtuDoy4S86gD3eG+h+SZdJAQDK8A9wcUFceIM7PjmbuSm 7viK2bTgyvHE+WoukuhWAIvh0SuFo4g+KFThS528hTf8g3bdoYP6ik72MZppdBh+4XU5 RF9wVk8CWFIMrz/bwVo2BYNra8dn0DvANzKXGMHUsQesOfDre5jCvK3JQVVZpsamAQ5Z gm4Rkwi3f73Jhf+RfkTeqO8WPHatkK5i8eoFfcxqWccioFeonIhwWxVL240e7ciqTwnI 3i6ngjkcBxVC6LtFGPx67QMmDIAnUSVLBYZU6xeuTaRnQpHYz4OEOClw+CWkP3aj9MEr n5RA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=HSNnsoi40sXC9a5NBIzV0J+z/SUw5gqWPuXVFawRMYc=; b=RsZO2Yu9ljiadRipOIM/8KCDMxnHNoyPAUOE1MtlwQF5bVgrADIh9SUMeZPimYQCcb RAoVuoRyGTWSjx2Z6dQrw3+xD38NgI+VGZ0QZJjCwn3WX9RnTnt590rEXF6IJBxzz+GG m7s3Duz17RpfSS2PQbE+fm4P8a81CNkAtIUFW+i5YRKghFZqlLrdkCpjAEs1k1z14KuD G/GdLnOLnJCwHUnzk+XhO17FsFAlxyWw/EcpDRWLwHivjRunZPeoTkxde7AIvItyL37o NpyqTFNHiOLR8hqZokGWE//JSX3DIS+YAzLNMqQ1wR8gkKk6kMghRNqXm16/55kWw/9u cENg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=V7AvK11r; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id s18sor6400200wmc.28.2019.07.06.03.55.20 for (Google Transport Security); Sat, 06 Jul 2019 03:55:20 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=V7AvK11r; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=HSNnsoi40sXC9a5NBIzV0J+z/SUw5gqWPuXVFawRMYc=; b=V7AvK11reWJTiJ1DMourV1U4KNoutKJGDoiTGDXXM3R+PR5LpFynIPMuHGWbUmIT6N 62QOnfL7Spg5I7UppXlkG9bH566FlMkdYX2c5mITv+X49REEJ7TzTRD5C+iQfoN/4rPl UgKMTPNUamuI84pgZfGnM+KdecKNvQnLCdW9YiA5ieNyU+3CJjFBApwua+MKXWYTWR3W cDjDfWnzPiKTGrdUhnTZwNc+HFKvMUxWxCZ7CxTIxdI37rHw++WBf8TzZNY7DbiPJbPx Vi4i+Oh39vDEODfCMLRruFPTteb2P7fgj4MRU+BMXpmRVkxdZYPg4w23p2aEvnIp8KBu br5g== X-Google-Smtp-Source: APXvYqxTOz8ZdoRBiRrROUWhnI6SyewPlaUzoSCGW9GiCDm2WtNdoe4eOEEH3/a8B3ek3jvZ4FdMSg== X-Received: by 2002:a7b:cbc6:: with SMTP id n6mr8125351wmi.14.1562410519789; Sat, 06 Jul 2019 03:55:19 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:18 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 07/12] LSM: creation of "pagefault_handler" LSM hook Date: Sat, 6 Jul 2019 12:54:48 +0200 Message-Id: <1562410493-8661-8-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Creation of a new hook to let LSM modules handle user-space pagefaults on x86. It can be used to avoid segfaulting the originating process. If it's the case it can modify process registers before returning. This is not a security feature by itself, it's a way to soften some unwanted side-effects of restrictive security features. In particular this is used by S.A.R.A. to implement what PaX call "trampoline emulation" that, in practice, allows for some specific code sequences to be executed even if they are in non executable memory. This may look like a bad thing at first, but you have to consider that: - This allows for strict memory restrictions (e.g. W^X) to stay on even when they should be turned off. And, even if this emulation makes those features less effective, it's still better than having them turned off completely. - The only code sequences emulated are trampolines used to make function calls. In many cases, when you have the chance to make arbitrary memory writes, you can already manipulate the control flow of the program by overwriting function pointers or return values. So, in many cases, "trampoline emulation" doesn't introduce new exploit vectors. - It's a feature that can be turned on only if needed, on a per executable file basis. Signed-off-by: Salvatore Mesoraca --- arch/Kconfig | 6 ++++++ arch/x86/Kconfig | 1 + arch/x86/mm/fault.c | 6 ++++++ include/linux/lsm_hooks.h | 12 ++++++++++++ include/linux/security.h | 11 +++++++++++ security/security.c | 11 +++++++++++ 6 files changed, 47 insertions(+) diff --git a/arch/Kconfig b/arch/Kconfig index c47b328..16997c3 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -252,6 +252,12 @@ config ARCH_HAS_FORTIFY_SOURCE config ARCH_HAS_KEEPINITRD bool +config ARCH_HAS_LSM_PAGEFAULT + bool + help + An architecture should select this if it supports + "pagefault_handler" LSM hook. + # Select if arch has all set_memory_ro/rw/x/nx() functions in asm/cacheflush.h config ARCH_HAS_SET_MEMORY bool diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 2bbbd4d..a3c7660 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -67,6 +67,7 @@ config X86 select ARCH_HAS_FORTIFY_SOURCE select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_KCOV if X86_64 + select ARCH_HAS_LSM_PAGEFAULT select ARCH_HAS_MEMBARRIER_SYNC_CORE select ARCH_HAS_PMEM_API if X86_64 select ARCH_HAS_PTE_SPECIAL diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 46df4c6..7fe36f1 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -18,6 +18,7 @@ #include /* faulthandler_disabled() */ #include /* efi_recover_from_page_fault()*/ #include +#include /* security_pagefault_handler */ #include /* boot_cpu_has, ... */ #include /* dotraplinkage, ... */ @@ -1360,6 +1361,11 @@ void do_user_addr_fault(struct pt_regs *regs, local_irq_enable(); } + if (unlikely(security_pagefault_handler(regs, + hw_error_code, + address))) + return; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); if (hw_error_code & X86_PF_WRITE) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 12ce609..478a187 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -518,6 +518,14 @@ * @vmflags contains the requested vmflags. * Return 0 if the operation is allowed to continue otherwise return * the appropriate error code. + * @pagefault_handler: + * Handle pagefaults on supported architectures, that is any architecture + * which defines CONFIG_ARCH_HAS_LSM_PAGEFAULT. + * @regs contains process' registers. + * @error_code contains error code for the pagefault. + * @address contains the address that caused the pagefault. + * Return 0 to let the kernel handle the pagefault as usually, any other + * value to let the process continue its execution. * @file_lock: * Check permission before performing file locking operations. * Note the hook mediates both flock and fcntl style locks. @@ -1603,6 +1611,9 @@ int (*file_mprotect)(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot); int (*check_vmflags)(vm_flags_t vmflags); + int (*pagefault_handler)(struct pt_regs *regs, + unsigned long error_code, + unsigned long address); int (*file_lock)(struct file *file, unsigned int cmd); int (*file_fcntl)(struct file *file, unsigned int cmd, unsigned long arg); @@ -1904,6 +1915,7 @@ struct security_hook_heads { struct hlist_head mmap_file; struct hlist_head file_mprotect; struct hlist_head check_vmflags; + struct hlist_head pagefault_handler; struct hlist_head file_lock; struct hlist_head file_fcntl; struct hlist_head file_set_fowner; diff --git a/include/linux/security.h b/include/linux/security.h index aed78eb..c287eb2 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -313,6 +313,9 @@ int security_mmap_file(struct file *file, unsigned long prot, int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot); int security_check_vmflags(vm_flags_t vmflags); +int __maybe_unused security_pagefault_handler(struct pt_regs *regs, + unsigned long error_code, + unsigned long address); int security_file_lock(struct file *file, unsigned int cmd); int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg); void security_file_set_fowner(struct file *file); @@ -865,6 +868,14 @@ static inline int security_check_vmflags(vm_flags_t vmflags) return 0; } +static inline int __maybe_unused security_pagefault_handler( + struct pt_regs *regs, + unsigned long error_code, + unsigned long address) +{ + return 0; +} + static inline int security_file_lock(struct file *file, unsigned int cmd) { return 0; diff --git a/security/security.c b/security/security.c index 3308e89..a8bdcf3 100644 --- a/security/security.c +++ b/security/security.c @@ -1426,6 +1426,17 @@ int security_check_vmflags(vm_flags_t vmflags) return call_int_hook(check_vmflags, 0, vmflags); } +int __maybe_unused security_pagefault_handler(struct pt_regs *regs, + unsigned long error_code, + unsigned long address) +{ + return call_int_hook(pagefault_handler, + 0, + regs, + error_code, + address); +} + int security_file_lock(struct file *file, unsigned int cmd) { return call_int_hook(file_lock, 0, file, cmd); From patchwork Sat Jul 6 10:54:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033605 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4CA9C14F6 for ; Sat, 6 Jul 2019 10:55:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3A1E22881B for ; Sat, 6 Jul 2019 10:55:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2E394289D2; Sat, 6 Jul 2019 10:55:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,GAPPY_SUBJECT,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8B4E32881B for ; Sat, 6 Jul 2019 10:55:36 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 8A98B8E0001; Sat, 6 Jul 2019 06:55:24 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 7E1468E0008; Sat, 6 Jul 2019 06:55:24 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 4AEBF8E0001; Sat, 6 Jul 2019 06:55:24 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by kanga.kvack.org (Postfix) with ESMTP id D32128E0006 for ; Sat, 6 Jul 2019 06:55:23 -0400 (EDT) Received: by mail-wr1-f72.google.com with SMTP id b1so5020274wru.4 for ; Sat, 06 Jul 2019 03:55:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=GuxALAFQ/TNai2yWaUBZYrBAIJmgHr1PeMz07TcuHEk=; b=raYdF7Xv6PZ8/ejE4Vd0zMoO+W1++JTaPdYze6HFLQjYjXOjkAeU22eEom/1K6E1A/ Zf5L3jXyU6eSsJ/5SkXE5pil/HbRNY6HzxUagLl/GOi5EXDXUFtPydKEusnRa+oW4exZ IVpAjQfDIPjjsopqv1MhMzPPZqCn55RRUeDhBr3YwCDKA4MgbYEymPIrf2uOfqPxqjcV 8+68fLxOMBVYfVR3LxyYAk+x5ybDU3szXmZqtPXvVwx9cnV9PRJ6pROK6K0siv6gP9bx 5IX1fRBa2sC2UC+tlMjzIY+ZK1OQRSwKawcSJn9uRXeErxOLz/+2HrhCYtWO0qlmUak1 HJYw== X-Gm-Message-State: APjAAAVa+yt4DFTHkedfTS+0PitrH74KDkBKao5FcjtnlOAQ7MKjKcbQ 24OE0TMtkpg/omYYOJh8pNQmr0SpV3OX/Oz9e/C+qCRO/aaxxGkJDcfr8K7Lj0zzn+fuYniMsgH VilZ5+scXAAUulguJDKYGiw1oygeZx8BcGIhwYirIcD1drdZjeI0GLzlqVoO4soIVsg== X-Received: by 2002:a7b:c947:: with SMTP id i7mr8079290wml.77.1562410523365; Sat, 06 Jul 2019 03:55:23 -0700 (PDT) X-Received: by 2002:a7b:c947:: with SMTP id i7mr8079136wml.77.1562410521420; Sat, 06 Jul 2019 03:55:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410521; cv=none; d=google.com; s=arc-20160816; b=GiDUaiUEyZfNCQ6UUEBKGmCBFEQH0EL2IBqlQueyt3P5rMKIcenIknYBu6nLye6xPR 84U2s4gdcfj7RyM6liSFEor2oeHZcoXjAbbj8WwvDmYs+E65cK9i7skApZIiFngPQsBd eu4p6fFtMIEY+R7cn7UUE1yJZGOQK5QKqmG7BClB5o6ub/Fx5C7kU3bl3G8UCzimAHse l5O7wEpHBfq1WEDBEX5C6IzFZohZg3944DLiFO/XWLO1gTvLcjBgqKhvTm7K2/2Y4ryp Mv+D9I0rA83+kvEg8cw5vYlJr1OBZUUQVxiVMd7aDCYFgz+0W/88X/OrAJy832kSdwIE s0cw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=GuxALAFQ/TNai2yWaUBZYrBAIJmgHr1PeMz07TcuHEk=; b=HRPS4/PJE2FxxkVZBSSQG+3krgEAfoO+NztpxfR4wMr1I8nGdkPWX9yBxb3rGhsyKQ Z6n9zr4JHRfJ0siRU2eEAqm34eusqTOAFlKl0VXmvmN3b1kOX6RQf4+QkdQo91LlSzZX oJskB0h2bTLQ/cRIOX2SasFNlFKp0a11FxMflgaXok0RAecsJZdfUcqBS7WrMbEZuFwI IWtqnGNOQhqqL876QqCNlhauUMUIbBXASOtq38wMViIvOVw/vOyCohBhXq93WfY8hESi HbIBYoSqDF4q5pPJB0vEjXKkrcI0N/v/0wFYDC2GPGyWJHfKYXhUZHBPrZllLPIeL2ol JgTQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=nXuWwFea; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id i126sor2555586wmg.5.2019.07.06.03.55.21 for (Google Transport Security); Sat, 06 Jul 2019 03:55:21 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=nXuWwFea; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=GuxALAFQ/TNai2yWaUBZYrBAIJmgHr1PeMz07TcuHEk=; b=nXuWwFeaFB10NA4V6lB4djfCG4L03Q6YVTn+kObhLt+JnC9zkbzXGcCXqxJ+khdjo0 uwJBElmo7sJB/OZhWNONnRz0FNfsGlRBcU13eybEa3in1yWNnQhM2ZVWqPKflMf8G9q8 yJqcXaTPODZ09JeyF2MJJbCLKwcqRKf9n0m5xpF62VdZNkdS7DTRXY1KsNuFyyu6eWg+ lTH/lyd0NHCcCvuVNS69Bl8/tPzx//CMr/uVPkJbMAvW2/fasALxnJQ69pGmUAuxZX9M Iso4mDoYZ17y8anniEhUvdE3SAAb8m0iakYlkfo5QCYApCOkWwUB3c3re0pm1oEW0nq7 Q8Yg== X-Google-Smtp-Source: APXvYqy1+ynai1OSOQkeLSv5Es/MREYsXma7ZlHF4OC5iwOUmuCSj70NPI+2aNwlq+0KMTWYYdT8cw== X-Received: by 2002:a1c:c5c2:: with SMTP id v185mr4017391wmf.161.1562410520881; Sat, 06 Jul 2019 03:55:20 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:20 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 08/12] S.A.R.A.: trampoline emulation Date: Sat, 6 Jul 2019 12:54:49 +0200 Message-Id: <1562410493-8661-9-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Some programs need to generate part of their code at runtime. Luckily enough, in some cases they only generate well-known code sequences (the "trampolines") that can be easily recognized and emulated by the kernel. This way WX Protection can still be active, so a potential attacker won't be able to generate arbitrary sequences of code, but just those that are explicitly allowed. This is not ideal, but it's still better than having WX Protection completely disabled. In particular S.A.R.A. is able to recognize trampolines used by GCC for nested C functions and libffi's trampolines. This feature is implemented only on x86_32 and x86_64. Trampoline emulation is modified from Brad Spengler/PaX Team's code in the last public patch of grsecurity/PaX based on my understanding of the code. Changes or omissions from the original code are mine and don't reflect the original grsecurity/PaX code. Signed-off-by: Salvatore Mesoraca --- arch/x86/Kbuild | 2 + arch/x86/security/Makefile | 2 + arch/x86/security/sara/Makefile | 1 + arch/x86/security/sara/emutramp.c | 57 ++++++++++++ arch/x86/security/sara/trampolines32.h | 137 +++++++++++++++++++++++++++ arch/x86/security/sara/trampolines64.h | 164 +++++++++++++++++++++++++++++++++ security/sara/Kconfig | 18 ++++ security/sara/include/emutramp.h | 35 +++++++ security/sara/wxprot.c | 29 ++++++ 9 files changed, 445 insertions(+) create mode 100644 arch/x86/security/Makefile create mode 100644 arch/x86/security/sara/Makefile create mode 100644 arch/x86/security/sara/emutramp.c create mode 100644 arch/x86/security/sara/trampolines32.h create mode 100644 arch/x86/security/sara/trampolines64.h create mode 100644 security/sara/include/emutramp.h diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild index 30dec01..4fea778 100644 --- a/arch/x86/Kbuild +++ b/arch/x86/Kbuild @@ -25,3 +25,5 @@ obj-y += platform/ obj-y += net/ obj-$(CONFIG_KEXEC_FILE) += purgatory/ + +obj-y += security/ diff --git a/arch/x86/security/Makefile b/arch/x86/security/Makefile new file mode 100644 index 0000000..ba4be4c --- /dev/null +++ b/arch/x86/security/Makefile @@ -0,0 +1,2 @@ +subdir-$(CONFIG_SECURITY_SARA) += sara +obj-$(CONFIG_SECURITY_SARA) += sara/ diff --git a/arch/x86/security/sara/Makefile b/arch/x86/security/sara/Makefile new file mode 100644 index 0000000..a4a76217 --- /dev/null +++ b/arch/x86/security/sara/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP) := emutramp.o diff --git a/arch/x86/security/sara/emutramp.c b/arch/x86/security/sara/emutramp.c new file mode 100644 index 0000000..45122e5 --- /dev/null +++ b/arch/x86/security/sara/emutramp.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * Assembly sequences used here were copied from + * PaX patch by PaX Team + * Being just hexadecimal constants, they are not subject to + * any copyright. + * + */ + +#define PF_PROT (1 << 0) +#define PF_USER (1 << 2) +#define PF_INSTR (1 << 4) + +#ifdef CONFIG_X86_32 + +#include "trampolines32.h" +static inline int trampoline_emulator(struct pt_regs *regs, + unsigned long address) +{ + return sara_trampoline_emulator_x86_32(regs); +} + +#else /* CONFIG_X86_32 */ + +#include "trampolines64.h" +static inline int trampoline_emulator(struct pt_regs *regs, + unsigned long address) +{ + return sara_trampoline_emulator_x86_64(regs, address); +} + +#endif /* CONFIG_X86_32 */ + + +int sara_trampoline_emulator(struct pt_regs *regs, + unsigned long error_code, + unsigned long address) +{ + if (!(error_code & PF_USER) || + !(error_code & PF_INSTR) || + !(error_code & PF_PROT)) + return 0; + + local_irq_enable(); + might_sleep(); + might_fault(); + return trampoline_emulator(regs, address); +} diff --git a/arch/x86/security/sara/trampolines32.h b/arch/x86/security/sara/trampolines32.h new file mode 100644 index 0000000..b3622d0 --- /dev/null +++ b/arch/x86/security/sara/trampolines32.h @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * Assembly sequences used here were copied from + * PaX patch by PaX Team + * Being just hexadecimal constants, they are not subject to + * any copyright. + * + */ + +#ifndef __SARA_TRAMPOLINES32_H +#define __SARA_TRAMPOLINES32_H + +#include +#include + +struct libffi_trampoline_x86_32 { + unsigned char mov; + unsigned int addr1; + unsigned char jmp; + unsigned int addr2; +} __packed; + +struct gcc_trampoline_x86_32_t1 { + unsigned char mov1; + unsigned int addr1; + unsigned char mov2; + unsigned int addr2; + unsigned short jmp; +} __packed; + +struct gcc_trampoline_x86_32_t2 { + unsigned char mov; + unsigned int addr1; + unsigned char jmp; + unsigned int addr2; +} __packed; + +union trampolines_x86_32 { + struct libffi_trampoline_x86_32 lf; + struct gcc_trampoline_x86_32_t1 g1; + struct gcc_trampoline_x86_32_t2 g2; +}; + +static inline int is_libffi_tramp_x86_32(const union trampolines_x86_32 *u) +{ + return (u->lf.mov == 0xB8 && u->lf.jmp == 0xE9); +} + +static inline void emu_libffi_tramp_x86_32(const union trampolines_x86_32 *u, + struct pt_regs *regs) +{ + regs->ax = u->lf.addr1; + regs->ip = (unsigned int) (regs->ip + + u->lf.addr2 + + sizeof(u->lf)); +} + +static inline int is_gcc_tramp_x86_32_t1(const union trampolines_x86_32 *u, + const struct pt_regs *regs) +{ + return (u->g1.mov1 == 0xB9 && + u->g1.mov2 == 0xB8 && + u->g1.jmp == 0xE0FF && + regs->ip > regs->sp); +} + +static inline void emu_gcc_tramp_x86_32_t1(const union trampolines_x86_32 *u, + struct pt_regs *regs) +{ + regs->cx = u->g1.addr1; + regs->ax = u->g1.addr2; + regs->ip = u->g1.addr2; +} + +static inline int is_gcc_tramp_x86_32_t2(const union trampolines_x86_32 *u, + const struct pt_regs *regs) +{ + return (u->g2.mov == 0xB9 && + u->g2.jmp == 0xE9 && + regs->ip > regs->sp); +} + +static inline void emu_gcc_tramp_x86_32_t2(const union trampolines_x86_32 *u, + struct pt_regs *regs) +{ + regs->cx = u->g2.addr1; + regs->ip = (unsigned int) (regs->ip + + u->g2.addr2 + + sizeof(u->g2)); +} + +static inline int sara_trampoline_emulator_x86_32(struct pt_regs *regs) +{ + int ret; + void __user *ip = (void __user *) regs->ip; + union trampolines_x86_32 t; //zero init + + BUILD_BUG_ON(sizeof(t.lf) > sizeof(t.g1)); + BUILD_BUG_ON(sizeof(t.g2) > sizeof(t.lf)); + + ret = copy_from_user(&t, ip, sizeof(t.g1)); + if (ret) + ret = copy_from_user(&t, ip, sizeof(t.lf)); + if (ret) + ret = copy_from_user(&t, ip, sizeof(t.g2)); + if (ret) + return 0; + + if (is_gcc_tramp_x86_32_t1(&t, regs)) { + pr_debug("Trampoline: gcc1 x86_32.\n"); + emu_gcc_tramp_x86_32_t1(&t, regs); + return 1; + } else if (is_libffi_tramp_x86_32(&t)) { + pr_debug("Trampoline: libffi x86_32.\n"); + emu_libffi_tramp_x86_32(&t, regs); + return 1; + } else if (is_gcc_tramp_x86_32_t2(&t, regs)) { + pr_debug("Trampoline: gcc2 x86_32.\n"); + emu_gcc_tramp_x86_32_t2(&t, regs); + return 1; + } + + pr_debug("Not a trampoline (x86_32).\n"); + + return 0; +} + +#endif /* __SARA_TRAMPOLINES32_H */ diff --git a/arch/x86/security/sara/trampolines64.h b/arch/x86/security/sara/trampolines64.h new file mode 100644 index 0000000..c9aaa03 --- /dev/null +++ b/arch/x86/security/sara/trampolines64.h @@ -0,0 +1,164 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * Assembly sequences used here were copied from + * PaX patch by PaX Team + * Being just hexadecimal constants, they are not subject to + * any copyright. + * + */ + +#ifndef __SARA_TRAMPOLINES64_H +#define __SARA_TRAMPOLINES64_H + +#include +#include + +#include "trampolines32.h" + +struct libffi_trampoline_x86_64 { + unsigned short mov1; + unsigned long addr1; + unsigned short mov2; + unsigned long addr2; + unsigned char stcclc; + unsigned short jmp1; + unsigned char jmp2; +} __packed; + +struct gcc_trampoline_x86_64_type1 { + unsigned short mov1; + unsigned long addr1; + unsigned short mov2; + unsigned long addr2; + unsigned short jmp1; + unsigned char jmp2; +} __packed; + +struct gcc_trampoline_x86_64_type2 { + unsigned short mov1; + unsigned int addr1; + unsigned short mov2; + unsigned long addr2; + unsigned short jmp1; + unsigned char jmp2; +} __packed; + +union trampolines_x86_64 { + struct libffi_trampoline_x86_64 lf; + struct gcc_trampoline_x86_64_type1 g1; + struct gcc_trampoline_x86_64_type2 g2; +}; + +static inline int is_libffi_tramp_x86_64(const union trampolines_x86_64 *u) +{ + return (u->lf.mov1 == 0xBB49 && + u->lf.mov2 == 0xBA49 && + (u->lf.stcclc == 0xF8 || + u->lf.stcclc == 0xF9) && + u->lf.jmp1 == 0xFF49 && + u->lf.jmp2 == 0xE3); +} + +static inline void emu_libffi_tramp_x86_64(const union trampolines_x86_64 *u, + struct pt_regs *regs) +{ + regs->r11 = u->lf.addr1; + regs->r10 = u->lf.addr2; + regs->ip = u->lf.addr1; + if (u->lf.stcclc == 0xF8) + regs->flags &= ~X86_EFLAGS_CF; + else + regs->flags |= X86_EFLAGS_CF; +} + +static inline int is_gcc_tramp_x86_64_t1(const union trampolines_x86_64 *u, + const struct pt_regs *regs) +{ + return (u->g1.mov1 == 0xBB49 && + u->g1.mov2 == 0xBA49 && + u->g1.jmp1 == 0xFF49 && + u->g1.jmp2 == 0xE3 && + regs->ip > regs->sp); +} + +static inline void emu_gcc_tramp_x86_64_t1(const union trampolines_x86_64 *u, + struct pt_regs *regs) +{ + regs->r11 = u->g1.addr1; + regs->r10 = u->g1.addr2; + regs->ip = u->g1.addr1; +} + +static inline int is_gcc_tramp_x86_64_t2(const union trampolines_x86_64 *u, + const struct pt_regs *regs) +{ + return (u->g2.mov1 == 0xBB41 && + u->g2.mov2 == 0xBA49 && + u->g2.jmp1 == 0xFF49 && + u->g2.jmp2 == 0xE3 && + regs->ip > regs->sp); +} + +static inline void emu_gcc_tramp_x86_64_t2(const union trampolines_x86_64 *u, + struct pt_regs *regs) +{ + regs->r11 = u->g2.addr1; + regs->r10 = u->g2.addr2; + regs->ip = u->g2.addr1; +} + +static inline int sara_trampoline_emulator_x86_64(struct pt_regs *regs, + unsigned long address) +{ + int ret; + void __user *ip = (void __user *) regs->ip; + union trampolines_x86_64 t; + + BUILD_BUG_ON(sizeof(t.g1) > sizeof(t.lf)); + BUILD_BUG_ON(sizeof(t.g2) > sizeof(t.g1)); + + if (regs->cs == __USER32_CS || + regs->cs & (1<<2)) { + if (address >> 32) /* K8 erratum #100 */ + return 0; + return sara_trampoline_emulator_x86_32(regs); + } + + ret = copy_from_user(&t, ip, sizeof(t.lf)); + if (ret) + ret = copy_from_user(&t, ip, sizeof(t.g1)); + if (ret) + ret = copy_from_user(&t, ip, sizeof(t.g2)); + if (ret) + return 0; + + if (is_libffi_tramp_x86_64(&t)) { + pr_debug("Trampoline: libffi x86_64.\n"); + emu_libffi_tramp_x86_64(&t, regs); + return 1; + } else if (is_gcc_tramp_x86_64_t1(&t, regs)) { + pr_debug("Trampoline: gcc1 x86_64.\n"); + emu_gcc_tramp_x86_64_t1(&t, regs); + return 1; + } else if (is_gcc_tramp_x86_64_t2(&t, regs)) { + pr_debug("Trampoline: gcc2 x86_64.\n"); + emu_gcc_tramp_x86_64_t2(&t, regs); + return 1; + } + + pr_debug("Not a trampoline (x86_64).\n"); + + return 0; + +} + +#endif /* __SARA_TRAMPOLINES64_H */ diff --git a/security/sara/Kconfig b/security/sara/Kconfig index 54a96e0..458e0e8 100644 --- a/security/sara/Kconfig +++ b/security/sara/Kconfig @@ -117,6 +117,24 @@ choice Documentation/admin-guide/LSM/SARA.rst. endchoice +config SECURITY_SARA_WXPROT_EMUTRAMP + bool "Enable emulation for some types of trampolines" + depends on SECURITY_SARA_WXPROT + depends on ARCH_HAS_LSM_PAGEFAULT + depends on X86 + default y + help + Some programs and libraries need to execute special small code + snippets from non-executable memory pages. + Most notable examples are the GCC and libffi trampolines. + This features make it possible to execute those trampolines even + if they reside in non-executable memory pages. + This features need to be enabled on a per-executable basis + via user-space utilities. + See Documentation/admin-guide/LSM/SARA.rst. for further information. + + If unsure, answer y. + config SECURITY_SARA_WXPROT_DISABLED bool "WX protection will be disabled at boot." depends on SECURITY_SARA_WXPROT diff --git a/security/sara/include/emutramp.h b/security/sara/include/emutramp.h new file mode 100644 index 0000000..d82f92d --- /dev/null +++ b/security/sara/include/emutramp.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * S.A.R.A. Linux Security Module + * + * Copyright (C) 2017 Salvatore Mesoraca + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * Assembly sequences used here were copied from + * PaX patch by PaX Team + * Being just hexadecimal constants, they are not subject to + * any copyright. + * + */ + +#ifndef __SARA_EMUTRAMP_H +#define __SARA_EMUTRAMP_H + +#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP +int sara_trampoline_emulator(struct pt_regs *regs, + unsigned long error_code, + unsigned long address); +#else +inline int sara_trampoline_emulator(struct pt_regs *regs, + unsigned long error_code, + unsigned long address) +{ + return 0; +} +#endif /* CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP */ + +#endif /* __SARA_EMUTRAMP_H */ diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c index 8a3d002..9c42bfc 100644 --- a/security/sara/wxprot.c +++ b/security/sara/wxprot.c @@ -31,6 +31,7 @@ #include "include/utils.h" #include "include/securityfs.h" #include "include/wxprot.h" +#include "include/emutramp.h" #define SARA_WXPROT_CONFIG_VERSION 0 @@ -41,6 +42,7 @@ #define SARA_WXP_COMPLAIN 0x0010 #define SARA_WXP_VERBOSE 0x0020 #define SARA_WXP_MMAP 0x0040 +#define SARA_WXP_EMUTRAMP 0x0100 #define SARA_WXP_TRANSFER 0x0200 #define SARA_WXP_NONE 0x0000 #define SARA_WXP_MPROTECT (SARA_WXP_HEAP | \ @@ -51,7 +53,12 @@ SARA_WXP_WXORX | \ SARA_WXP_COMPLAIN | \ SARA_WXP_VERBOSE) +#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP +#define SARA_WXP_ALL (__SARA_WXP_ALL | \ + SARA_WXP_EMUTRAMP) +#else /* CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP */ #define SARA_WXP_ALL __SARA_WXP_ALL +#endif /* CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP */ struct wxprot_config_container { struct sara_dfa_tables *dfa; @@ -67,7 +74,11 @@ struct wxprot_config_container { static u16 default_flags __lsm_ro_after_init = CONFIG_SECURITY_SARA_WXPROT_DEFAULT_FLAGS; +#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP +static const bool wxprot_emutramp = true; +#else static const bool wxprot_emutramp; +#endif static void pr_wxp(char *msg) { @@ -110,6 +121,9 @@ static bool are_flags_valid(u16 flags) if (unlikely(flags & SARA_WXP_MMAP && !(flags & SARA_WXP_OTHER))) return false; + if (unlikely(flags & SARA_WXP_EMUTRAMP && + ((flags & SARA_WXP_MPROTECT) != SARA_WXP_MPROTECT))) + return false; return true; } @@ -514,11 +528,26 @@ static int sara_file_mprotect(struct vm_area_struct *vma, return 0; } +#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP +static int sara_pagefault_handler(struct pt_regs *regs, + unsigned long error_code, + unsigned long address) +{ + if (!sara_enabled || !wxprot_enabled || + likely(!(get_current_sara_wxp_flags() & SARA_WXP_EMUTRAMP))) + return 0; + return sara_trampoline_emulator(regs, error_code, address); +} +#endif + static struct security_hook_list wxprot_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bprm_set_creds, sara_bprm_set_creds), LSM_HOOK_INIT(check_vmflags, sara_check_vmflags), LSM_HOOK_INIT(shm_shmat, sara_shm_shmat), LSM_HOOK_INIT(file_mprotect, sara_file_mprotect), +#ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP + LSM_HOOK_INIT(pagefault_handler, sara_pagefault_handler), +#endif }; static void config_free(struct wxprot_config_container *data) From patchwork Sat Jul 6 10:54:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033601 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 61DD213BD for ; Sat, 6 Jul 2019 10:55:34 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 519AE2881B for ; Sat, 6 Jul 2019 10:55:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 452C7289D2; Sat, 6 Jul 2019 10:55:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,GAPPY_SUBJECT,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=unavailable version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 90C9B2881B for ; Sat, 6 Jul 2019 10:55:33 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 63FA98E0007; Sat, 6 Jul 2019 06:55:24 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 547F88E0006; Sat, 6 Jul 2019 06:55:24 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 2B6C38E0007; Sat, 6 Jul 2019 06:55:24 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by kanga.kvack.org (Postfix) with ESMTP id C5EDB8E0001 for ; Sat, 6 Jul 2019 06:55:23 -0400 (EDT) Received: by mail-wr1-f69.google.com with SMTP id p13so4997359wru.17 for ; Sat, 06 Jul 2019 03:55:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=2o5CRslS3uRS8RVi/y7cIRyfxfb3HvwyRL/v1ZeEIno=; b=OBiuZ3YYChFfHf3S4Jc3QutQp05vBGsXifPRxsytJuRp5lBjH06qSJxv8seemRTtgh pAEWDcgLs2ZdUvjkicac5U4KEgMEfLGlpSfseNmGdZ2WlTgUw4JNazJfP2bGbGZ+59DF jLqCUW8hHIxn8FhiX/p8CgUvEj5ZWdPW40xWVbsRPIhR8u4H6eBkN20S1Pyetto0ImtD QsF891JhE2ZqdJ+Pu/rtuQJIyvoLRTyktrYI4qlxw6xTy+he5xECL8zge1zix6F+OMv9 ZaPyfO39/cEhLZameP1hJUD6iRCpMD/B0ar3IXiH5KpcLUMAP+FJAaCokYvyKCJyvwWP lwew== X-Gm-Message-State: APjAAAV1eIHmy+tkeVmcw9UxzQZXyXW58FiYoGfeFhrFGaXQfrpE+WID KV45Hy2LtibYGGO19PrkUVvVWzZZ4UZ3CJskovHEKLTX6gxfP+KikW+YZDypH4JSfxza7I5PxGh EjjMpvh8Lqr4wBk+zwsKBA0TR1KHemYa3wj8IvfbzkxlRrs3m6mLEcTFxO2L641B/Og== X-Received: by 2002:a1c:acc8:: with SMTP id v191mr7973369wme.177.1562410523348; Sat, 06 Jul 2019 03:55:23 -0700 (PDT) X-Received: by 2002:a1c:acc8:: with SMTP id v191mr7973283wme.177.1562410522214; Sat, 06 Jul 2019 03:55:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410522; cv=none; d=google.com; s=arc-20160816; b=ziIjLmQPqjKRLDZCsQUAaGxcdL1IZGTwE211tYPO9VZwXUiPUiXv40DLvNhQucaKbG 1eAt05GAI+iGUB4knsrKL8iZv29Hm0uAH4JGL83cddWaCNVUzfgcNtw8HSE7NBJlbI6r iJmGoXryLYYiR7J7AtTfIT5o6Q3H6W/Gp28GTPbsk+2q0AJKpZdvhU7rXp2tfInNqzUk cmT+9gVWajU6sUsoCyCbnsSnSSties01DST4dMIbj4jzZ5eiowRYWTCjJAZi+wnUXhSU xitScO0L3TguzKHsLIeB77OQ+b0rlI7F2jXnPVh+cO6rW9a1SoxGWew/yjWryaDoR5JJ xu2w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=2o5CRslS3uRS8RVi/y7cIRyfxfb3HvwyRL/v1ZeEIno=; b=YEP9LXXKc+DK6ovSFEl/UtzD4c+HVC9uuY/GnPc1eAeVzFJvg2DgolREEQVH5bAzXx ULHl5+yeMDT/yOiFg8J3VAkZlutRgyKGXdKPLcIUf4JbsmgADV43jwpBEV107+o4xNtg 2PluECoiHiwwjrIEtnRyu/pG5V4qJ1NiieTC/y6IHtE1CZUxQpf1X54KT+dVssTiH+pG BWi40LWcqQhWOqwUCqg6AIL6RGu9LOlkj1aQbd/Wip5chdnrE2BjfYjCHHa/zNvBJ5FL XIEiW+plKvh+9NvYvE8Lzk9tMgE4Aqtt/XGizT+M54EvAp27D9C3YFv/naceSUcPg7cj 0Pdw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=rPg5B9Tq; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id s6sor8655218wrv.2.2019.07.06.03.55.22 for (Google Transport Security); Sat, 06 Jul 2019 03:55:22 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=rPg5B9Tq; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=2o5CRslS3uRS8RVi/y7cIRyfxfb3HvwyRL/v1ZeEIno=; b=rPg5B9TqS7krvMJJliXmsCRezH5NtE0qwL7MshANq/BMIQk+fLCGGDvdN0TqTFS/Hg 6+JesQatpm70HrH1/sKDHhJW5NuJ9lbPo/Pt3diMYQHeYiUTvped3PnPQZHI+4YJ0jN8 9/g0eLOYr5OMGYidjZj/2dAXPCxNHpShNsdocDH/i6xFouRHR8c8cHVZsIJgLYUcb0DD FQpwJKoiJ419jrwGoHRUHCLQTGHHWLdYLwHvsLFGedgjUlQUYEHsbPU+I9QqdvMXnfZ9 v9/8/wdff2V5mB4KBlxcXIQv7e6lcDopq/KTB5+TyDiIp+3dMLe+RN3aV4nQOiuYU/ye mN5g== X-Google-Smtp-Source: APXvYqztD1m1u9aJTdBW5y6FhM7gZEDkT1ZI7+xUeEaha6acs1qD6E71wBnezSnp1EbFzIl12Fdq9g== X-Received: by 2002:a5d:42c5:: with SMTP id t5mr8328348wrr.5.1562410521889; Sat, 06 Jul 2019 03:55:21 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:21 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 09/12] S.A.R.A.: WX protection procattr interface Date: Sat, 6 Jul 2019 12:54:50 +0200 Message-Id: <1562410493-8661-10-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP This allow threads to get current WX Protection flags for themselves or for other threads (if they have CAP_MAC_ADMIN). It also allow a thread to set itself flags to a stricter set of rules than the current one. Via a new wxprot flag (SARA_WXP_FORCE_WXORX) is it possible to ask the kernel to rescan the memory and remove the VM_WRITE flag from any area that is marked both writable and executable. Protections that prevent the runtime creation of executable code can be troublesome for all those programs that actually need to do it e.g. programs shipping with a JIT compiler built-in. This feature can be use to run the JIT compiler with few restrictions while enforcing full WX Protection in the rest of the program. To simplify access to this interface a CC0 licensed library is available here: https://github.com/smeso/libsara Signed-off-by: Salvatore Mesoraca --- fs/proc/base.c | 11 ++++ security/sara/wxprot.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index 255f675..7873d27 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2612,6 +2612,13 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, LSM_DIR_OPS(smack); #endif +#ifdef CONFIG_SECURITY_SARA +static const struct pid_entry sara_attr_dir_stuff[] = { + ATTR("sara", "wxprot", 0666), +}; +LSM_DIR_OPS(sara); +#endif + static const struct pid_entry attr_dir_stuff[] = { ATTR(NULL, "current", 0666), ATTR(NULL, "prev", 0444), @@ -2623,6 +2630,10 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, DIR("smack", 0555, proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops), #endif +#ifdef CONFIG_SECURITY_SARA + DIR("sara", 0555, + proc_sara_attr_dir_inode_ops, proc_sara_attr_dir_ops), +#endif }; static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c index 9c42bfc..84f7b1e 100644 --- a/security/sara/wxprot.c +++ b/security/sara/wxprot.c @@ -14,6 +14,7 @@ #ifdef CONFIG_SECURITY_SARA_WXPROT #include +#include #include #include #include @@ -42,6 +43,7 @@ #define SARA_WXP_COMPLAIN 0x0010 #define SARA_WXP_VERBOSE 0x0020 #define SARA_WXP_MMAP 0x0040 +#define SARA_WXP_FORCE_WXORX 0x0080 #define SARA_WXP_EMUTRAMP 0x0100 #define SARA_WXP_TRANSFER 0x0200 #define SARA_WXP_NONE 0x0000 @@ -540,6 +542,152 @@ static int sara_pagefault_handler(struct pt_regs *regs, } #endif +static int sara_getprocattr(struct task_struct *p, char *name, char **value) +{ + int ret; + u16 flags; + char *buf; + + ret = -EINVAL; + if (strcmp(name, "wxprot") != 0) + goto out; + + ret = -EACCES; + if (unlikely(current != p && + !capable(CAP_MAC_ADMIN))) + goto out; + + ret = -ENOMEM; + buf = kzalloc(8, GFP_KERNEL); + if (unlikely(buf == NULL)) + goto out; + + if (!sara_enabled || !wxprot_enabled) { + flags = 0x0; + } else { + rcu_read_lock(); + flags = get_sara_wxp_flags(__task_cred(p)); + rcu_read_unlock(); + } + + snprintf(buf, 8, "0x%04x\n", flags); + ret = strlen(buf); + *value = buf; + +out: + return ret; +} + +static int sara_setprocattr(const char *name, void *value, size_t size) +{ + int ret; + struct vm_area_struct *vma; + struct cred *new = prepare_creds(); + u16 cur_flags; + u16 req_flags; + char *buf = NULL; + + ret = -EINVAL; + if (!sara_enabled || !wxprot_enabled) + goto error; + if (unlikely(new == NULL)) + return -ENOMEM; + if (strcmp(name, "wxprot") != 0) + goto error; + if (unlikely(value == NULL || size == 0 || size > 7)) + goto error; + ret = -ENOMEM; + buf = kmalloc(size+1, GFP_KERNEL); + if (unlikely(buf == NULL)) + goto error; + buf[size] = '\0'; + memcpy(buf, value, size); + ret = -EINVAL; + if (unlikely(strlen(buf) != size)) + goto error; + if (unlikely(kstrtou16(buf, 0, &req_flags) != 0)) + goto error; + /* + * SARA_WXP_FORCE_WXORX is a procattr only flag with a special + * meaning and it isn't recognized by are_flags_valid + */ + if (unlikely(!are_flags_valid(req_flags & ~SARA_WXP_FORCE_WXORX))) + goto error; + /* + * Extra checks on requested flags: + * - SARA_WXP_FORCE_WXORX requires SARA_WXP_WXORX + * - SARA_WXP_MMAP can only be activated if the program + * has a relro section + * - COMPLAIN mode can only be requested if it was already + * on (procattr can only be used to make protection stricter) + * - EMUTRAMP can only be activated if it was already on or + * if MPROTECT and WXORX weren't already on (procattr can + * only be used to make protection stricter) + * - VERBOSITY request is ignored + */ + if (unlikely(req_flags & SARA_WXP_FORCE_WXORX && + !(req_flags & SARA_WXP_WXORX))) + goto error; + if (unlikely(!get_current_sara_relro_page_found() && + req_flags & SARA_WXP_MMAP)) + goto error; + cur_flags = get_current_sara_wxp_flags(); + if (unlikely((req_flags & SARA_WXP_COMPLAIN) && + !(cur_flags & SARA_WXP_COMPLAIN))) + goto error; + if (unlikely((req_flags & SARA_WXP_EMUTRAMP) && + !(cur_flags & SARA_WXP_EMUTRAMP) && + (cur_flags & (SARA_WXP_MPROTECT | + SARA_WXP_WXORX)))) + goto error; + if (cur_flags & SARA_WXP_VERBOSE) + req_flags |= SARA_WXP_VERBOSE; + else + req_flags &= ~SARA_WXP_VERBOSE; + /* + * Except SARA_WXP_COMPLAIN and SARA_WXP_EMUTRAMP, + * any other flag can't be removed (procattr can + * only be used to make protection stricter). + */ + if (unlikely(cur_flags & (req_flags ^ cur_flags) & + ~(SARA_WXP_COMPLAIN|SARA_WXP_EMUTRAMP))) + goto error; + ret = -EINTR; + /* + * When SARA_WXP_FORCE_WXORX is on we traverse all the + * memory and remove the write permission from any area + * that is both writable and executable. + */ + if (req_flags & SARA_WXP_FORCE_WXORX) { + if (down_write_killable(¤t->mm->mmap_sem)) + goto error; + for (vma = current->mm->mmap; vma; vma = vma->vm_next) { + if (vma->vm_flags & VM_EXEC && + vma->vm_flags & VM_WRITE) { + vma->vm_flags &= ~VM_WRITE; + vma_set_page_prot(vma); + change_protection(vma, + vma->vm_start, + vma->vm_end, + vma->vm_page_prot, + 0, + 0); + } + } + up_write(¤t->mm->mmap_sem); + } + get_sara_wxp_flags(new) = req_flags & ~SARA_WXP_FORCE_WXORX; + commit_creds(new); + ret = size; + goto out; + +error: + abort_creds(new); +out: + kfree(buf); + return ret; +} + static struct security_hook_list wxprot_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bprm_set_creds, sara_bprm_set_creds), LSM_HOOK_INIT(check_vmflags, sara_check_vmflags), @@ -548,6 +696,8 @@ static int sara_pagefault_handler(struct pt_regs *regs, #ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP LSM_HOOK_INIT(pagefault_handler, sara_pagefault_handler), #endif + LSM_HOOK_INIT(getprocattr, sara_getprocattr), + LSM_HOOK_INIT(setprocattr, sara_setprocattr), }; static void config_free(struct wxprot_config_container *data) From patchwork Sat Jul 6 10:54:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033607 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4675614F6 for ; Sat, 6 Jul 2019 10:55:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 357AB2881B for ; Sat, 6 Jul 2019 10:55:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 28FA5289D2; Sat, 6 Jul 2019 10:55:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,GAPPY_SUBJECT,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4B5992881B for ; Sat, 6 Jul 2019 10:55:39 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 5E6C98E0008; Sat, 6 Jul 2019 06:55:26 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 5710E8E0006; Sat, 6 Jul 2019 06:55:26 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3EF038E0008; Sat, 6 Jul 2019 06:55:26 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by kanga.kvack.org (Postfix) with ESMTP id D27828E0006 for ; Sat, 6 Jul 2019 06:55:25 -0400 (EDT) Received: by mail-wr1-f70.google.com with SMTP id i6so5006273wre.1 for ; Sat, 06 Jul 2019 03:55:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=yTf2cEJ/R1sIWwnnsJBizfOJ+ZTQkKILtxUL3GoVlWE=; b=aeQLOLZTxmlH7UjeMQ76maTA9fY35/PbF3psy+yQFiDc6qmYB+cN7hKHsH8HRy8WjS 1gGd5pZfsTg1lhGOapDOw+ia2VBWgBnxWdF0KqAc48RfS1w4aCiZQMfn4oI8pVXjP/SD gqX6M/x831Z3H19/6DyFCK3aMgOxszmKKkQ8hgbNZoWe/82ZL7FwOWN2RtwA+lvx/t7G cS6WN804+y+iO4c6w4wwY1RW8cCKD6Nr9rYzJPm9CgbsYvrnDyDibDCAyFvP1MK7LwJk jE5Kr+x3Mdx0be2VZZKShpWZve1YtzeaEbfKArsWvOMm725TSj4h/YJLdDz2VT4+P3yR vd+Q== X-Gm-Message-State: APjAAAU1lJ9FsS39TvOU/5g5iMnBU7vLHaI3zVHlLL1euQorhJ07l2Ed 5BnnE/KG4bU80FUOT1QgZYd4zjs5slYg5T/uoH6JFF1fHTqkdx9+VaCGuK44PvAzOoUTTQvoauc 5PviLf4vFJKjWvCQWLd5mnzypi0O35U8IFqA8g81K3Tc8brj1XymYDVrfwle490qCTA== X-Received: by 2002:adf:f686:: with SMTP id v6mr8413231wrp.238.1562410525394; Sat, 06 Jul 2019 03:55:25 -0700 (PDT) X-Received: by 2002:adf:f686:: with SMTP id v6mr8413097wrp.238.1562410523678; Sat, 06 Jul 2019 03:55:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410523; cv=none; d=google.com; s=arc-20160816; b=YdUVy/tJaG7JIorhN3Y1QLyLBi97C/MEojzYwSw3dvU+QVZto+IQw+8RCb8ayZ2GmE b2HJTrGXGGc5QCM8Togjnws6XS4yHbIa0lI9uky7Qupg3lf64585GQeB2VwPMTGE4hTz NCRvJ4A2z2F8IXXoAXA6TABGokVWh4c5LLKGdfVQ20lKFOdXlvOPXK/MfVAv63WG/YrH QnwNJRxgXcbHWQyzVyUCVfUxTybd78Udg0mNFmCIliYhp6x7S2A248tY+MQIFD1f/pf7 0ac7bE6rcegDYMsnBciwNJQRemayayTSzDAuQi66g4oTo+K2nSJCitU4w9P2lWq03jfa NcLQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=yTf2cEJ/R1sIWwnnsJBizfOJ+ZTQkKILtxUL3GoVlWE=; b=SPcejN0r7xIgnJjp0Qo5+Dwm9zX3UoO6+vVHREapnKg4e3xb/D7EixIIWnTDc3RPYB 53/Gm+h01uFKEpEUu5/aCs+fFIoTr9RYrQ1MZqjR/MZXzWfJEJ+rUTfRu04yUb93XmTZ skvZGcet+l9otIvjXrDjN8dppQmNAGAcgx5GJA6ZxJS5JG/3c/+f2q4VE5uNInOUtOeh LABtnq+MdZZTZTnhyRkUsUpdOo1WeYZC5FH36pFEpp2DSVIcr19XqCMwWZpQ9tPjgDPX 2ua5qyH7XpiaVg6D1MjY2gUKwI0xq99oBJFIgARFb/g2L7PnzARG/PIdKrfQ7Q6xytRs YgqA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=ZLNuz0c2; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id e9sor8656893wrx.37.2019.07.06.03.55.23 for (Google Transport Security); Sat, 06 Jul 2019 03:55:23 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=ZLNuz0c2; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=yTf2cEJ/R1sIWwnnsJBizfOJ+ZTQkKILtxUL3GoVlWE=; b=ZLNuz0c29GG+6CNJGcOAjeOlpRMP9h7O99Pi/gakDKFGU3lhhHikq8a99CInc2k/XO x6Aq3KQ16oEDc3jolc38IPHfVlXaurELUSiUDHn05p6lfOFDkkvsNRWEIR/u9OIqM0Iv HtbBQ2B/Kq1vvvG4gn4LbVxWfdc/sXmvb7bh25PrgcUiOFGqI5qzgRkWR5JJ3qB8it29 nt6KXK7N3DC9FtosDIw8Yw2FSs9KbQjD6zMPBftq1aXOG2YvtlhuzxNjQd3NYN3DSsHP AO1doaXc1DmHasyn5SSmlIyHvB5/T78+l9uWIWn6bgSiY0WNtJcA4pqYF4yEJgMx128n jwQQ== X-Google-Smtp-Source: APXvYqy4CMl5RxszjxSvrEAMWtejw7CVXkEcAJC69QuAF9VdqwZsgSkOM4PQR4vCXHHgIdQEtRBcQw== X-Received: by 2002:adf:e483:: with SMTP id i3mr7749477wrm.210.1562410523298; Sat, 06 Jul 2019 03:55:23 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:22 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 10/12] S.A.R.A.: XATTRs support Date: Sat, 6 Jul 2019 12:54:51 +0200 Message-Id: <1562410493-8661-11-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Adds support for extended filesystem attributes in security and user namespaces. They can be used to override flags set via the centralized configuration, even when S.A.R.A. configuration is locked or saractl is not used at all. Signed-off-by: Salvatore Mesoraca --- Documentation/admin-guide/LSM/SARA.rst | 20 +++++ Documentation/admin-guide/kernel-parameters.txt | 16 ++++ include/uapi/linux/xattr.h | 4 + security/sara/Kconfig | 22 ++++++ security/sara/wxprot.c | 99 +++++++++++++++++++++++++ 5 files changed, 161 insertions(+) diff --git a/Documentation/admin-guide/LSM/SARA.rst b/Documentation/admin-guide/LSM/SARA.rst index fdde04c..47d9364 100644 --- a/Documentation/admin-guide/LSM/SARA.rst +++ b/Documentation/admin-guide/LSM/SARA.rst @@ -55,6 +55,8 @@ WX Protection. In particular: To extend the scope of the above features, despite the issues that they may cause, they are complemented by **/proc/PID/attr/sara/wxprot** interface and **trampoline emulation**. +It's also possible to override the centralized configuration via `Extended +filesystem attributes`_. At the moment, WX Protection (unless specified otherwise) should work on any architecture supporting the NX bit, including, but not limited to: @@ -123,6 +125,24 @@ in your project or copy/paste parts of it. To make things simpler `libsara` is the only part of S.A.R.A. released under *CC0 - No Rights Reserved* license. +Extended filesystem attributes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +When this functionality is enabled, it's possible to override +WX Protection flags set in the main configuration via extended attributes, +even when S.A.R.A.'s configuration is in "locked" mode. +If the user namespace is also enabled, its attributes will override settings +configured via the security namespace. +The xattrs currently in use are: + +- security.sara.wxprot +- user.sara.wxprot + +They can be manually set to the desired value as a decimal, hexadecimal or +octal number. When this functionality is enabled, S.A.R.A. can be easily used +without the help of its userspace tools. Though the preferred way to change +these attributes is `sara-xattr` which is part of `saractl` [2]_. + + Trampoline emulation ^^^^^^^^^^^^^^^^^^^^ Some programs need to generate part of their code at runtime. Luckily enough, diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 3d6e86d..af40f1b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4254,6 +4254,22 @@ See S.A.R.A. documentation. Default value is set via kernel config option. + sara.wxprot_xattrs_enabled= [SARA] + Enable support for security xattrs. + Format: { "0" | "1" } + See security/sara/Kconfig help text + 0 -- disable. + 1 -- enable. + Default value is set via kernel config option. + + sara.wxprot_xattrs_user= [SARA] + Enable support for user xattrs. + Format: { "0" | "1" } + See security/sara/Kconfig help text + 0 -- disable. + 1 -- enable. + Default value is set via kernel config option. + serialnumber [BUGS=X86-32] shapers= [NET] diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h index c1395b5..45c0333 100644 --- a/include/uapi/linux/xattr.h +++ b/include/uapi/linux/xattr.h @@ -77,5 +77,9 @@ #define XATTR_POSIX_ACL_DEFAULT "posix_acl_default" #define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT +#define XATTR_SARA_SUFFIX "sara." +#define XATTR_SARA_WXP_SUFFIX XATTR_SARA_SUFFIX "wxp" +#define XATTR_NAME_SEC_SARA_WXP XATTR_SECURITY_PREFIX XATTR_SARA_WXP_SUFFIX +#define XATTR_NAME_USR_SARA_WXP XATTR_USER_PREFIX XATTR_SARA_WXP_SUFFIX #endif /* _UAPI_LINUX_XATTR_H */ diff --git a/security/sara/Kconfig b/security/sara/Kconfig index 458e0e8..773256b 100644 --- a/security/sara/Kconfig +++ b/security/sara/Kconfig @@ -135,6 +135,28 @@ config SECURITY_SARA_WXPROT_EMUTRAMP If unsure, answer y. +config SECURITY_SARA_WXPROT_XATTRS_ENABLED + bool "xattrs support enabled by default." + depends on SECURITY_SARA_WXPROT + default n + help + If you say Y here it will be possible to override WX protection + configuration via extended attributes in the security namespace. + Even when S.A.R.A.'s configuration has been locked. + + If unsure, answer N. + +config CONFIG_SECURITY_SARA_WXPROT_XATTRS_USER + bool "'user' namespace xattrs support enabled by default." + depends on SECURITY_SARA_WXPROT_XATTRS_ENABLED + default n + help + If you say Y here it will be possible to override WX protection + configuration via extended attributes in the user namespace. + Even when S.A.R.A.'s configuration has been locked. + + If unsure, answer N. + config SECURITY_SARA_WXPROT_DISABLED bool "WX protection will be disabled at boot." depends on SECURITY_SARA_WXPROT diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c index 84f7b1e..773d1fd 100644 --- a/security/sara/wxprot.c +++ b/security/sara/wxprot.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "include/dfa.h" #include "include/sara.h" @@ -82,6 +83,18 @@ struct wxprot_config_container { static const bool wxprot_emutramp; #endif +#ifdef CONFIG_SECURITY_SARA_WXPROT_XATTRS_ENABLED +static int wxprot_xattrs_enabled __read_mostly = true; +#else +static int wxprot_xattrs_enabled __read_mostly; +#endif + +#ifdef CONFIG_SECURITY_SARA_WXPROT_XATTRS_USER +static int wxprot_xattrs_user __read_mostly = true; +#else +static int wxprot_xattrs_user __read_mostly; +#endif + static void pr_wxp(char *msg) { char *buf, *path; @@ -133,6 +146,14 @@ static bool are_flags_valid(u16 flags) MODULE_PARM_DESC(wxprot_enabled, "Disable or enable S.A.R.A. WX Protection at boot time."); +module_param(wxprot_xattrs_enabled, int, 0); +MODULE_PARM_DESC(wxprot_xattrs_enabled, + "Disable or enable S.A.R.A. WXP extended attributes interfaces."); + +module_param(wxprot_xattrs_user, int, 0); +MODULE_PARM_DESC(wxprot_xattrs_user, + "Allow normal users to override S.A.R.A. WXP settings via extended attributes."); + static int param_set_wxpflags(const char *val, const struct kernel_param *kp) { u16 flags; @@ -236,6 +257,65 @@ static inline int is_relro_page(const struct vm_area_struct *vma) } /* + * Extended attributes handling + */ +static int sara_wxprot_xattrs_name(struct dentry *d, + const char *name, + u16 *flags) +{ + int rc; + char buffer[10]; + u16 tmp; + + if (!(d->d_inode->i_opflags & IOP_XATTR)) + return -EOPNOTSUPP; + + rc = __vfs_getxattr(d, d->d_inode, name, buffer, sizeof(buffer) - 1); + if (rc > 0) { + buffer[rc] = '\0'; + rc = kstrtou16(buffer, 0, &tmp); + if (rc) + return rc; + if (!are_flags_valid(tmp)) + return -EINVAL; + *flags = tmp; + return 0; + } else if (rc < 0) + return rc; + + return -ENODATA; +} + +#define sara_xattrs_may_return(RC, XATTRNAME, FNAME) do { \ + if (RC == -EINVAL || RC == -ERANGE) \ + pr_info_ratelimited( \ + "WXP: malformed xattr '%s' on '%s'\n", \ + XATTRNAME, \ + FNAME); \ + else if (RC == 0) \ + return 0; \ +} while (0) + +static inline int sara_wxprot_xattrs(struct dentry *d, + u16 *flags) +{ + int rc; + + if (!wxprot_xattrs_enabled) + return 1; + if (wxprot_xattrs_user) { + rc = sara_wxprot_xattrs_name(d, XATTR_NAME_USR_SARA_WXP, + flags); + sara_xattrs_may_return(rc, XATTR_NAME_USR_SARA_WXP, + d->d_name.name); + } + rc = sara_wxprot_xattrs_name(d, XATTR_NAME_SEC_SARA_WXP, flags); + sara_xattrs_may_return(rc, XATTR_NAME_SEC_SARA_WXP, d->d_name.name); + return 1; +} + + +/* * LSM hooks */ static int sara_bprm_set_creds(struct linux_binprm *bprm) @@ -259,6 +339,10 @@ static int sara_bprm_set_creds(struct linux_binprm *bprm) if (!sara_enabled || !wxprot_enabled) return 0; + if (sara_wxprot_xattrs(bprm->file->f_path.dentry, + &sara_wxp_flags) == 0) + goto flags_set; + /* * SARA_WXP_TRANSFER means that the parent * wants this child to inherit its flags. @@ -283,6 +367,7 @@ static int sara_bprm_set_creds(struct linux_binprm *bprm) } else path = (char *) bprm->interp; +flags_set: if (sara_wxp_flags != default_flags && sara_wxp_flags & SARA_WXP_VERBOSE) pr_debug_ratelimited("WXP: '%s' run with flags '0x%x'.\n", @@ -777,6 +862,10 @@ static int config_hash(char **buf) static DEFINE_SARA_SECFS_BOOL_FLAG(wxprot_enabled_data, wxprot_enabled); +static DEFINE_SARA_SECFS_BOOL_FLAG(wxprot_xattrs_enabled_data, + wxprot_xattrs_enabled); +static DEFINE_SARA_SECFS_BOOL_FLAG(wxprot_xattrs_user_data, + wxprot_xattrs_user); static struct sara_secfs_fptrs fptrs __lsm_ro_after_init = { .load = config_load, @@ -820,6 +909,16 @@ static DEFINE_SARA_SECFS_BOOL_FLAG(wxprot_enabled_data, .type = SARA_SECFS_CONFIG_HASH, .data = &fptrs, }, + { + .name = "xattr_enabled", + .type = SARA_SECFS_BOOL, + .data = (void *) &wxprot_xattrs_enabled_data, + }, + { + .name = "xattr_user_allowed", + .type = SARA_SECFS_BOOL, + .data = (void *) &wxprot_xattrs_user_data, + }, }; From patchwork Sat Jul 6 10:54:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033611 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0236814F6 for ; Sat, 6 Jul 2019 10:55:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E770F2881B for ; Sat, 6 Jul 2019 10:55:42 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DB273289D2; Sat, 6 Jul 2019 10:55:42 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,GAPPY_SUBJECT,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=unavailable version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5D90C28994 for ; Sat, 6 Jul 2019 10:55:42 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 12CF28E0009; Sat, 6 Jul 2019 06:55:27 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 0B6A88E0006; Sat, 6 Jul 2019 06:55:26 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id DD3C08E0009; Sat, 6 Jul 2019 06:55:26 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by kanga.kvack.org (Postfix) with ESMTP id 928B98E0006 for ; Sat, 6 Jul 2019 06:55:26 -0400 (EDT) Received: by mail-wr1-f70.google.com with SMTP id v7so5018543wrt.6 for ; Sat, 06 Jul 2019 03:55:26 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=u2RjwdUFNE3OIK/3bCmlFikIsAzp11hkr0vwILrcAOk=; b=gAY05uIpzZGZZgiyEf+ykyDCyIqAUo2czs325YrStu6APeW7JzIY259QAhzPLMuuhr MQvtiQVOz3uru+9LIG8P9/kl8OLVtEPibPze10lLtYwwggt4u78sX5Qi46kzhYNYTFHE 317YKRvqExE3hpg935ZLl8IxTFWPTAiT/5xlqrUYNMuTsVNGDhZ4d4Hr7R46HDSWn3pj I2A0cSQe+w7EF9SCpsgdHyvx7TXgDyECuBhD60QHM3zuKr4tcLm6D3+kK+loR+JmyBn6 JvVfQGD91lKR8J8PmbTtaliUpU5O7VRxrVQD8ZlXnw+CF6Ig2cBIfwHaRkWDu1oFhDv8 a6kg== X-Gm-Message-State: APjAAAUKEfHNkwHWzGogGeuUXJ7/bYU+VvkiY9q8vjAC5PpXRnkOhIKj jWkXzCZ1fKP1fjUujehebFOZSU+xZuUcRq+tFuQtsSNgxwPaqbSTY6CLLyMig8hxhnltsoSZuS5 9R8fBoc2fEK95PdtLEpr5/ne96voGyQoYmaQYrWYnt/NczjJIaUZV74VUo0uhGBXhKA== X-Received: by 2002:adf:e941:: with SMTP id m1mr8891630wrn.279.1562410526181; Sat, 06 Jul 2019 03:55:26 -0700 (PDT) X-Received: by 2002:adf:e941:: with SMTP id m1mr8891517wrn.279.1562410524783; Sat, 06 Jul 2019 03:55:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410524; cv=none; d=google.com; s=arc-20160816; b=V6od/aS5QadXzwXCTzTbiiRn8mbIvQb7J26b24F26Vn0uuGHYBoa2thXNamvbYJjLJ Ngh+LheUrnd9S+WnM3IjCKre0AVerAJxyZPtnnszR2LJ9hiwfcsF7JmThcqYsul4dfnY SAdV0pHOAMcFWbxGDSv+kKOq34OMi9MV+OZjFrIYeN8L2WAETdAcGthPGqu6w0GcPpYf LeD6eY3BelDPlkDyTC3yOuQKr289vwI0kUje52PHwAGNbdZ3uTTONzvB0oCI2XcPU/+S 8px9Rb6CEIxfFnPl6Eb7aM6j6JQd6QjniXnxWy1y/2F0+3Nxugry94cPKkNbwSZXRJJv oAlw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=u2RjwdUFNE3OIK/3bCmlFikIsAzp11hkr0vwILrcAOk=; b=KAwpwUISUwYf+m3MIxGJreFb/w3ImG0Kj2AlT4aFA/JSaHez+M4vcpArua/QTH3qgI wABI/NTzUl3pF7f6VkV0pmUTYvFx+Yf4ESFebOYt6uwuFzo7jXx/MVfheAtKMF+s5PUn oEsGN0k8i2s5Kv7bO1LkS8y0j9TGNpqz9tz7ZMpBlQfEYg769ZHWphgTyyUnEaTlFM2X NUqyilUAF2JH69D54O05ssxK3pNi1LMOjLy7X0EH6kJIOg0gAqA3tnnAagXGF1vbzXuw tYEuDnyWt4gK18GYly66jNLamXOKCmq2DW/K5a44hbRM/8osAP0azAMytbxCf8w5Q2U9 fbrA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=thNRn6TJ; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id i126sor2555623wmg.5.2019.07.06.03.55.24 for (Google Transport Security); Sat, 06 Jul 2019 03:55:24 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=thNRn6TJ; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=u2RjwdUFNE3OIK/3bCmlFikIsAzp11hkr0vwILrcAOk=; b=thNRn6TJGPSAjqCTr1tPi/WxernvhpJlmpA3TOqpdYJiE30WEHmKtQQLBhQkPRLOPw 6LdBMJiwQeRDj45LsQ+CyPeBPtz6Sm/DVPA/1jFuQwsFGykkDeEEAkecFk+eI93fAHD1 qYlH4joBKaM50/AAsI6LhYNjkSKoWjJohjBdSbGLIHp32dQu3tN7YZr1eYxcsB+bqXUy bX3ZLkExfr5FGb8+TAw/oOIVBNNg7ayqAkWV/3r6PYpzR3qHiM4xg4ORrndOJWzJXK+K OUQHzEOkfBbfQCpO4tDaUbNknqB74EkTe516YzXQIsCHfecezahJQP/7fVtAx2XeBD7c +9Fw== X-Google-Smtp-Source: APXvYqxxhkCkToEoUM8bgIOUXQl0J7gFqXqis0ZuQI5jP94wYx8vI8XERZcndoRkmUp3pDS0ZQ935g== X-Received: by 2002:a1c:5f87:: with SMTP id t129mr8243038wmb.150.1562410524445; Sat, 06 Jul 2019 03:55:24 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:23 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 11/12] S.A.R.A.: /proc/*/mem write limitation Date: Sat, 6 Jul 2019 12:54:52 +0200 Message-Id: <1562410493-8661-12-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Prevent a task from opening, in "write" mode, any /proc/*/mem file that operates on the task's mm. A process could use it to overwrite read-only memory, bypassing S.A.R.A. restrictions. Signed-off-by: Salvatore Mesoraca --- security/sara/include/sara_data.h | 18 ++++++++++++++++- security/sara/sara_data.c | 8 ++++++++ security/sara/wxprot.c | 41 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/security/sara/include/sara_data.h b/security/sara/include/sara_data.h index 9216c47..ee95f74 100644 --- a/security/sara/include/sara_data.h +++ b/security/sara/include/sara_data.h @@ -15,6 +15,7 @@ #define __SARA_DATA_H #include +#include #include #include #include @@ -40,6 +41,10 @@ struct sara_shm_data { spinlock_t lock; }; +struct sara_inode_data { + struct task_struct *task; +}; + static inline struct sara_data *get_sara_data(const struct cred *cred) { @@ -79,6 +84,17 @@ static inline struct sara_shm_data *get_sara_shm_data( #define lock_sara_shm(X) (spin_lock(&get_sara_shm_data((X))->lock)) #define unlock_sara_shm(X) (spin_unlock(&get_sara_shm_data((X))->lock)) -#endif + +static inline struct sara_inode_data *get_sara_inode_data( + const struct inode *inode) +{ + if (unlikely(!inode->i_security)) + return NULL; + return inode->i_security + sara_blob_sizes.lbs_inode; +} + +#define get_sara_inode_task(X) (get_sara_inode_data((X))->task) + +#endif /* CONFIG_SECURITY_SARA_WXPROT */ #endif /* __SARA_H */ diff --git a/security/sara/sara_data.c b/security/sara/sara_data.c index 9afca37..e875cf0 100644 --- a/security/sara/sara_data.c +++ b/security/sara/sara_data.c @@ -17,6 +17,7 @@ #include #include #include +#include #include static int sara_cred_prepare(struct cred *new, const struct cred *old, @@ -40,15 +41,22 @@ static int sara_shm_alloc_security(struct kern_ipc_perm *shp) return 0; } +static void sara_task_to_inode(struct task_struct *t, struct inode *i) +{ + get_sara_inode_task(i) = t; +} + static struct security_hook_list data_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(cred_prepare, sara_cred_prepare), LSM_HOOK_INIT(cred_transfer, sara_cred_transfer), LSM_HOOK_INIT(shm_alloc_security, sara_shm_alloc_security), + LSM_HOOK_INIT(task_to_inode, sara_task_to_inode), }; struct lsm_blob_sizes sara_blob_sizes __lsm_ro_after_init = { .lbs_cred = sizeof(struct sara_data), .lbs_ipc = sizeof(struct sara_shm_data), + .lbs_inode = sizeof(struct sara_inode_data), }; int __init sara_data_init(void) diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c index 773d1fd..1a8d132 100644 --- a/security/sara/wxprot.c +++ b/security/sara/wxprot.c @@ -22,8 +22,11 @@ #include #include #include +#include #include #include +#include +#include #include #include @@ -615,6 +618,43 @@ static int sara_file_mprotect(struct vm_area_struct *vma, return 0; } +static int sara_file_open(struct file *file) +{ + struct task_struct *t; + struct mm_struct *mm; + u16 sara_wxp_flags = get_current_sara_wxp_flags(); + + /* + * Prevent write access to /proc/.../mem + * if it operates on the mm_struct of the + * current process: it could be used to + * bypass W^X. + */ + + if (!sara_enabled || + !wxprot_enabled || + !(sara_wxp_flags & SARA_WXP_WXORX) || + !(file->f_mode & FMODE_WRITE)) + return 0; + + t = get_sara_inode_task(file_inode(file)); + if (unlikely(t != NULL && + strcmp(file->f_path.dentry->d_name.name, + "mem") == 0)) { + get_task_struct(t); + mm = get_task_mm(t); + put_task_struct(t); + if (unlikely(mm == current->mm)) + sara_warn_or_goto(error, + "write access to /proc/*/mem"); + mmput(mm); + } + return 0; +error: + mmput(mm); + return -EACCES; +} + #ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP static int sara_pagefault_handler(struct pt_regs *regs, unsigned long error_code, @@ -778,6 +818,7 @@ static int sara_setprocattr(const char *name, void *value, size_t size) LSM_HOOK_INIT(check_vmflags, sara_check_vmflags), LSM_HOOK_INIT(shm_shmat, sara_shm_shmat), LSM_HOOK_INIT(file_mprotect, sara_file_mprotect), + LSM_HOOK_INIT(file_open, sara_file_open), #ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP LSM_HOOK_INIT(pagefault_handler, sara_pagefault_handler), #endif From patchwork Sat Jul 6 10:54:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 11033615 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D3F8D13BD for ; Sat, 6 Jul 2019 10:55:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C093A289D2 for ; Sat, 6 Jul 2019 10:55:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AD6F328A27; Sat, 6 Jul 2019 10:55:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,GAPPY_SUBJECT,MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=unavailable version=3.3.1 Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 481BD28994 for ; Sat, 6 Jul 2019 10:55:45 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 8817C8E0006; Sat, 6 Jul 2019 06:55:27 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 7E1E88E000A; Sat, 6 Jul 2019 06:55:27 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 6F6148E0006; Sat, 6 Jul 2019 06:55:27 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by kanga.kvack.org (Postfix) with ESMTP id 236048E000A for ; Sat, 6 Jul 2019 06:55:27 -0400 (EDT) Received: by mail-wm1-f70.google.com with SMTP id s19so3487843wmc.7 for ; Sat, 06 Jul 2019 03:55:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:dkim-signature:from:to:cc:subject:date :message-id:in-reply-to:references; bh=7bgA3KVSNsVJyluNyhiPajryn8BOsiL4nv8POO6e3hg=; b=ISKL5OIv3av48LfRJ8mpAe1oJDA2/X4aPwXMsc6ikcwgyDYakHpFIPf4GbMo4zNEIu WxhlWoGQXxJrdya4VZ7ciS6EwB4m6n6bRaM/BoTk9RfSWNGR6ZrXN19ogadYYTWKfEmQ DD3a22uDkVXkDEAMWzwcsEAg70VLVrXpPy+x3w470AyrGz8mZK/LSZi4hhs787UAjtMY lYAyN2xg5ueYwxbFcqCCQeG+loNkKEhasoZWkutfZctyeq6Vi1oTOft88m1X32k1FbvR 9iasUdCTArIdIEX9fB+4ZMHVnJmaTwf/78/plpik6TDPHfOKdqnlHPeqwbzWm5l4i6jz zAkw== X-Gm-Message-State: APjAAAVUDH1KdIPvlTeTRWM3fPQsJHvXBn8JvFkT2AIUNYv333cQoDML kJv2xLHsp23Gij3FYQXr7ut6NdakWxTosBjWk1TJp2FcB91wV4ck73GAvkVFXzXTmyt/gmAleka d34kQmFBXwPtvPJbYCvjnecifogeaBqd5BxFcpcQjdTe77fTVyDHXeExjnTfJgfSNTA== X-Received: by 2002:adf:f812:: with SMTP id s18mr9431566wrp.32.1562410526692; Sat, 06 Jul 2019 03:55:26 -0700 (PDT) X-Received: by 2002:adf:f812:: with SMTP id s18mr9431474wrp.32.1562410525611; Sat, 06 Jul 2019 03:55:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1562410525; cv=none; d=google.com; s=arc-20160816; b=XTEEeou3NBRn+zQ1Ds8uLt2Ot3lfDrwvSLDaroTuvG5t2wtodJOvoKTsL52D8zj7Qh rknGGa6FFVHH3p+W78zBlYFEC2qp2lwq79Fh++kWCNkLMtCTqA/j62HIair5Eb430HJn rWEHcpLmBufN64KWXcTGv3mrq5T37L6nFL7tRUkK4oI4qYsZ7GnX7rlHx7STaS368GQi clEWw56+C0QHh/8zep2ZJ+mNjqQau/3DU6sBBzoKXFFfdr21JyKXAV8LE46I/dFSN287 OGuVkY+g97HD7Swq+8Zc8GCXOBo9Dwqrxk6FEbVG3ADEMHVia4viq4EAobxxkyJQUx79 Yv4w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=7bgA3KVSNsVJyluNyhiPajryn8BOsiL4nv8POO6e3hg=; b=Ti4y8keTJ0FDI68OPaTo7jlm2grT0tmZwtPimA22EmKlULQ1BkZ5ZHop4B7pH7l/kl L9+ZszAMttK/G7W9NGLwB71UHy7gAlBUIngAxUTzYHHUcMx5rQ0/glvHnPPdRIVGZraC dLwqZqQ2Dr3kfkf2MnuZbSapEWxcMdwNe1oLuRDhBGBG7D5POxkMEAkYchn8jXkLO4Km d2vlKPf9A3GhxnCYoTQhLM+JQnQb8cKesmSgIfcDbRXwOi4OMTdED5nC5/VlWN3bpC05 +6knWUT/JsVWOga3T4oTx9YuYarAgV88ujHywkoZs1oKKhJdEeSNrfhg1Ieq4UBMNVwU 9eaQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=U523Em2K; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-sor-f65.google.com (mail-sor-f65.google.com. [209.85.220.65]) by mx.google.com with SMTPS id z12sor233388wrl.13.2019.07.06.03.55.25 for (Google Transport Security); Sat, 06 Jul 2019 03:55:25 -0700 (PDT) Received-SPF: pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) client-ip=209.85.220.65; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=U523Em2K; spf=pass (google.com: domain of s.mesoraca16@gmail.com designates 209.85.220.65 as permitted sender) smtp.mailfrom=s.mesoraca16@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=7bgA3KVSNsVJyluNyhiPajryn8BOsiL4nv8POO6e3hg=; b=U523Em2KEtwXXxdV/BGn5jTzA7rwZNHEXsm1OcyY68qXcXEIgtM7G0Cet6d7ccvPCH xbNCt3TDC5HduqU/DgmJHVWSZe3KHZA5S97dUyH+Nq+WuUGuXAX0ragXjruWpmzsAxwt ZI947WMH7fH0XqCrCOg3eUA/2YAFkYNqtSug+CIUNQQHYURAjMXd6h9N5ALvdD0NpxEB AK2lAV8bchfSrDSx25gT6m0BWN8JZu//SbcHOnuqBRH2eqm3G2johuskfOsaaGz6nZlh deThmGjYCWPUDpw151T+5llw2TOJGBzuERv8CkChSGkkIYR0JLd+dQLERH79C+pRIoUr 14dA== X-Google-Smtp-Source: APXvYqzPbEUIxunmBrxyk9NAIxCXus8RCS7gBuXZApUJVMJ6c1dTQqt5X0xbeRxaG4n4nmyktigDXg== X-Received: by 2002:adf:e843:: with SMTP id d3mr9048922wrn.249.1562410525376; Sat, 06 Jul 2019 03:55:25 -0700 (PDT) Received: from localhost (net-93-71-3-102.cust.vodafonedsl.it. [93.71.3.102]) by smtp.gmail.com with ESMTPSA id h11sm12578794wrx.93.2019.07.06.03.55.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 06 Jul 2019 03:55:25 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: kernel-hardening@lists.openwall.com, linux-mm@kvack.org, linux-security-module@vger.kernel.org, Alexander Viro , Brad Spengler , Casey Schaufler , Christoph Hellwig , James Morris , Jann Horn , Kees Cook , PaX Team , Salvatore Mesoraca , "Serge E. Hallyn" , Thomas Gleixner Subject: [PATCH v5 12/12] MAINTAINERS: take maintainership for S.A.R.A. Date: Sat, 6 Jul 2019 12:54:53 +0200 Message-Id: <1562410493-8661-13-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> References: <1562410493-8661-1-git-send-email-s.mesoraca16@gmail.com> X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Salvatore Mesoraca --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f16e5d0..de6dab1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13925,6 +13925,15 @@ F: drivers/phy/samsung/phy-s5pv210-usb2.c F: drivers/phy/samsung/phy-samsung-usb2.c F: drivers/phy/samsung/phy-samsung-usb2.h +SARA SECURITY MODULE +M: Salvatore Mesoraca +T: git git://github.com/smeso/sara.git lsm/sara/master +W: https://sara.smeso.it +S: Maintained +F: security/sara/ +F: arch/x86/security/sara/ +F: Documentation/admin-guide/LSM/SARA.rst + SC1200 WDT DRIVER M: Zwane Mwaikambo S: Maintained