From patchwork Fri Sep 8 22:44:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ram Pai X-Patchwork-Id: 811875 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xptgn1BFxz9s7h for ; Sat, 9 Sep 2017 09:24:21 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="UzAJdGnk"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3xptgm6cykzDqjf for ; Sat, 9 Sep 2017 09:24:20 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="UzAJdGnk"; dkim-atps=neutral X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gmail.com (client-ip=2607:f8b0:400d:c0d::241; helo=mail-qt0-x241.google.com; envelope-from=ram.n.pai@gmail.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="UzAJdGnk"; dkim-atps=neutral Received: from mail-qt0-x241.google.com (mail-qt0-x241.google.com [IPv6:2607:f8b0:400d:c0d::241]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3xpsrk5kNvzDrd6 for ; Sat, 9 Sep 2017 08:47:02 +1000 (AEST) Received: by mail-qt0-x241.google.com with SMTP id 7so2357084qtz.3 for ; Fri, 08 Sep 2017 15:47:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=tD1voKtKeorE1X4wP9PgZpqxPg97wZPDAdmWK2LMd78=; b=UzAJdGnkdAr8OmpuelxCL8zZwYiVjRpWDTUBQPxdLQcwYuzssmXQd+ojVLUglrg+gY bYUOWfUMHKt/qRvsrP/RtKY+OY177rYGpXCftZd6WPPx7Zh79Uj+WOn/jNo1/L0laf5H gNntvv+WQbCUYVQeUeu44mxr5JGCeOQEAmKtESh6DBsi0UNjOCBYnT2dMpJ1ZZ6ks3AZ pa8qNy0F7O4BYMlQ0d9bOMCFvP8AVorTE1YbImw+35LRSIgHtLDtPZncACDm8lPPxOPU wlFLy8K07BuQFVGLcUR9VppQTyUMB6R/Ru0HgrPQOgveEYwZwVA9BAB1UORbD/yWo9J0 HNKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=tD1voKtKeorE1X4wP9PgZpqxPg97wZPDAdmWK2LMd78=; b=IhbplQo1E7VYV1GYsbtoWWbUiJZoQWQzSC/0xjcPOY7MxTI2YAwZ9Ygg5H/wJ6fnC6 +zQ21daltzGlhrsrgC8iPorRM0QGK+UP4/s1LjgQQUyq8bX/a7qBv3pPcGXBYt1oFaVR ArUIXYQIa+nTLcfzYV1T7Bd8pB84Na8EXMOZX6Kwf1cBqqR/6EBemBfIMfeu9u4sLTZc A6lk7rJy2h3yjPrJ4bL2jvlW3qF0bOMAGYGlr/wvHIuafTLOCPY2aE8GXACc7mcTY3K7 aTHr0YApdluoWO0yVndkZNdXDyC2EAs1tLuJjHH4IWt+uNhKLOU1DFc+PXxyNd2peFRT /fVg== X-Gm-Message-State: AHPjjUh2bPXU0LfNGCKaz8cHm/zpFmaV/EzzzHQY8gzgaN0QjFhPvjUc FkSIC0/LGyhHUg== X-Google-Smtp-Source: AOwi7QDJkV1JKy8I1ExlL1LSg//pyGa4az90YnbKY3ggiOZSJCrJaXy/6/Bh0OnwlG2iRsKeBz6slg== X-Received: by 10.200.42.99 with SMTP id l32mr6390944qtl.121.1504910820869; Fri, 08 Sep 2017 15:47:00 -0700 (PDT) Received: from localhost.localdomain (50-39-103-96.bvtn.or.frontiernet.net. [50.39.103.96]) by smtp.gmail.com with ESMTPSA id x124sm2033726qka.85.2017.09.08.15.46.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 08 Sep 2017 15:47:00 -0700 (PDT) From: Ram Pai To: mpe@ellerman.id.au, linuxppc-dev@lists.ozlabs.org Subject: [PATCH 11/25] powerpc: introduce execute-only pkey Date: Fri, 8 Sep 2017 15:44:59 -0700 Message-Id: <1504910713-7094-20-git-send-email-linuxram@us.ibm.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1504910713-7094-1-git-send-email-linuxram@us.ibm.com> References: <1504910713-7094-1-git-send-email-linuxram@us.ibm.com> X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: ebiederm@xmission.com, linuxram@us.ibm.com, mhocko@kernel.org, paulus@samba.org, aneesh.kumar@linux.vnet.ibm.com, bauerman@linux.vnet.ibm.com, khandual@linux.vnet.ibm.com Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" This patch provides the implementation of execute-only pkey. The architecture-independent layer expects the arch-dependent layer, to support the ability to create and enable a special key which has execute-only permission. Signed-off-by: Ram Pai Acked-by: Balbir Singh --- arch/powerpc/include/asm/book3s/64/mmu.h | 1 + arch/powerpc/include/asm/pkeys.h | 9 ++++- arch/powerpc/mm/pkeys.c | 57 ++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletions(-) diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h index 55950f4..ee18ba0 100644 --- a/arch/powerpc/include/asm/book3s/64/mmu.h +++ b/arch/powerpc/include/asm/book3s/64/mmu.h @@ -115,6 +115,7 @@ struct patb_entry { * bit unset -> key available for allocation */ u32 pkey_allocation_map; + s16 execute_only_pkey; /* key holding execute-only protection */ #endif } mm_context_t; diff --git a/arch/powerpc/include/asm/pkeys.h b/arch/powerpc/include/asm/pkeys.h index 78c5362..0cf115f 100644 --- a/arch/powerpc/include/asm/pkeys.h +++ b/arch/powerpc/include/asm/pkeys.h @@ -115,11 +115,16 @@ static inline int mm_pkey_free(struct mm_struct *mm, int pkey) * Try to dedicate one of the protection keys to be used as an * execute-only protection key. */ +extern int __execute_only_pkey(struct mm_struct *mm); static inline int execute_only_pkey(struct mm_struct *mm) { - return 0; + if (!pkey_inited || !pkey_execute_disable_support) + return -1; + + return __execute_only_pkey(mm); } + static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma, int prot, int pkey) { @@ -141,6 +146,8 @@ static inline void pkey_mm_init(struct mm_struct *mm) if (!pkey_inited) return; mm_pkey_allocation_map(mm) = initial_allocation_mask; + /* -1 means unallocated or invalid */ + mm->context.execute_only_pkey = -1; } extern void thread_pkey_regs_save(struct thread_struct *thread); diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c index 7cd1be4..8a24983 100644 --- a/arch/powerpc/mm/pkeys.c +++ b/arch/powerpc/mm/pkeys.c @@ -188,3 +188,60 @@ void thread_pkey_regs_init(struct thread_struct *thread) write_iamr(0x0ul); write_uamor(0x0ul); } + +static inline bool pkey_allows_readwrite(int pkey) +{ + int pkey_shift = pkeyshift(pkey); + + if (!(read_uamor() & (0x3UL << pkey_shift))) + return true; + + return !(read_amr() & ((AMR_RD_BIT|AMR_WR_BIT) << pkey_shift)); +} + +int __execute_only_pkey(struct mm_struct *mm) +{ + bool need_to_set_mm_pkey = false; + int execute_only_pkey = mm->context.execute_only_pkey; + int ret; + + /* Do we need to assign a pkey for mm's execute-only maps? */ + if (execute_only_pkey == -1) { + /* Go allocate one to use, which might fail */ + execute_only_pkey = mm_pkey_alloc(mm); + if (execute_only_pkey < 0) + return -1; + need_to_set_mm_pkey = true; + } + + /* + * We do not want to go through the relatively costly + * dance to set AMR if we do not need to. Check it + * first and assume that if the execute-only pkey is + * readwrite-disabled than we do not have to set it + * ourselves. + */ + if (!need_to_set_mm_pkey && + !pkey_allows_readwrite(execute_only_pkey)) + return execute_only_pkey; + + /* + * Set up AMR so that it denies access for everything + * other than execution. + */ + ret = __arch_set_user_pkey_access(current, execute_only_pkey, + (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE)); + /* + * If the AMR-set operation failed somehow, just return + * 0 and effectively disable execute-only support. + */ + if (ret) { + mm_set_pkey_free(mm, execute_only_pkey); + return -1; + } + + /* We got one, store it and use it from here on out */ + if (need_to_set_mm_pkey) + mm->context.execute_only_pkey = execute_only_pkey; + return execute_only_pkey; +}