From patchwork Mon Jun 12 16:57:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 9782333 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 007F660244 for ; Mon, 12 Jun 2017 16:59:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E44C3284C7 for ; Mon, 12 Jun 2017 16:59:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D88C4284DA; Mon, 12 Jun 2017 16:59: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=-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=unavailable 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 45B24284C7 for ; Mon, 12 Jun 2017 16:59:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753578AbdFLQ7B (ORCPT ); Mon, 12 Jun 2017 12:59:01 -0400 Received: from mail-wr0-f194.google.com ([209.85.128.194]:36288 "EHLO mail-wr0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752987AbdFLQ6j (ORCPT ); Mon, 12 Jun 2017 12:58:39 -0400 Received: by mail-wr0-f194.google.com with SMTP id e23so23362314wre.3; Mon, 12 Jun 2017 09:58:38 -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=R4kyhCAjNwssSHedq/sdz/NbgsIsCkBWqJGq+pRG57I=; b=m2VyISQoyfB0+Tdzx3z9Vr4hxhQBZZe03lcEVRqOAyPeqPNSjEEum+6TnqHZvhFbEJ 8G41lN8W+fGYXz71QLiPIvOJqvTULH8+jBRG5NqYzzxcEnMz14t00Dfibcr2QVxo3Tcc XoHpRmOpQA+zIObeq0cA7iekvnObP960ldNwqIhM3Hyzbjo+x336ra2QIjqq0cP9AE/q itBLaqphnhHFBw+NVZet7l3xRtuX5FzDXv4TAbnftS6ZMXdW3+QeBSwCE36flsxKxCbx Z3x8McrV6e3pu5AcN9KlUhJXKtoF7PcFtP+4v+NzWwnsK49AnMVGgdCxDdDGcNXn5cMR 8CEw== 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=R4kyhCAjNwssSHedq/sdz/NbgsIsCkBWqJGq+pRG57I=; b=XZbrICGHpdxWYjAJ/3pMJ/W8VNvVmQu/Zi79SYbJHArpqMYWRCKVVlkFFl0lW5bsNM cGOWSryFPcQisjwtYPR6+RyeNS7AjfUrUGW67Bl70g2DA0ygOdMh/8nr2niISfOJzcd0 scc2I1avqCIONGvDBI55sTjKboJyryzvhnqPw+8Y+UP8qg1hCNXKxiC9z59otFbUglyy t1pJSq5Hu3yC6LzSPEg6FC/wB1SwEaNCZgVDnRE5wTITtNDco5/Va3JFsPvo2gXo0WOo +kS/nXlcv6aEF9kBnoPngeaXjjW+sJ2TfQgeu03IUrY78dnuPJBTvHqXmVONwUyu8XQr 5kGA== X-Gm-Message-State: AKS2vOxBQH8zPjOBXYVErqZUbFWQRYvCcVOj3YAao63Iuxdmkl3nnpLf PECvKkLc5NUijymAz+9uZgZ5 X-Received: by 10.28.184.195 with SMTP id i186mr4339524wmf.98.1497286717738; Mon, 12 Jun 2017 09:58:37 -0700 (PDT) Received: from localhost ([109.112.0.253]) by smtp.gmail.com with ESMTPSA id n2sm20925973wrn.30.2017.06.12.09.58.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 12 Jun 2017 09:58:37 -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" Subject: [PATCH 11/11] S.A.R.A. WX Protection procattr interface Date: Mon, 12 Jun 2017 18:57:00 +0200 Message-Id: <1497286620-15027-12-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1497286620-15027-1-git-send-email-s.mesoraca16@gmail.com> References: <1497286620-15027-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 processes to get current WX Protection flags for themselves or for other processes of the same user. It also allow a process 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 process 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. Given that it's possible to segregate the part that runs untrusted code from the rest through a fork, 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/saralib Signed-off-by: Salvatore Mesoraca --- security/sara/wxprot.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c index 44e42be..00cd22c 100644 --- a/security/sara/wxprot.c +++ b/security/sara/wxprot.c @@ -40,6 +40,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 @@ -496,6 +497,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 && + current_euid().val)) + 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), @@ -503,6 +624,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 {