From patchwork Wed Dec 7 15:49:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 30907 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp260927wrr; Wed, 7 Dec 2022 07:52:42 -0800 (PST) X-Google-Smtp-Source: AA0mqf4yUl5EZ4Hhanol6+GbzVgPNoGYcVLo0Nt6xAeI9AE3WYgAt+ZqA28j+cahuPCfjnJ73VOl X-Received: by 2002:a17:907:a06e:b0:7c0:dfb7:3525 with SMTP id ia14-20020a170907a06e00b007c0dfb73525mr15418471ejc.205.1670428362026; Wed, 07 Dec 2022 07:52:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670428362; cv=none; d=google.com; s=arc-20160816; b=kFQdcohfQYfNdO8r1NrlsxqdCdGfoWL6/jKi1em4IOpTrdezlmLIZSVAgKWNdl74Tt xp18g9+9XTBsulzCvatr18w1FuUKlhT/xqZzFqu5Jz2eJMnBu1fKwgSTysDAFZ5sBWgp IZv03uUZCrNz5jI+lioMkPSEV2iAtmQbB2pL6rx5WjvL/DOAcCx2a/OsUvhGlAicxNUF rO6ljGi0OOXky1uw+GqWZpu+GpNjO2e8dIPbT1gGy8hnRIHjcAzVC3m5e6tg8U8sHYNF Yh1q/M8h9JI2SNMFz0OmpEfIZcAP2XaEjCYHTW0nJxv0LKaaLYA5N47+Z1hMUn591vpo 9hWA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=71ca0yPxFF6EaiLKMWlrSqitNHDHlqW3RCkGeX1vy+A=; b=vYjUBkBkoR7sxyXSKuEF7FRuCC80YJOWHyxTehTQ55c3C42JTdB1CgjARcdQPChwYy af46Erpzy75t1I2l5kmjrC2p8Y6uZFeYKjOUIcRfqDPDWzsRe2VABHc3UkKJguxnUwaG keqSyGRgUh0spb41nXl9+t3RoGHIgFxU7AZ9RGxkIy1e6jd/C2fuiSBie9yorDOaEiD9 QY/j5838HlnUKq0VR4v0M1dlN3Pl3ewc7AGNL8lKAcxKaogLNYLBBe6QPy54zzpvSecx Wks82m5ngUV1Nv/9e6ou0f/QDv4XDQZlpE78Gf1565s0G1JG3BklmArZ5tjWs+RTKcA+ eZ9g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=PhU557wY; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id r24-20020aa7c158000000b0046ca3c3df50si4313939edp.211.2022.12.07.07.52.18; Wed, 07 Dec 2022 07:52:42 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=PhU557wY; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229811AbiLGPty (ORCPT + 99 others); Wed, 7 Dec 2022 10:49:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50628 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229705AbiLGPtq (ORCPT ); Wed, 7 Dec 2022 10:49:46 -0500 Received: from mail-pj1-x102e.google.com (mail-pj1-x102e.google.com [IPv6:2607:f8b0:4864:20::102e]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 034B3326DF for ; Wed, 7 Dec 2022 07:49:46 -0800 (PST) Received: by mail-pj1-x102e.google.com with SMTP id t11-20020a17090a024b00b0021932afece4so1814391pje.5 for ; Wed, 07 Dec 2022 07:49:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=71ca0yPxFF6EaiLKMWlrSqitNHDHlqW3RCkGeX1vy+A=; b=PhU557wYsKo/iDLZ/eBYG10j3SUNufkud5V4AzaP2ICyOtQc995aeL12t/n/DCDOjS NMogyAHS/VfnZLMBDSu6Di4KmFIVVQ0uOhTFzgcacngKlg82FwY5QBCqc7jvGtP83Lsg 0oNoHBlwcyoa3/tfXpapegc2TgwcvzzxnMc4Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=71ca0yPxFF6EaiLKMWlrSqitNHDHlqW3RCkGeX1vy+A=; b=1W32KPTrcOjMjc0ED7xQynRIaX3Lbf+wCf8jWMDrS5QnGC9Pvg63giTpSy7kpqCrcX Y0UsT6dwFpLl1eabbNNo3OGegAj7nh0Bwp3NOTMlR7HADy9waUToxRT3+f/qrhLj3s9n sDTYMPHDVjEeWngP59iQRsaC2TM+/k/xJ/PX34PfvKsoai0eQjEyQVj3y/NPuzpZM6eK VM+bT5FuRI3DN4Z/7Tpts14Hi8GRQXbCnnelCelPURIHWtjnJVDl0rcxPR1K9NCwowm/ PpjuC5bUS4439ohj271GKxHWJjL10iVDIAhb4girxrqx0cD/W1olYSMNq+MmdmVvlb1H HnpA== X-Gm-Message-State: ANoB5plXZXIxWPL95K3FX9vDXn480oHhvTKJCqVzaSPC/pwbaI88TV5z PR47XEFn7DjAQr8dxaMD9oO4bQ== X-Received: by 2002:a17:902:8343:b0:187:1f0:4579 with SMTP id z3-20020a170902834300b0018701f04579mr748942pln.61.1670428185700; Wed, 07 Dec 2022 07:49:45 -0800 (PST) Received: from jeffxud.c.googlers.com.com (30.202.168.34.bc.googleusercontent.com. [34.168.202.30]) by smtp.gmail.com with ESMTPSA id a9-20020a170902ecc900b0017f7628cbddsm14920934plh.30.2022.12.07.07.49.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Dec 2022 07:49:44 -0800 (PST) From: jeffxu@chromium.org To: skhan@linuxfoundation.org, keescook@chromium.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, jannh@google.com, linux-hardening@vger.kernel.org Subject: [PATCH v6 1/6] mm/memfd: add F_SEAL_EXEC Date: Wed, 7 Dec 2022 15:49:34 +0000 Message-Id: <20221207154939.2532830-2-jeffxu@google.com> X-Mailer: git-send-email 2.39.0.rc0.267.gcb52ba06e7-goog In-Reply-To: <20221207154939.2532830-1-jeffxu@google.com> References: <20221207154939.2532830-1-jeffxu@google.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751571089842539072?= X-GMAIL-MSGID: =?utf-8?q?1751571089842539072?= From: Daniel Verkamp The new F_SEAL_EXEC flag will prevent modification of the exec bits: written as traditional octal mask, 0111, or as named flags, S_IXUSR | S_IXGRP | S_IXOTH. Any chmod(2) or similar call that attempts to modify any of these bits after the seal is applied will fail with errno EPERM. This will preserve the execute bits as they are at the time of sealing, so the memfd will become either permanently executable or permanently un-executable. Signed-off-by: Daniel Verkamp Co-developed-by: Jeff Xu Signed-off-by: Jeff Xu Reviewed-by: Kees Cook --- include/uapi/linux/fcntl.h | 1 + mm/memfd.c | 2 ++ mm/shmem.c | 6 ++++++ 3 files changed, 9 insertions(+) diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h index 2f86b2ad6d7e..e8c07da58c9f 100644 --- a/include/uapi/linux/fcntl.h +++ b/include/uapi/linux/fcntl.h @@ -43,6 +43,7 @@ #define F_SEAL_GROW 0x0004 /* prevent file from growing */ #define F_SEAL_WRITE 0x0008 /* prevent writes */ #define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */ +#define F_SEAL_EXEC 0x0020 /* prevent chmod modifying exec bits */ /* (1U << 31) is reserved for signed error codes */ /* diff --git a/mm/memfd.c b/mm/memfd.c index 08f5f8304746..4ebeab94aa74 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -147,6 +147,7 @@ static unsigned int *memfd_file_seals_ptr(struct file *file) } #define F_ALL_SEALS (F_SEAL_SEAL | \ + F_SEAL_EXEC | \ F_SEAL_SHRINK | \ F_SEAL_GROW | \ F_SEAL_WRITE | \ @@ -175,6 +176,7 @@ static int memfd_add_seals(struct file *file, unsigned int seals) * SEAL_SHRINK: Prevent the file from shrinking * SEAL_GROW: Prevent the file from growing * SEAL_WRITE: Prevent write access to the file + * SEAL_EXEC: Prevent modification of the exec bits in the file mode * * As we don't require any trust relationship between two parties, we * must prevent seals from being removed. Therefore, sealing a file diff --git a/mm/shmem.c b/mm/shmem.c index c1d8b8a1aa3b..e18a9cf9d937 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1085,6 +1085,12 @@ static int shmem_setattr(struct user_namespace *mnt_userns, if (error) return error; + if ((info->seals & F_SEAL_EXEC) && (attr->ia_valid & ATTR_MODE)) { + if ((inode->i_mode ^ attr->ia_mode) & 0111) { + return -EPERM; + } + } + if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { loff_t oldsize = inode->i_size; loff_t newsize = attr->ia_size; From patchwork Wed Dec 7 15:49:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 30901 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp260276wrr; Wed, 7 Dec 2022 07:51:16 -0800 (PST) X-Google-Smtp-Source: AA0mqf7ZW4gKq/lz5+FMgmPZHoNwalJtCfCorUYjNKtND3deYdXB95VOjBIio7NMvTl1kmfXesFH X-Received: by 2002:a50:f608:0:b0:46b:66a0:4fcf with SMTP id c8-20020a50f608000000b0046b66a04fcfmr34857845edn.192.1670428276432; Wed, 07 Dec 2022 07:51:16 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670428276; cv=none; d=google.com; s=arc-20160816; b=w5eADBAh2JhUc75gETSSei1qJYdxGjPTuregLo6jYIpZWTUSrYYO9t/LR1Bxiw89YJ sV1aRUxPaltOO//23twPrxHNny+3zfGgo6l9B5KeTAK8g8iPYM+A6S7D3snxf/0l9rGQ Bos3Sr0RYDZcsDYIRH49NzNGaA5GlkcIGChDQ+vmdS07pOrR26WJBK1JqKdtlFWE0lxo 5mBlJhgAxRitmTLDZkUzPjK0cqa3XOjC1boR1b/25DbXdD0LQ9lYiNpGjDJov83fWS6l dcoc66wa52YuC0hRsFeesj04Gpk9s/Vwb7qJojCiaF3Pw5iHccHNXZXWSrLXnAOuDuxB CoIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=NbsvwgwPR3B757gRns7/stgcrkFvNaKcuShOuGKUmaw=; b=xjVrbDJOxp8YcSo4bmpZIf7V/G6U6UUmi6dDgEObejXmyuhl0fA+escD58rS9zhy8K l2vF6zH4+vWSpCKSghTJPitZljSPszKl5WpV1wtW57RkmvvDbkRX3idfdPHH1bfTlzkm eIts9k+c6h9YuVbAi09Rb+GKx3P9fNT+MqQBLwqEhZgeWauRGAWGFaVB7bwXdxJMm/dS jqC8KiaxwUbTfgd2NG/YZxYak2VtDOCjtM+tsHR7isXf6rrYRxvLQi0ipN0iC/qeLb5/ r91pzZZf8pcOzOPuSk67gY8Op5xR+G4Gxl/SSYCcLFYf3OH5yBICKrK9YQ0bZbT/9ILX 36Vw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=dWibBvBT; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id b8-20020aa7c6c8000000b00469054c7246si3950366eds.506.2022.12.07.07.50.53; Wed, 07 Dec 2022 07:51:16 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=dWibBvBT; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229602AbiLGPt6 (ORCPT + 99 others); Wed, 7 Dec 2022 10:49:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50590 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229753AbiLGPts (ORCPT ); Wed, 7 Dec 2022 10:49:48 -0500 Received: from mail-pl1-x62a.google.com (mail-pl1-x62a.google.com [IPv6:2607:f8b0:4864:20::62a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2D3D95CD31 for ; Wed, 7 Dec 2022 07:49:47 -0800 (PST) Received: by mail-pl1-x62a.google.com with SMTP id w23so17374039ply.12 for ; Wed, 07 Dec 2022 07:49:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NbsvwgwPR3B757gRns7/stgcrkFvNaKcuShOuGKUmaw=; b=dWibBvBTiVA/84gDobjRgvxVixl764pEHsZqeOQjsQTYcSLe2AY2xlkKC1Imw+7IV2 PoFF7j9IoX6GzTzxhWS5x5nv3blYhAWDvnhY/ykRnnBQF3Y3rS372HPWrCicpAQYKQ4/ NY3okmtSv8f4TkrJddqps6OldgMeuk8K3hlFY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=NbsvwgwPR3B757gRns7/stgcrkFvNaKcuShOuGKUmaw=; b=PeHiIQPR1C2Yjef6b7jdLAlgbeWjCTQteEMIGgyN3qboMD5+GKyAgktIVjZhYIO3dT x+uivdT/yO5B/Ia7GKzzhmouAGkvaIlQJDdWaz8VfIhd8I1+TVJx8gF1fi6TO8uLJif/ TLlVcvIv/yqzwCnyCmO5gFrJ45BZJiyPU5KoF9I0tn7n/kvkCcaRMqc8v8V1eW6nsfEN cTfojJUmlaICdAYodOblTRskdIT8RSgVqGQrQ08DyiEQbys6XiXXdgbPO9S187E/rXEh Gk1oPE7NkWic/rGouTO6O0Je+wRpR3CvN5CDslnVFSmg3GVRVs2Y8W5Dhdx3HOJoPSGf +Ntg== X-Gm-Message-State: ANoB5plgnQOu2+jJDa+ejI4GEGeTTQuBtPr97+XMaBYnIeOehIAeCvGC bdoRAQzygvJNbnb6VgNX+4e1BvtWWuIqhZTx X-Received: by 2002:a17:903:40cb:b0:189:b4d0:aee with SMTP id t11-20020a17090340cb00b00189b4d00aeemr756372pld.67.1670428186688; Wed, 07 Dec 2022 07:49:46 -0800 (PST) Received: from jeffxud.c.googlers.com.com (30.202.168.34.bc.googleusercontent.com. [34.168.202.30]) by smtp.gmail.com with ESMTPSA id a9-20020a170902ecc900b0017f7628cbddsm14920934plh.30.2022.12.07.07.49.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Dec 2022 07:49:46 -0800 (PST) From: jeffxu@chromium.org To: skhan@linuxfoundation.org, keescook@chromium.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, jannh@google.com, linux-hardening@vger.kernel.org Subject: [PATCH v6 2/6] selftests/memfd: add tests for F_SEAL_EXEC Date: Wed, 7 Dec 2022 15:49:35 +0000 Message-Id: <20221207154939.2532830-3-jeffxu@google.com> X-Mailer: git-send-email 2.39.0.rc0.267.gcb52ba06e7-goog In-Reply-To: <20221207154939.2532830-1-jeffxu@google.com> References: <20221207154939.2532830-1-jeffxu@google.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751571000453306544?= X-GMAIL-MSGID: =?utf-8?q?1751571000453306544?= From: Daniel Verkamp Basic tests to ensure that user/group/other execute bits cannot be changed after applying F_SEAL_EXEC to a memfd. Signed-off-by: Daniel Verkamp Co-developed-by: Jeff Xu Signed-off-by: Jeff Xu Reviewed-by: Kees Cook --- tools/testing/selftests/memfd/memfd_test.c | 129 ++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c index 94df2692e6e4..1d7e7b36bbdd 100644 --- a/tools/testing/selftests/memfd/memfd_test.c +++ b/tools/testing/selftests/memfd/memfd_test.c @@ -28,12 +28,44 @@ #define MFD_DEF_SIZE 8192 #define STACK_SIZE 65536 +#ifndef F_SEAL_EXEC +#define F_SEAL_EXEC 0x0020 +#endif + +#ifndef MAX_PATH +#define MAX_PATH 256 +#endif + /* * Default is not to test hugetlbfs */ static size_t mfd_def_size = MFD_DEF_SIZE; static const char *memfd_str = MEMFD_STR; +static ssize_t fd2name(int fd, char *buf, size_t bufsize) +{ + char buf1[MAX_PATH]; + int size; + ssize_t nbytes; + + size = snprintf(buf1, MAX_PATH, "/proc/self/fd/%d", fd); + if (size < 0) { + printf("snprintf(%d) failed on %m\n", fd); + abort(); + } + + /* + * reserver one byte for string termination. + */ + nbytes = readlink(buf1, buf, bufsize-1); + if (nbytes == -1) { + printf("readlink(%s) failed %m\n", buf1); + abort(); + } + buf[nbytes] = '\0'; + return nbytes; +} + static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags) { int r, fd; @@ -98,11 +130,14 @@ static unsigned int mfd_assert_get_seals(int fd) static void mfd_assert_has_seals(int fd, unsigned int seals) { + char buf[MAX_PATH]; + int nbytes; unsigned int s; + fd2name(fd, buf, MAX_PATH); s = mfd_assert_get_seals(fd); if (s != seals) { - printf("%u != %u = GET_SEALS(%d)\n", seals, s, fd); + printf("%u != %u = GET_SEALS(%s)\n", seals, s, buf); abort(); } } @@ -594,6 +629,64 @@ static void mfd_fail_grow_write(int fd) } } +static void mfd_assert_mode(int fd, int mode) +{ + struct stat st; + char buf[MAX_PATH]; + int nbytes; + + fd2name(fd, buf, MAX_PATH); + + if (fstat(fd, &st) < 0) { + printf("fstat(%s) failed: %m\n", buf); + abort(); + } + + if ((st.st_mode & 07777) != mode) { + printf("fstat(%s) wrong file mode 0%04o, but expected 0%04o\n", + buf, (int)st.st_mode & 07777, mode); + abort(); + } +} + +static void mfd_assert_chmod(int fd, int mode) +{ + char buf[MAX_PATH]; + int nbytes; + + fd2name(fd, buf, MAX_PATH); + + if (fchmod(fd, mode) < 0) { + printf("fchmod(%s, 0%04o) failed: %m\n", buf, mode); + abort(); + } + + mfd_assert_mode(fd, mode); +} + +static void mfd_fail_chmod(int fd, int mode) +{ + struct stat st; + char buf[MAX_PATH]; + int nbytes; + + fd2name(fd, buf, MAX_PATH); + + if (fstat(fd, &st) < 0) { + printf("fstat(%s) failed: %m\n", buf); + abort(); + } + + if (fchmod(fd, mode) == 0) { + printf("fchmod(%s, 0%04o) didn't fail as expected\n", + buf, mode); + abort(); + } + + /* verify that file mode bits did not change */ + mfd_assert_mode(fd, st.st_mode & 07777); +} + static int idle_thread_fn(void *arg) { sigset_t set; @@ -880,6 +973,39 @@ static void test_seal_resize(void) close(fd); } +/* + * Test SEAL_EXEC + * Test that chmod() cannot change x bits after sealing + */ +static void test_seal_exec(void) +{ + int fd; + + printf("%s SEAL-EXEC\n", memfd_str); + + fd = mfd_assert_new("kern_memfd_seal_exec", + mfd_def_size, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + + mfd_assert_mode(fd, 0777); + + mfd_assert_chmod(fd, 0644); + + mfd_assert_has_seals(fd, 0); + mfd_assert_add_seals(fd, F_SEAL_EXEC); + mfd_assert_has_seals(fd, F_SEAL_EXEC); + + mfd_assert_chmod(fd, 0600); + mfd_fail_chmod(fd, 0777); + mfd_fail_chmod(fd, 0670); + mfd_fail_chmod(fd, 0605); + mfd_fail_chmod(fd, 0700); + mfd_fail_chmod(fd, 0100); + mfd_assert_chmod(fd, 0666); + + close(fd); +} + /* * Test sharing via dup() * Test that seals are shared between dupped FDs and they're all equal. @@ -1059,6 +1185,7 @@ int main(int argc, char **argv) test_seal_shrink(); test_seal_grow(); test_seal_resize(); + test_seal_exec(); test_share_dup("SHARE-DUP", ""); test_share_mmap("SHARE-MMAP", ""); From patchwork Wed Dec 7 15:49:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 30903 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp260377wrr; Wed, 7 Dec 2022 07:51:34 -0800 (PST) X-Google-Smtp-Source: AA0mqf4ULw8B8QjUWmjD4yoLsbufugBkXvTrAERRgFzuM/1aAbokAJ+Bimjf7ZEySm9yV1NpPA0b X-Received: by 2002:a17:906:5e55:b0:7c0:cfc5:dd0c with SMTP id b21-20020a1709065e5500b007c0cfc5dd0cmr17949993eju.743.1670428293955; Wed, 07 Dec 2022 07:51:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670428293; cv=none; d=google.com; s=arc-20160816; b=HW+LDflL8+zqfM/RvSyTgVPIX8YI6UTimfezWEC6L4xcl3b6qtviAK+niNEkewYkLz gfT2GkJdY3QDYSPjU23VOU6pcUQeHcbm/tlRU+F6b5zNhtMbcvMRip7AoxQLpMiBOPH9 NW/JitPoHHUoWF6E4lOyOq0msmn0R2UdOxayCM4+dS2x2HMCJGO2hBprc/lqgWHB1Jgw pAMSFbdmH65/ggEX5iuTj4Z3sLJdePTUQrUKS+jiCH2/LAg7GC5jsYMbwXTeQOCM0NLT EgS45acbgePKzCIBPD0rVN/4Jq7YEB3oqlAImW8i6/GkqsmxFdNQC5dsUB+rZLRg8rvY GAgA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=j02hcUmpYLv5fRuUpSeXXOL/JCHtO2qkj12Q1X4RZAg=; b=WgF9Y/iKKLgU7lRXGA+r26oKHsqELhQ+Hg1cmn5lDP7FiynG90GEsyniar1TIn/VOH bpfT8O+P8kZqv9JwkC5iTgqlRtY6JliRNvY4CUlFjLmBt0cWImTqrDEo4W6exzxMTVs7 ol5CLrsaFc9LhBWzlh5NfadByJB/mIq+bZ6RMYYh8ZXiu8+RRj+5Cua9O5p4Q1DKjvIr LH03Vn71U0kQjE5DuC0bOxuefLWNrweA88ZDDLr6NTfjpuX7JxajiuNImPU3w+CbDS3V vRkj1hfTwlqlWYp1pmK2PlJiH3OeP1CV6JPsvPuxsuY89+SOISXtGi9G5Hb/VVwZIeMx PuzA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=R5BHpK7Z; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id tz14-20020a170907c78e00b0078e1d213812si13724635ejc.184.2022.12.07.07.51.10; Wed, 07 Dec 2022 07:51:33 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=R5BHpK7Z; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229911AbiLGPuI (ORCPT + 99 others); Wed, 7 Dec 2022 10:50:08 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50628 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229819AbiLGPtt (ORCPT ); Wed, 7 Dec 2022 10:49:49 -0500 Received: from mail-pj1-x102c.google.com (mail-pj1-x102c.google.com [IPv6:2607:f8b0:4864:20::102c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2DE1060B47 for ; Wed, 7 Dec 2022 07:49:48 -0800 (PST) Received: by mail-pj1-x102c.google.com with SMTP id u5so8621868pjy.5 for ; Wed, 07 Dec 2022 07:49:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=j02hcUmpYLv5fRuUpSeXXOL/JCHtO2qkj12Q1X4RZAg=; b=R5BHpK7ZG9aovJ+1jeInMWGBsCCU+DnF25bMLAW45g60cIzG8FFjGMOXE+YWkWnupK kQHfR+uCW3ib+lGzbzFcJTQMcw+b6mTj+yo7v+J3Y5PsUrokernH9eTgmzS5L2ZyHQPx He6qg6g0nzNS1MVsYGfSwJbIUQhYQcP1HAQvE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=j02hcUmpYLv5fRuUpSeXXOL/JCHtO2qkj12Q1X4RZAg=; b=Wv5JlTAPsow0UyR6HhW2K15nG4LJOJNvRVBvXS5K7NQPvTyHKIWEOqDXJoLXOciHM1 E+L3sFK3ha+GwaZb2H+yz943wZnaTtpwhzbX01QK2PWSPDL4yAGbSPXY0MUgvu9bO8oI DmXuASuEcSzY54+HKRsbXr0XAUb5QYdsQYhiqmwSNfRYm+RIs3GvuwKqpt6/yi5DCjkx R+y70iuvSYapIPmZB97a/ozvvUwhwMkRjEYyoxvsTHO2pn0/drX7GWUGfVj4I1zqqFWV tfN+isC55V6bWdt6wR50dgYKAvdZL8X9d/Iwajzdsb4e32/oOVHYl/lyy473UBhg3fI5 bykw== X-Gm-Message-State: ANoB5pnf7gxLgLUSaco02zhYm5tgYTEpGJzE5UuO2MgL7IoprTiBgFCM 80RIgwHfZJOG0iNQRlTdavduSg== X-Received: by 2002:a17:902:9891:b0:189:2688:c97f with SMTP id s17-20020a170902989100b001892688c97fmr690338plp.50.1670428187656; Wed, 07 Dec 2022 07:49:47 -0800 (PST) Received: from jeffxud.c.googlers.com.com (30.202.168.34.bc.googleusercontent.com. [34.168.202.30]) by smtp.gmail.com with ESMTPSA id a9-20020a170902ecc900b0017f7628cbddsm14920934plh.30.2022.12.07.07.49.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Dec 2022 07:49:46 -0800 (PST) From: jeffxu@chromium.org To: skhan@linuxfoundation.org, keescook@chromium.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, jannh@google.com, linux-hardening@vger.kernel.org, kernel test robot Subject: [PATCH v6 3/6] mm/memfd: add MFD_NOEXEC_SEAL and MFD_EXEC Date: Wed, 7 Dec 2022 15:49:36 +0000 Message-Id: <20221207154939.2532830-4-jeffxu@google.com> X-Mailer: git-send-email 2.39.0.rc0.267.gcb52ba06e7-goog In-Reply-To: <20221207154939.2532830-1-jeffxu@google.com> References: <20221207154939.2532830-1-jeffxu@google.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751571018444711132?= X-GMAIL-MSGID: =?utf-8?q?1751571018444711132?= From: Jeff Xu The new MFD_NOEXEC_SEAL and MFD_EXEC flags allows application to set executable bit at creation time (memfd_create). When MFD_NOEXEC_SEAL is set, memfd is created without executable bit (mode:0666), and sealed with F_SEAL_EXEC, so it can't be chmod to be executable (mode: 0777) after creation. when MFD_EXEC flag is set, memfd is created with executable bit (mode:0777), this is the same as the old behavior of memfd_create. The new pid namespaced sysctl vm.memfd_noexec has 3 values: 0: memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL acts like MFD_EXEC was set. 1: memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL acts like MFD_NOEXEC_SEAL was set. 2: memfd_create() without MFD_NOEXEC_SEAL will be rejected. The sysctl allows finer control of memfd_create for old-software that doesn't set the executable bit, for example, a container with vm.memfd_noexec=1 means the old-software will create non-executable memfd by default. Also, the value of memfd_noexec is passed to child namespace at creation time. For example, if the init namespace has vm.memfd_noexec=2, all its children namespaces will be created with 2. Signed-off-by: Jeff Xu Co-developed-by: Daniel Verkamp Signed-off-by: Daniel Verkamp Reported-by: kernel test robot --- include/linux/pid_namespace.h | 19 +++++++++++ include/uapi/linux/memfd.h | 4 +++ kernel/pid_namespace.c | 5 +++ kernel/pid_sysctl.h | 59 +++++++++++++++++++++++++++++++++++ mm/memfd.c | 48 ++++++++++++++++++++++++++-- 5 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 kernel/pid_sysctl.h diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index 07481bb87d4e..a4789a7b34a9 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -16,6 +16,21 @@ struct fs_pin; +#if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE) +/* + * sysctl for vm.memfd_noexec + * 0: memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL + * acts like MFD_EXEC was set. + * 1: memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL + * acts like MFD_NOEXEC_SEAL was set. + * 2: memfd_create() without MFD_NOEXEC_SEAL will be + * rejected. + */ +#define MEMFD_NOEXEC_SCOPE_EXEC 0 +#define MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL 1 +#define MEMFD_NOEXEC_SCOPE_NOEXEC_ENFORCED 2 +#endif + struct pid_namespace { struct idr idr; struct rcu_head rcu; @@ -31,6 +46,10 @@ struct pid_namespace { struct ucounts *ucounts; int reboot; /* group exit code if this pidns was rebooted */ struct ns_common ns; +#if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE) + /* sysctl for vm.memfd_noexec */ + int memfd_noexec_scope; +#endif } __randomize_layout; extern struct pid_namespace init_pid_ns; diff --git a/include/uapi/linux/memfd.h b/include/uapi/linux/memfd.h index 7a8a26751c23..273a4e15dfcf 100644 --- a/include/uapi/linux/memfd.h +++ b/include/uapi/linux/memfd.h @@ -8,6 +8,10 @@ #define MFD_CLOEXEC 0x0001U #define MFD_ALLOW_SEALING 0x0002U #define MFD_HUGETLB 0x0004U +/* not executable and sealed to prevent changing to executable. */ +#define MFD_NOEXEC_SEAL 0x0008U +/* executable */ +#define MFD_EXEC 0x0010U /* * Huge page size encoding when MFD_HUGETLB is specified, and a huge page diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index f4f8cb0435b4..8a98b1af9376 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -23,6 +23,7 @@ #include #include #include +#include "pid_sysctl.h" static DEFINE_MUTEX(pid_caches_mutex); static struct kmem_cache *pid_ns_cachep; @@ -110,6 +111,8 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns ns->ucounts = ucounts; ns->pid_allocated = PIDNS_ADDING; + initialize_memfd_noexec_scope(ns); + return ns; out_free_idr: @@ -455,6 +458,8 @@ static __init int pid_namespaces_init(void) #ifdef CONFIG_CHECKPOINT_RESTORE register_sysctl_paths(kern_path, pid_ns_ctl_table); #endif + + register_pid_ns_sysctl_table_vm(); return 0; } diff --git a/kernel/pid_sysctl.h b/kernel/pid_sysctl.h new file mode 100644 index 000000000000..5986d6493b5b --- /dev/null +++ b/kernel/pid_sysctl.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_PID_SYSCTL_H +#define LINUX_PID_SYSCTL_H + +#include + +#if defined(CONFIG_SYSCTL) && defined(CONFIG_MEMFD_CREATE) +static inline void initialize_memfd_noexec_scope(struct pid_namespace *ns) +{ + ns->memfd_noexec_scope = + task_active_pid_ns(current)->memfd_noexec_scope; +} + +static int pid_mfd_noexec_dointvec_minmax(struct ctl_table *table, + int write, void *buf, size_t *lenp, loff_t *ppos) +{ + struct pid_namespace *ns = task_active_pid_ns(current); + struct ctl_table table_copy; + + if (write && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + table_copy = *table; + if (ns != &init_pid_ns) + table_copy.data = &ns->memfd_noexec_scope; + + /* + * set minimum to current value, the effect is only bigger + * value is accepted. + */ + if (*(int *)table_copy.data > *(int *)table_copy.extra1) + table_copy.extra1 = table_copy.data; + + return proc_dointvec_minmax(&table_copy, write, buf, lenp, ppos); +} + +static struct ctl_table pid_ns_ctl_table_vm[] = { + { + .procname = "memfd_noexec", + .data = &init_pid_ns.memfd_noexec_scope, + .maxlen = sizeof(init_pid_ns.memfd_noexec_scope), + .mode = 0644, + .proc_handler = pid_mfd_noexec_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_TWO, + }, + { } +}; +static struct ctl_path vm_path[] = { { .procname = "vm", }, { } }; +static inline void register_pid_ns_sysctl_table_vm(void) +{ + register_sysctl_paths(vm_path, pid_ns_ctl_table_vm); +} +#else +static inline void set_memfd_noexec_scope(struct pid_namespace *ns) {} +static inline void register_pid_ns_ctl_table_vm(void) {} +#endif + +#endif /* LINUX_PID_SYSCTL_H */ diff --git a/mm/memfd.c b/mm/memfd.c index 4ebeab94aa74..ec70675a7069 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -18,6 +18,7 @@ #include #include #include +#include #include /* @@ -263,12 +264,14 @@ long memfd_fcntl(struct file *file, unsigned int cmd, unsigned long arg) #define MFD_NAME_PREFIX_LEN (sizeof(MFD_NAME_PREFIX) - 1) #define MFD_NAME_MAX_LEN (NAME_MAX - MFD_NAME_PREFIX_LEN) -#define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB) +#define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | MFD_NOEXEC_SEAL | MFD_EXEC) SYSCALL_DEFINE2(memfd_create, const char __user *, uname, unsigned int, flags) { + char comm[TASK_COMM_LEN]; + struct pid_namespace *ns; unsigned int *file_seals; struct file *file; int fd, error; @@ -285,6 +288,39 @@ SYSCALL_DEFINE2(memfd_create, return -EINVAL; } + /* Invalid if both EXEC and NOEXEC_SEAL are set.*/ + if ((flags & MFD_EXEC) && (flags & MFD_NOEXEC_SEAL)) + return -EINVAL; + + if (!(flags & (MFD_EXEC | MFD_NOEXEC_SEAL))) { +#ifdef CONFIG_SYSCTL + int sysctl = MEMFD_NOEXEC_SCOPE_EXEC; + + ns = task_active_pid_ns(current); + if (ns) + sysctl = ns->memfd_noexec_scope; + + switch (sysctl) { + case MEMFD_NOEXEC_SCOPE_EXEC: + flags |= MFD_EXEC; + break; + case MEMFD_NOEXEC_SCOPE_NOEXEC_SEAL: + flags |= MFD_NOEXEC_SEAL; + break; + default: + pr_warn_ratelimited( + "memfd_create(): MFD_NOEXEC_SEAL is enforced, pid=%d '%s'\n", + task_pid_nr(current), get_task_comm(comm, current)); + return -EINVAL; + } +#else + flags |= MFD_EXEC; +#endif + pr_warn_ratelimited( + "memfd_create() without MFD_EXEC nor MFD_NOEXEC_SEAL, pid=%d '%s'\n", + task_pid_nr(current), get_task_comm(comm, current)); + } + /* length includes terminating zero */ len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1); if (len <= 0) @@ -328,7 +364,15 @@ SYSCALL_DEFINE2(memfd_create, file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; file->f_flags |= O_LARGEFILE; - if (flags & MFD_ALLOW_SEALING) { + if (flags & MFD_NOEXEC_SEAL) { + struct inode *inode = file_inode(file); + + inode->i_mode &= ~0111; + file_seals = memfd_file_seals_ptr(file); + *file_seals &= ~F_SEAL_SEAL; + *file_seals |= F_SEAL_EXEC; + } else if (flags & MFD_ALLOW_SEALING) { + /* MFD_EXEC and MFD_ALLOW_SEALING are set */ file_seals = memfd_file_seals_ptr(file); *file_seals &= ~F_SEAL_SEAL; } From patchwork Wed Dec 7 15:49:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 30904 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp260476wrr; Wed, 7 Dec 2022 07:51:44 -0800 (PST) X-Google-Smtp-Source: AA0mqf4bCzjRXswfFPsg3Zphr/jId2Sb2medOTjDE6/SLpbJd2OB5P/XSjvsmpWbVwqcjuBgnGat X-Received: by 2002:aa7:c2d6:0:b0:46c:38a4:a54c with SMTP id m22-20020aa7c2d6000000b0046c38a4a54cmr19493914edp.393.1670428304449; Wed, 07 Dec 2022 07:51:44 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670428304; cv=none; d=google.com; s=arc-20160816; b=pNqWsx29jeA6r1bAEth3pcrMuMhdaeFqzXtQvdw73BKP2QOdEEHKhHvpfGr6F2lnK1 K7rO54c6V1/If4+8nXxPRIkffIr/xg5W4e+3irHiYcY3ZmDC8wLTcSl0m8LoKi/xGwvl CLPfoo4YelmJqnsBqC1JYw7pUgwaMy7RJvt+YnQWUYlj9kUIvjVefUqXcW8Pg6rd9H+i RGqRnRXSNK651F5pLU/e/il6Eq9M3dx5WP/y/wqi2oeEdIaKFVnfF0yJ/vaOQuiJeQp4 iU5FTxnKjioHE4b7lluMqClnvhU5hCLCRmc4JCya+6D7swbNlaEhb9lSCfQyaREJaByc IM4w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=68tZIB+0aYpPIylSIqK6cc/meXXHAi0u5AcBKUyeGcY=; b=ktlXzAQ2Ek8KO6MvHufYTdnafQB75BudyQJ0mKwWE14uS9QcW9yPqwC9PlJrMMqPt0 O1uwPrwQi0JGwfLtPf+EPl4i/rsu0lo625nj4gzQh+kB8V03W/fh3dwUiUvA8n45koPX IhML+gEYMJ+pgfsO9XGgJZIYVj8IaSkfQ6iSPgNyU5O2HI6U5TUI4gt4Y9reULMvITK6 lQES7P8GbqAZ5t4bqITqNALww5Poq/YdQptMb/F5GmPdDmX1bG05GJKYQOO/iV/W86X7 9GKTYsOq6V37jyYngvEgyYJL8aES4nfiJZrq6xmRGef9t8+iOdav0LB5pyc5TSMs5kwu ap7g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=Pgcz8EqF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ht10-20020a170907608a00b0078db3762061si7906093ejc.439.2022.12.07.07.51.19; Wed, 07 Dec 2022 07:51:44 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=Pgcz8EqF; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229866AbiLGPuN (ORCPT + 99 others); Wed, 7 Dec 2022 10:50:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50422 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229828AbiLGPtt (ORCPT ); Wed, 7 Dec 2022 10:49:49 -0500 Received: from mail-pl1-x631.google.com (mail-pl1-x631.google.com [IPv6:2607:f8b0:4864:20::631]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0BC6C326DF for ; Wed, 7 Dec 2022 07:49:49 -0800 (PST) Received: by mail-pl1-x631.google.com with SMTP id s7so17386578plk.5 for ; Wed, 07 Dec 2022 07:49:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=68tZIB+0aYpPIylSIqK6cc/meXXHAi0u5AcBKUyeGcY=; b=Pgcz8EqFIllSIrbiyT8+zFROC9GpuYiPrYWAWuws/ZAml4A7Ugasa59H8dzt4twoB4 O0cAxxO9Mke403E/Mj+rjoT+GeN92NHh57bpsegW33gdWlb7tQAmt+ewJoJYOEJvEyeH jGBefsgqUB3ZHzuky+3uRwszEnFjlO/ZS+68A= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=68tZIB+0aYpPIylSIqK6cc/meXXHAi0u5AcBKUyeGcY=; b=c+56RN1229YtQJ1AO9WUr8K7/1VI24Sfek6I1/Ec+Ny4zTwpDaJRcer35OaOO6gv8s lflXc6juRLtA5RzFRGFAmWHG1hxgXvQUFg2Ol5TD/BC4WqBEsEbqNcQzBn6HB+UNjLI8 upDeWUCbu/yb2zPMgiPySR3yflYxRwQjtYe5M+t17Pzgw8hJvHT9bHOAcE0Qyd2mEKxf 8ARWpd2oYr+GgMGb7+7dnDz2o9rLK4Vf1xrKLIPEFNCVyEl3bmx0rK51DvkDqCbX9Btu 67noElESMiyiCC7793QsB8cSBmSvWePmOQXRQLIgJ+FuPAvUmM1bryap78B71DY59rBw ecrA== X-Gm-Message-State: ANoB5plXP6cjVAkEP167xdP2Lm5rEh15OKKTBHV+VrTpW2Goe8pYqJVT f78DnGRTVK/VWi1qo98N52lwZQ== X-Received: by 2002:a05:6a21:9991:b0:a4:5f8d:805a with SMTP id ve17-20020a056a21999100b000a45f8d805amr1331414pzb.53.1670428188610; Wed, 07 Dec 2022 07:49:48 -0800 (PST) Received: from jeffxud.c.googlers.com.com (30.202.168.34.bc.googleusercontent.com. [34.168.202.30]) by smtp.gmail.com with ESMTPSA id a9-20020a170902ecc900b0017f7628cbddsm14920934plh.30.2022.12.07.07.49.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Dec 2022 07:49:47 -0800 (PST) From: jeffxu@chromium.org To: skhan@linuxfoundation.org, keescook@chromium.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, jannh@google.com, linux-hardening@vger.kernel.org Subject: [PATCH v6 4/6] mm/memfd: Add write seals when apply SEAL_EXEC to executable memfd Date: Wed, 7 Dec 2022 15:49:37 +0000 Message-Id: <20221207154939.2532830-5-jeffxu@google.com> X-Mailer: git-send-email 2.39.0.rc0.267.gcb52ba06e7-goog In-Reply-To: <20221207154939.2532830-1-jeffxu@google.com> References: <20221207154939.2532830-1-jeffxu@google.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751571029793767763?= X-GMAIL-MSGID: =?utf-8?q?1751571029793767763?= From: Jeff Xu In order to avoid WX mappings, add F_SEAL_WRITE when apply F_SEAL_EXEC to an executable memfd, so W^X from start. This implys application need to fill the content of the memfd first, after F_SEAL_EXEC is applied, application can no longer modify the content of the memfd. Typically, application seals the memfd right after writing to it. For example: 1. memfd_create(MFD_EXEC). 2. write() code to the memfd. 3. fcntl(F_ADD_SEALS, F_SEAL_EXEC) to convert the memfd to W^X. 4. call exec() on the memfd. Signed-off-by: Jeff Xu Reviewed-by: Kees Cook --- mm/memfd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mm/memfd.c b/mm/memfd.c index ec70675a7069..92f0a5765f7c 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -222,6 +222,12 @@ static int memfd_add_seals(struct file *file, unsigned int seals) } } + /* + * SEAL_EXEC implys SEAL_WRITE, making W^X from the start. + */ + if (seals & F_SEAL_EXEC && inode->i_mode & 0111) + seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE; + *file_seals |= seals; error = 0; From patchwork Wed Dec 7 15:49:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 30905 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp260681wrr; Wed, 7 Dec 2022 07:52:10 -0800 (PST) X-Google-Smtp-Source: AA0mqf4C9kdFmE3EgbOjVCiwCR1hKtT+RsouDbY/RFgHLyBtW07bYzp/QdWkicfuSL233ZjX/ZCS X-Received: by 2002:aa7:d911:0:b0:46b:c156:9945 with SMTP id a17-20020aa7d911000000b0046bc1569945mr28694772edr.350.1670428330482; Wed, 07 Dec 2022 07:52:10 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670428330; cv=none; d=google.com; s=arc-20160816; b=o3gNQ+FgNdfc5UPyYDaWKCZmJ/WrLADe7UTd8qJuShthrmBbIDAP9b8oEYXRtxsakM V3VEsnZhYPyk1jh53UUTkQo9O8n9X2xyVp3giJnvkzqScvYrCv8Q3tSVnzXpJnhMuLuW murVAdeeLB9pZ3AR6lnu5nC3Hz0hYHe0RI0L8fySB8WD6r0NQLXYr1jofSTtbjiyvNsh a2JHfXZKQbi7WJottQqbLrH4rKMrZH4A4zDMwdIBI8habVZCvj4Lz9hW/uS+w7B+s6bx c5qLD3PYeTxa7lzNKKZa49i7nkizFO/qOlIbIruMRNXfPU/tNE16RAFyqmSZFVl1WM64 OadA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=KFN1ukpXKxLmNAYkBULVsoTlaw64wakqQaa318EnS7w=; b=RtlTBIop7vk/s8MJKKtY5xfUwx7Wo9sKDtziWCnJtZNAK1uw+A+Vuk73F3zh5JzesO A1rF5b38mvySEyRoMr5Lyqv7ieA1El6km/jfhRQWJW57Q9imbKQz4fxxQ4i+Mw5EI38r duOAL5W91SA8+C0MUugQ6e5vQpruJkJOmFd+mA/A+FaxgDLEAAusuv4oUld3qWJcMfGl XNlCWN36fszIoEMxPOiSNemiJ64rDoD76w0yp6TgqRN6kLvhM7yOQd9u9IKCIo17lN33 mzvDJ5NKVSw2DxgCHFJahLJif0ov8QYTia+eDnz++4y70+mvdQ3AizF9zPDbQzo42xWa 5ARw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=mzrL0wC7; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id cr21-20020a170906d55500b0073d5a794b43si16658781ejc.985.2022.12.07.07.51.46; Wed, 07 Dec 2022 07:52:10 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=mzrL0wC7; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229629AbiLGPuS (ORCPT + 99 others); Wed, 7 Dec 2022 10:50:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50584 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229756AbiLGPtu (ORCPT ); Wed, 7 Dec 2022 10:49:50 -0500 Received: from mail-pl1-x633.google.com (mail-pl1-x633.google.com [IPv6:2607:f8b0:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 193A963BA8 for ; Wed, 7 Dec 2022 07:49:50 -0800 (PST) Received: by mail-pl1-x633.google.com with SMTP id y4so17406955plb.2 for ; Wed, 07 Dec 2022 07:49:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=KFN1ukpXKxLmNAYkBULVsoTlaw64wakqQaa318EnS7w=; b=mzrL0wC7HJZg6H4fg+hl9vB15griUB7WwlNY9n7bcHzWC9Ln1UlmOfqokZnpGBCCzk 9g2xDYSY9rsPj1uzjolhlIwWhChYv22zqyPN5DysMI6Cix18qsA7ESpgAGiOxo1KA90p JBXL2IWPcZJqXOT434+F0e46/gbeZiuZ3sUlk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=KFN1ukpXKxLmNAYkBULVsoTlaw64wakqQaa318EnS7w=; b=IrDUOsD/RbWiHoovjj52SXk7FJmhREQSBkSLVTiZKCJs5GO+E3ysqtH/HFaxboqQEv T9kw1eyeaHWJlZy1pcw/Ex6wScflGCQGlgOkL0Z78yAcQFI7VAB7xv8aXaRus8kUrnkO Ckguu3GNgN9z0WOt/Bd7reickEHWx37OP4ew51XhfqXP+seRc8Fp9Q1YXxbcX7yd531S 7dOvIGwp7UnU0Ctmw/+NkGSmb7L/klQC75+092U7WtTzP80ECKtmgkWrnPVRElqIZ0Rk VFTKyqTpgPeZ9xkwEKoWaVSEss1DVsWVK5N0u3RWe11lvZmgZlBt2S6BzuUyQ8p2Jt8a r+1Q== X-Gm-Message-State: ANoB5pn4GE7QdBAKhTcgpFbP2NMngq4+WQ8wEMw3HPDHwB0EleDSnwLE k9Yy7gWIKHH/h/I4KRxlEVkaCA== X-Received: by 2002:a17:902:8218:b0:189:9ef4:4b59 with SMTP id x24-20020a170902821800b001899ef44b59mr685624pln.52.1670428189559; Wed, 07 Dec 2022 07:49:49 -0800 (PST) Received: from jeffxud.c.googlers.com.com (30.202.168.34.bc.googleusercontent.com. [34.168.202.30]) by smtp.gmail.com with ESMTPSA id a9-20020a170902ecc900b0017f7628cbddsm14920934plh.30.2022.12.07.07.49.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Dec 2022 07:49:48 -0800 (PST) From: jeffxu@chromium.org To: skhan@linuxfoundation.org, keescook@chromium.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, jannh@google.com, linux-hardening@vger.kernel.org Subject: [PATCH v6 5/6] selftests/memfd: add tests for MFD_NOEXEC_SEAL MFD_EXEC Date: Wed, 7 Dec 2022 15:49:38 +0000 Message-Id: <20221207154939.2532830-6-jeffxu@google.com> X-Mailer: git-send-email 2.39.0.rc0.267.gcb52ba06e7-goog In-Reply-To: <20221207154939.2532830-1-jeffxu@google.com> References: <20221207154939.2532830-1-jeffxu@google.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751571057076741737?= X-GMAIL-MSGID: =?utf-8?q?1751571057076741737?= From: Jeff Xu Tests to verify MFD_NOEXEC, MFD_EXEC and vm.memfd_noexec sysctl. Co-developed-by: Daniel Verkamp Signed-off-by: Daniel Verkamp Signed-off-by: Jeff Xu Reviewed-by: Kees Cook --- tools/testing/selftests/memfd/fuse_test.c | 1 + tools/testing/selftests/memfd/memfd_test.c | 229 ++++++++++++++++++++- 2 files changed, 225 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/memfd/fuse_test.c b/tools/testing/selftests/memfd/fuse_test.c index be675002f918..93798c8c5d54 100644 --- a/tools/testing/selftests/memfd/fuse_test.c +++ b/tools/testing/selftests/memfd/fuse_test.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c index 1d7e7b36bbdd..cbf1768fb1b9 100644 --- a/tools/testing/selftests/memfd/memfd_test.c +++ b/tools/testing/selftests/memfd/memfd_test.c @@ -32,10 +32,19 @@ #define F_SEAL_EXEC 0x0020 #endif +#define F_WX_SEALS (F_SEAL_SHRINK | \ + F_SEAL_GROW | \ + F_SEAL_WRITE | \ + F_SEAL_FUTURE_WRITE | \ + F_SEAL_EXEC) #ifndef MAX_PATH #define MAX_PATH 256 #endif +#ifndef MFD_NOEXEC_SEAL +#define MFD_NOEXEC_SEAL 0x0008U +#endif + /* * Default is not to test hugetlbfs */ @@ -86,6 +95,37 @@ static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags) return fd; } +static void sysctl_assert_write(const char *val) +{ + int fd = open("/proc/sys/vm/memfd_noexec", O_WRONLY | O_CLOEXEC); + + if (fd < 0) { + printf("open sysctl failed\n"); + abort(); + } + + if (write(fd, val, strlen(val)) < 0) { + printf("write sysctl failed\n"); + abort(); + } +} + +static void sysctl_fail_write(const char *val) +{ + int fd = open("/proc/sys/vm/memfd_noexec", O_WRONLY | O_CLOEXEC); + + if (fd < 0) { + printf("open sysctl failed\n"); + abort(); + } + + if (write(fd, val, strlen(val)) >= 0) { + printf("write sysctl %s succeeded, but failure expected\n", + val); + abort(); + } +} + static int mfd_assert_reopen_fd(int fd_in) { int fd; @@ -764,6 +804,9 @@ static void test_create(void) mfd_fail_new("", ~0); mfd_fail_new("", 0x80000000U); + /* verify EXEC and NOEXEC_SEAL can't both be set */ + mfd_fail_new("", MFD_EXEC | MFD_NOEXEC_SEAL); + /* verify MFD_CLOEXEC is allowed */ fd = mfd_assert_new("", 0, MFD_CLOEXEC); close(fd); @@ -975,20 +1018,21 @@ static void test_seal_resize(void) /* * Test SEAL_EXEC - * Test that chmod() cannot change x bits after sealing + * Test fd is created with exec and allow sealing. + * chmod() cannot change x bits after sealing. */ -static void test_seal_exec(void) +static void test_exec_seal(void) { int fd; printf("%s SEAL-EXEC\n", memfd_str); + printf("%s Apply SEAL_EXEC\n", memfd_str); fd = mfd_assert_new("kern_memfd_seal_exec", mfd_def_size, - MFD_CLOEXEC | MFD_ALLOW_SEALING); + MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_EXEC); mfd_assert_mode(fd, 0777); - mfd_assert_chmod(fd, 0644); mfd_assert_has_seals(fd, 0); @@ -1002,10 +1046,181 @@ static void test_seal_exec(void) mfd_fail_chmod(fd, 0700); mfd_fail_chmod(fd, 0100); mfd_assert_chmod(fd, 0666); + mfd_assert_write(fd); + close(fd); + + printf("%s Apply ALL_SEALS\n", memfd_str); + fd = mfd_assert_new("kern_memfd_seal_exec", + mfd_def_size, + MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_EXEC); + + mfd_assert_mode(fd, 0777); + mfd_assert_chmod(fd, 0700); + + mfd_assert_has_seals(fd, 0); + mfd_assert_add_seals(fd, F_SEAL_EXEC); + mfd_assert_has_seals(fd, F_WX_SEALS); + mfd_fail_chmod(fd, 0711); + mfd_fail_chmod(fd, 0600); + mfd_fail_write(fd); + close(fd); +} + +/* + * Test EXEC_NO_SEAL + * Test fd is created with exec and not allow sealing. + */ +static void test_exec_no_seal(void) +{ + int fd; + + printf("%s EXEC_NO_SEAL\n", memfd_str); + + /* Create with EXEC but without ALLOW_SEALING */ + fd = mfd_assert_new("kern_memfd_exec_no_sealing", + mfd_def_size, + MFD_CLOEXEC | MFD_EXEC); + mfd_assert_mode(fd, 0777); + mfd_assert_has_seals(fd, F_SEAL_SEAL); + mfd_assert_chmod(fd, 0666); close(fd); } +/* + * Test memfd_create with MFD_NOEXEC flag + */ +static void test_noexec_seal(void) +{ + int fd; + + printf("%s NOEXEC_SEAL\n", memfd_str); + + /* Create with NOEXEC and ALLOW_SEALING */ + fd = mfd_assert_new("kern_memfd_noexec", + mfd_def_size, + MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL); + mfd_assert_mode(fd, 0666); + mfd_assert_has_seals(fd, F_SEAL_EXEC); + mfd_fail_chmod(fd, 0777); + close(fd); + + /* Create with NOEXEC but without ALLOW_SEALING */ + fd = mfd_assert_new("kern_memfd_noexec", + mfd_def_size, + MFD_CLOEXEC | MFD_NOEXEC_SEAL); + mfd_assert_mode(fd, 0666); + mfd_assert_has_seals(fd, F_SEAL_EXEC); + mfd_fail_chmod(fd, 0777); + close(fd); +} + +static void test_sysctl_child(void) +{ + int fd; + + printf("%s sysctl 0\n", memfd_str); + sysctl_assert_write("0"); + fd = mfd_assert_new("kern_memfd_sysctl_0", + mfd_def_size, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + + mfd_assert_mode(fd, 0777); + mfd_assert_has_seals(fd, 0); + mfd_assert_chmod(fd, 0644); + close(fd); + + printf("%s sysctl 1\n", memfd_str); + sysctl_assert_write("1"); + fd = mfd_assert_new("kern_memfd_sysctl_1", + mfd_def_size, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + + mfd_assert_mode(fd, 0666); + mfd_assert_has_seals(fd, F_SEAL_EXEC); + mfd_fail_chmod(fd, 0777); + sysctl_fail_write("0"); + close(fd); + + printf("%s sysctl 2\n", memfd_str); + sysctl_assert_write("2"); + mfd_fail_new("kern_memfd_sysctl_2", + MFD_CLOEXEC | MFD_ALLOW_SEALING); + sysctl_fail_write("0"); + sysctl_fail_write("1"); +} + +static int newpid_thread_fn(void *arg) +{ + test_sysctl_child(); + return 0; +} + +static void test_sysctl_child2(void) +{ + int fd; + + sysctl_fail_write("0"); + fd = mfd_assert_new("kern_memfd_sysctl_1", + mfd_def_size, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + + mfd_assert_mode(fd, 0666); + mfd_assert_has_seals(fd, F_SEAL_EXEC); + mfd_fail_chmod(fd, 0777); + close(fd); +} + +static int newpid_thread_fn2(void *arg) +{ + test_sysctl_child2(); + return 0; +} +static pid_t spawn_newpid_thread(unsigned int flags, int (*fn)(void *)) +{ + uint8_t *stack; + pid_t pid; + + stack = malloc(STACK_SIZE); + if (!stack) { + printf("malloc(STACK_SIZE) failed: %m\n"); + abort(); + } + + pid = clone(fn, + stack + STACK_SIZE, + SIGCHLD | flags, + NULL); + if (pid < 0) { + printf("clone() failed: %m\n"); + abort(); + } + + return pid; +} + +static void join_newpid_thread(pid_t pid) +{ + waitpid(pid, NULL, 0); +} + +/* + * Test sysctl + * A very basic sealing test to see whether setting/retrieving seals works. + */ +static void test_sysctl(void) +{ + int pid = spawn_newpid_thread(CLONE_NEWPID, newpid_thread_fn); + + join_newpid_thread(pid); + + printf("%s child ns\n", memfd_str); + sysctl_assert_write("1"); + + pid = spawn_newpid_thread(CLONE_NEWPID, newpid_thread_fn2); + join_newpid_thread(pid); +} + /* * Test sharing via dup() * Test that seals are shared between dupped FDs and they're all equal. @@ -1179,13 +1394,15 @@ int main(int argc, char **argv) test_create(); test_basic(); + test_exec_seal(); + test_exec_no_seal(); + test_noexec_seal(); test_seal_write(); test_seal_future_write(); test_seal_shrink(); test_seal_grow(); test_seal_resize(); - test_seal_exec(); test_share_dup("SHARE-DUP", ""); test_share_mmap("SHARE-MMAP", ""); @@ -1201,6 +1418,8 @@ int main(int argc, char **argv) test_share_fork("SHARE-FORK", SHARED_FT_STR); join_idle_thread(pid); + test_sysctl(); + printf("memfd: DONE\n"); return 0; From patchwork Wed Dec 7 15:49:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 30906 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp260833wrr; Wed, 7 Dec 2022 07:52:27 -0800 (PST) X-Google-Smtp-Source: AA0mqf5uXGRL88KQw2r5mzC5lo3/m3wJ2Ee7xehMfbv1WgdvANytgoijgbV56BUNYfbkm8z6VCIh X-Received: by 2002:a05:6402:35cf:b0:469:5ee9:4a76 with SMTP id z15-20020a05640235cf00b004695ee94a76mr62975803edc.405.1670428346885; Wed, 07 Dec 2022 07:52:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670428346; cv=none; d=google.com; s=arc-20160816; b=VgIYZXo2L3HCJVB6/B4L/yhLyztMbBwDAr2JiCnVdojSpq2ZoueNWY+HMgDJ/Z7S2z +3ELdOBnwwdIK3H+SjBkU6WHM20MTcBFw+C5wa7oYt3Yw+fpbouWhedFw/v6TlRimjTh C4xNNRLcpgpEG7Dn9EO+YOvZMsFV0r/tLzxerDQRBdMrm9JmoyFr3dR/Jr/SNc3bPUhQ MThzMfV2jF1kYNkhU+T4RrGkm3qUCGkh8BGA7vy12eKfIb9YLKPdAnldDfxB07sZ5kX1 CgBQvX8nOipJrbevMdKDrpL5qn52a82WuoFnaoeC/tRIHxUbQrB6HwaMl35xeNVO74dL Q6qQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=br+NzT6Ekl7un/bONAJTTP+zVNWLoPX0fUe5M313tYk=; b=iajEGv536cFIpE6Gc443ldwMXeXQuCyE57SKDoziRP7wxmFC/1cF+HdZluQMjGZxBx 62YWF8WvGU85BhytR/PGoD3O3FVRpfDLcKN17oUF10L01jPZ/dwD1QIEeq0/XJ+7NcA6 xLWI8Wp4YJ/LiFpgfth3Jm5yQqf+gJ5pfWhB5CT3bU+nnbqEdWk/M5/nS15WgHaE/AND fD8EzFAL3+VEVwdQi1q4TNa6lCToT6wXGN2AfM+4IMsZsSWY7gnld4p33FnNb7y10VRs zEQmjuAaKkp22Lt0Mqa42VPm5KeHtSym6Ter3HdbNAJ2TLNnWQQVw+Et9gbTgpulro7h nDdA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=KveNxSwr; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ji13-20020a170907980d00b007c098f5e5f4si19057922ejc.233.2022.12.07.07.52.02; Wed, 07 Dec 2022 07:52:26 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=KveNxSwr; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229942AbiLGPuX (ORCPT + 99 others); Wed, 7 Dec 2022 10:50:23 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50802 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229760AbiLGPtv (ORCPT ); Wed, 7 Dec 2022 10:49:51 -0500 Received: from mail-pj1-x1034.google.com (mail-pj1-x1034.google.com [IPv6:2607:f8b0:4864:20::1034]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0692A63BBB for ; Wed, 7 Dec 2022 07:49:51 -0800 (PST) Received: by mail-pj1-x1034.google.com with SMTP id b11so18005781pjp.2 for ; Wed, 07 Dec 2022 07:49:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=br+NzT6Ekl7un/bONAJTTP+zVNWLoPX0fUe5M313tYk=; b=KveNxSwrAsaP96yq/2ARVH0FCPenY0jXv1lv5clhnkzL7NYz4dsA1XuERs7Zl08c5t 8vCBKRTn59G+ilGEelru03ZLrBZQfDmbySTIZfw8NCC1D/7Z0wESKY45SOkudNKxEzZ8 +FtkzZYTl3DL+21FEiiiK6YesMBG9HrOrbn8g= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=br+NzT6Ekl7un/bONAJTTP+zVNWLoPX0fUe5M313tYk=; b=q0UrhfYV9W5x+cjqNTO16E7y+saN9IMvwxeq5UxJZPGYz7WSwCgVbPRPFqqxeyYR3m ALnyTgusg1Bm/r+sH3mEZ1aIOgsR2NFesJb7v3vFo/JI4/iuzd9hz8YMmyvX4CY2OQt4 aYlBu5R9tUvUN1TfTTLBqAlUXgxniaaX2pFziDnnSWq3s6TtVrU7922K+lPboWIGztV8 x46KjbWreDRZJqiK1Xc4NRh9VW67S6cQMVyHmIVUTtPNJZBi9Q394qSZvlX3xGrCqX66 M/EJp2Id0P4zORgui0JdARQiTzdcQ3Qaj3NZcpyCIgr/SBP1CLF6lRVUWYeO6eOdl9x4 ItDA== X-Gm-Message-State: ANoB5pl41eotylrsENiMdxgo9G1fKt9S9XikkGIgTmS+Xv6TcpUgeeg/ r2HyJdNyq/KB8X4x/Vhg/vHB+Q== X-Received: by 2002:a17:902:b611:b0:188:f570:7bdf with SMTP id b17-20020a170902b61100b00188f5707bdfmr682078pls.40.1670428190523; Wed, 07 Dec 2022 07:49:50 -0800 (PST) Received: from jeffxud.c.googlers.com.com (30.202.168.34.bc.googleusercontent.com. [34.168.202.30]) by smtp.gmail.com with ESMTPSA id a9-20020a170902ecc900b0017f7628cbddsm14920934plh.30.2022.12.07.07.49.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 07 Dec 2022 07:49:49 -0800 (PST) From: jeffxu@chromium.org To: skhan@linuxfoundation.org, keescook@chromium.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, jannh@google.com, linux-hardening@vger.kernel.org, kernel test robot Subject: [PATCH v6 6/6] mm/memfd: security hook for memfd_create Date: Wed, 7 Dec 2022 15:49:39 +0000 Message-Id: <20221207154939.2532830-7-jeffxu@google.com> X-Mailer: git-send-email 2.39.0.rc0.267.gcb52ba06e7-goog In-Reply-To: <20221207154939.2532830-1-jeffxu@google.com> References: <20221207154939.2532830-1-jeffxu@google.com> MIME-Version: 1.0 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751571073828688925?= X-GMAIL-MSGID: =?utf-8?q?1751571073828688925?= From: Jeff Xu The new security_memfd_create allows lsm to check flags of memfd_create. The security by default system (such as chromeos) can use this to implement system wide lsm to allow only non-executable memfd being created. Signed-off-by: Jeff Xu Reported-by: kernel test robot --- include/linux/lsm_hook_defs.h | 1 + include/linux/lsm_hooks.h | 4 ++++ include/linux/security.h | 6 ++++++ mm/memfd.c | 5 +++++ security/security.c | 13 +++++++++++++ 5 files changed, 29 insertions(+) diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index ec119da1d89b..fd40840927c8 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -164,6 +164,7 @@ LSM_HOOK(int, 0, file_alloc_security, struct file *file) LSM_HOOK(void, LSM_RET_VOID, file_free_security, struct file *file) LSM_HOOK(int, 0, file_ioctl, struct file *file, unsigned int cmd, unsigned long arg) +LSM_HOOK(int, 0, memfd_create, char *name, unsigned int flags) LSM_HOOK(int, 0, mmap_addr, unsigned long addr) LSM_HOOK(int, 0, mmap_file, struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 4ec80b96c22e..5a18a6552278 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -543,6 +543,10 @@ * simple integer value. When @arg represents a user space pointer, it * should never be used by the security module. * Return 0 if permission is granted. + * @memfd_create: + * @name is the name of memfd file. + * @flags is the flags used in memfd_create. + * Return 0 if permission is granted. * @mmap_addr : * Check permissions for a mmap operation at @addr. * @addr contains virtual address that will be used for the operation. diff --git a/include/linux/security.h b/include/linux/security.h index ca1b7109c0db..5b87a780822a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -384,6 +384,7 @@ int security_file_permission(struct file *file, int mask); int security_file_alloc(struct file *file); void security_file_free(struct file *file); int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +int security_memfd_create(char *name, unsigned int flags); int security_mmap_file(struct file *file, unsigned long prot, unsigned long flags); int security_mmap_addr(unsigned long addr); @@ -963,6 +964,11 @@ static inline int security_file_ioctl(struct file *file, unsigned int cmd, return 0; } +static inline int security_memfd_create(char *name, unsigned int flags) +{ + return 0; +} + static inline int security_mmap_file(struct file *file, unsigned long prot, unsigned long flags) { diff --git a/mm/memfd.c b/mm/memfd.c index 92f0a5765f7c..f04ed5f0474f 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -356,6 +356,11 @@ SYSCALL_DEFINE2(memfd_create, goto err_name; } + /* security hook for memfd_create */ + error = security_memfd_create(name, flags); + if (error) + return error; + if (flags & MFD_HUGETLB) { file = hugetlb_file_setup(name, 0, VM_NORESERVE, HUGETLB_ANONHUGE_INODE, diff --git a/security/security.c b/security/security.c index 79d82cb6e469..5c018e080923 100644 --- a/security/security.c +++ b/security/security.c @@ -1010,6 +1010,19 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb, } EXPORT_SYMBOL(security_sb_clone_mnt_opts); +int security_add_mnt_opt(const char *option, const char *val, int len, + void **mnt_opts) +{ + return call_int_hook(sb_add_mnt_opt, -EINVAL, + option, val, len, mnt_opts); +} +EXPORT_SYMBOL(security_add_mnt_opt); + +int security_memfd_create(char *name, unsigned int flags) +{ + return call_int_hook(memfd_create, 0, name, flags); +} + int security_move_mount(const struct path *from_path, const struct path *to_path) { return call_int_hook(move_mount, 0, from_path, to_path);