From patchwork Thu Jun 15 16:42:56 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 9789325 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C1E7760384 for ; Thu, 15 Jun 2017 16:44:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B2F6227F7F for ; Thu, 15 Jun 2017 16:44:57 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A79E428552; Thu, 15 Jun 2017 16:44:57 +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=-4.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, GAPPY_SUBJECT, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0C001284F5 for ; Thu, 15 Jun 2017 16:44:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752611AbdFOQox (ORCPT ); Thu, 15 Jun 2017 12:44:53 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:36117 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752017AbdFOQot (ORCPT ); Thu, 15 Jun 2017 12:44:49 -0400 Received: by mail-wr0-f195.google.com with SMTP id 77so4271500wrb.3; Thu, 15 Jun 2017 09:44:44 -0700 (PDT) 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=oTbOWVfxhyCvXNphJIMe1qSSageqkl0iouhyiTfZ0FQ=; b=Qo0l5iX7n8X8Y5stAJ9mEx8A//yfaq/9m/Ui8yF4tBp+O/OksZqn2bKHRd4H71f9ZV BnPk2HwS9lrOCiO+ELkgzdlYXmFhl3fqoL49v4tj97QXI2xOdxu36jgnM6DNZ1W72XNS ipcQGLgbTLdy0CojTTxwXbrDvy+Jv8c1WWapfOUGp19D47rR5n2RsU5a0uqtcpvWK8OI 8AwC61BzM3wllLHJ8Qb+YlAyOoWS21q2NDPdWkXnBawf6CDZa8x7jUdLcTSBSTwAxRgx ZyAbdMQSVV2fcY7qcohCdwRemKUMqRCTpuKJwPgKSNU6ZyZKqsRZOw9Ldof9PUBobbTE bvyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=oTbOWVfxhyCvXNphJIMe1qSSageqkl0iouhyiTfZ0FQ=; b=EcbptBHqWygfDLaT6qeB4FG8PNZHQzc9KIsJcVFXgFzGz3wajUuJYQmny8oLwCMsdn pmDQGeb+XPLnrV5CwUs6tsVHjUB7WoEJ4AsSE/v9SYNmDU16KKjnAX91uCxX9NR6WPZK dHUZ2LzMdoov+UijNbRlLfwefrvJvEXHmyY0s4eVVAtL6qEsomWJljJzzhGV93MD8tus wS1W3z8fIx+IgwiQzE6s9SrRy12e6xnxARd0rmTkeEB7euK4c25pCbhlcj6D1i3figEG THCbLF4TZyXlKZvG4yih5dryeOAs1r4BkQyf5g2OaTImhMT4+XtVZxBzXduLIwZu7Gao Q7wg== X-Gm-Message-State: AKS2vOzUtufGArKtcAlFHTeyp0G7aiqr6p/qWV8amC2XNNjYwfLiGl1P yg5cGda42d1D3ndckGryUVRx X-Received: by 10.223.133.4 with SMTP id 4mr4799687wrh.30.1497545082433; Thu, 15 Jun 2017 09:44:42 -0700 (PDT) Received: from localhost ([37.176.236.94]) by smtp.gmail.com with ESMTPSA id k19sm615938wmg.9.2017.06.15.09.44.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 15 Jun 2017 09:44:42 -0700 (PDT) From: Salvatore Mesoraca To: linux-kernel@vger.kernel.org Cc: linux-security-module@vger.kernel.org, kernel-hardening@lists.openwall.com, Salvatore Mesoraca , Brad Spengler , PaX Team , Casey Schaufler , Kees Cook , James Morris , "Serge E. Hallyn" , linux-mm@kvack.org, x86@kernel.org, Jann Horn , Christoph Hellwig , Thomas Gleixner Subject: [RFC v2 9/9] S.A.R.A. WX Protection procattr interface Date: Thu, 15 Jun 2017 18:42:56 +0200 Message-Id: <1497544976-7856-10-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1497544976-7856-1-git-send-email-s.mesoraca16@gmail.com> References: <1497544976-7856-1-git-send-email-s.mesoraca16@gmail.com> Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk 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 --- security/sara/wxprot.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c index 38c86be..0939591 100644 --- a/security/sara/wxprot.c +++ b/security/sara/wxprot.c @@ -12,6 +12,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 @@ -503,6 +505,126 @@ static inline int sara_pagefault_handler_x86_64(struct pt_regs *regs) #endif /* CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP */ +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, 16, &req_flags) != 0)) + goto error; + if (unlikely(!are_flags_valid(req_flags & ~SARA_WXP_FORCE_WXORX))) + goto error; + 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; + if (unlikely(cur_flags & (req_flags ^ cur_flags) & + ~(SARA_WXP_COMPLAIN|SARA_WXP_EMUTRAMP))) + goto error; + ret = -EINTR; + 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[] __ro_after_init = { LSM_HOOK_INIT(bprm_set_creds, sara_bprm_set_creds), LSM_HOOK_INIT(check_vmflags, sara_check_vmflags), @@ -510,6 +632,8 @@ static inline int sara_pagefault_handler_x86_64(struct pt_regs *regs) #ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP LSM_HOOK_INIT(pagefault_handler_x86, sara_pagefault_handler_x86), #endif + LSM_HOOK_INIT(getprocattr, sara_getprocattr), + LSM_HOOK_INIT(setprocattr, sara_setprocattr), }; struct binary_config_header {