From patchwork Mon Sep 11 19:50:27 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Salvatore Mesoraca X-Patchwork-Id: 9947993 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 ED584602C9 for ; Mon, 11 Sep 2017 19:52:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E544F28D34 for ; Mon, 11 Sep 2017 19:52:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DA3F628D39; Mon, 11 Sep 2017 19:52:01 +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.3 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, GAPPY_SUBJECT, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, 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 5FDE928D38 for ; Mon, 11 Sep 2017 19:52:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751519AbdIKTvz (ORCPT ); Mon, 11 Sep 2017 15:51:55 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:37301 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751493AbdIKTvx (ORCPT ); Mon, 11 Sep 2017 15:51:53 -0400 Received: by mail-wm0-f65.google.com with SMTP id f4so7670060wmh.4; Mon, 11 Sep 2017 12:51:52 -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=skf8WPbB1GWDV/gzvs4Z/BCaReKXVJlnD0B/SSmuI7g=; b=YuVHhmmXgEaR6LoI62ZFhVFfnim/DLTT5NC0BtrJ6H5noPcfMimtltgvaNSsyZy2eb 9shimXTFIdtqqgcI9tlEpirUmNaaV9RdR6ZTA3J76XfXJlhGor9l6sz1ywclCljeSwj6 U0XzW+4T4eD+kX5Cl8Yhks30RkP9kpRVxuGdTl0kTzfriPs75RobZDbtm35i+Q8EOD3p 6g/uoTR3GEBI0Sz29ay4wZOJlcC0kDUgfUXPKL9pNnMZbvTV23Blw7JfEnKsbSeVch6I hzE5o3knzS7ek9Ajyz1qGJzertSuIRD/veNsILbiUHVkIUkvbOuxR/pfLFFymUoWulp+ /SuQ== 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=skf8WPbB1GWDV/gzvs4Z/BCaReKXVJlnD0B/SSmuI7g=; b=jNe0/vf1RCDcfBTQ9rLsJxQ/wt3SVsj+r0G77wh+vXWHjHxPfyNVhGWnYxkhYrmvml qq5o7m/A7oFnHo9g6wpxXfXJGEboplHPaJRPN+dyhMGIJNtTLlUHPwSbbmlvMrk7E1j/ I471OQTxDRaW0IDutd0HgUqewu67NgqpH4RVUmGvXfV9ldym1vUm/O3DAnRIeO8K9jVn qULoMrws7cYOqGmkpfItbrq6rI4QS8PD9XkL7fl9j9Ew3Sb99I38xnH/4fTM+iZGQkeV zSaNGVdi+mLr+pnq6RXkMA9yi+ehkGKdCtSx9/0alms7v0gfXyWAr5jRvKQ2jqTff85w vCSQ== X-Gm-Message-State: AHPjjUjnR+5thEOZrJjdk+G7CFLwBAPTOeKp0uJebYRORhclcew6jejp NZ0zMphMsBTdcEwVGnYAR6VrirM+YqQ= X-Google-Smtp-Source: AOwi7QDMu7k5izHA7+2J/ZWnityiljW8dw1Meik+oCPacFvocukknANY0RVODP0f9kCVfoVgBiCLUg== X-Received: by 10.28.128.197 with SMTP id b188mr8962511wmd.121.1505159511438; Mon, 11 Sep 2017 12:51:51 -0700 (PDT) Received: from localhost ([93.66.104.212]) by smtp.gmail.com with ESMTPSA id a39sm14663448wrc.48.2017.09.11.12.51.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 11 Sep 2017 12:51:50 -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: [RFC v3 9/9] S.A.R.A. WX Protection procattr interface Date: Mon, 11 Sep 2017 21:50:27 +0200 Message-Id: <1505159427-11747-10-git-send-email-s.mesoraca16@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1505159427-11747-1-git-send-email-s.mesoraca16@gmail.com> References: <1505159427-11747-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 | 150 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/security/sara/wxprot.c b/security/sara/wxprot.c index d360833..afc4e13 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 @@ -43,6 +44,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 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; + /* + * 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[] __ro_after_init = { LSM_HOOK_INIT(bprm_set_creds, sara_bprm_set_creds), LSM_HOOK_INIT(check_vmflags, sara_check_vmflags), @@ -547,6 +695,8 @@ static inline int sara_pagefault_handler_x86_64(struct pt_regs *regs) #ifdef CONFIG_SECURITY_SARA_WXPROT_EMUTRAMP LSM_HOOK_INIT(pagefault_handler, sara_pagefault_handler_x86), #endif + LSM_HOOK_INIT(getprocattr, sara_getprocattr), + LSM_HOOK_INIT(setprocattr, sara_setprocattr), }; struct binary_config_header {