From patchwork Fri Aug 5 22:21:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 12937859 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5C906C19F2D for ; Fri, 5 Aug 2022 22:21:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241795AbiHEWV5 (ORCPT ); Fri, 5 Aug 2022 18:21:57 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36430 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241840AbiHEWVu (ORCPT ); Fri, 5 Aug 2022 18:21:50 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3AA241CB26 for ; Fri, 5 Aug 2022 15:21:49 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-31f4e870a17so31513087b3.9 for ; Fri, 05 Aug 2022 15:21:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=mbnTnCyzBrPsZ2cIyy/polFSFcHi5iA+y2wZHy5S50g=; b=O1tv2Chuzvi0NDU6zf4N/Fshq6yGCqiuDTuun/edjoU5VnoWU6HlwRqRq214Cym4mz noFPwUsXvo0SYNfeNEjWoXIVZcign3gEgsFpITz4QnZrbGOtKfeY+cDS9TK5falMgCNI DJ6xcL5LbkGOVjDMSML6SM3jRDsvX6GsPMXFLvFKSYD1BtYOfgnhaOBaYbe12JSlISWh zKPVACct5OHq40PuoLQGZTx+YFMcXX1RgsGmCiYPiEbumgKzZ847z4pJf7UeYvrXqLcR FAIEKIHGSOX0P4KPT7WoPV95vsdEH3BO4vgVQ2JI3EeE9rV4Ph0MSuemj+SCfQWNltzS 3OGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=mbnTnCyzBrPsZ2cIyy/polFSFcHi5iA+y2wZHy5S50g=; b=HZE2/dZO4bqaDzx3/dcgqSJ4/E+ccWS/Ax9wHP+MIlELX7Xq43I9OObN9Pzc7DvEcT hI3R1xyEQIthBF++7rZPetd/W+zriMov1PFI7aNA458D2c/Ckb260B1Y2i1jewD6XVwg eMMDoV+yJ1rBRAE86QWYKoR/dNWcQ2UChmsWMK6gJHgTjtE39fWPZtjw+iij+fLNMKPO GgYnFxkgpmzd3cmD0xdiYmhH2WOXNkyUaLNyzALN3gsCrolYOgKKRaDdX2EH+DR5dS1y mnJkVJRatSrDLSXAk6IT9aeZteW6cf9RrS1IW4xRbjW2ZvF1bN18C1VFHmDlwxG87gbt JJLw== X-Gm-Message-State: ACgBeo1vEX6VVU9eCvhBBftqY5knFHYIxx6Nx/SkdWkRb9ZjBcd859NZ 9c5QroTV9wvJiUmeZzoDeX2TZXD02QY= X-Google-Smtp-Source: AA6agR6sCneuMkIn8ODRd5RHoaPnFVjTcuaTHnQMf3gsH0n2vQfppBnVbsN+vr+g2fHjPeLdvPi2NkEA0yQ= X-Received: from jeffxud.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:e37]) (user=jeffxu job=sendgmr) by 2002:a05:6902:723:b0:677:115b:553c with SMTP id l3-20020a056902072300b00677115b553cmr7776175ybt.214.1659738108553; Fri, 05 Aug 2022 15:21:48 -0700 (PDT) Date: Fri, 5 Aug 2022 22:21:22 +0000 In-Reply-To: <20220805222126.142525-1-jeffxu@google.com> Message-Id: <20220805222126.142525-2-jeffxu@google.com> Mime-Version: 1.0 References: <20220805222126.142525-1-jeffxu@google.com> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v2 1/5] mm/memfd: add F_SEAL_EXEC From: To: skhan@linuxfoundation.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, keescook@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, mnissler@chromium.org, jannh@google.com, Jeff Xu Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org 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. Co-developed-by: Jeff Xu Signed-off-by: Jeff Xu Signed-off-by: Daniel Verkamp --- 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..a472ba69596c 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 e5e43b990fdc..bb530f562bdd 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1082,6 +1082,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 Fri Aug 5 22:21:23 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 12937860 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id EC8EDC25B08 for ; Fri, 5 Aug 2022 22:21:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241755AbiHEWV6 (ORCPT ); Fri, 5 Aug 2022 18:21:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36346 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241845AbiHEWVv (ORCPT ); Fri, 5 Aug 2022 18:21:51 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EF1331C920 for ; Fri, 5 Aug 2022 15:21:50 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-31f4e870a17so31513517b3.9 for ; Fri, 05 Aug 2022 15:21:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=5E4PGAWMReAFHkj0eA7xzWpJk8N5M4FgV4LT8CvMVPA=; b=TDuzZmP48qciezv1MXsf3LVuEa0sxCTwiXmz3GaFb6bY9Qtk1DrEr4hk/hgSUCSU9D AfNdO6ggJ2vgmMWeMOlX/leMgSXGcQVjNK0zYR0phfm+32xYcPAHGvQSYoqPiNbxudnk HvE2bkCtTLZ4+b3Ay+j53c5ejYOvr0jzKdc8h62ng9xyA/YGHmq7HQjrLzA1ZaYH+BV9 0FZ6JoFGedju30kgJTOIXqXWVdCHFjQ55uchR5QBZO9lhMl46oSxaKE6Z0a+P78bLdDl tNj+/17Hexg7tUbRBM+OCbb+sqB6gZJt9lxBqysd3REOSfOgCXMUXOEiZd1Awo0K8DSt 9wmQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=5E4PGAWMReAFHkj0eA7xzWpJk8N5M4FgV4LT8CvMVPA=; b=rOW/jHzWE8qvBu3UFLpsDYdnBr3APbHLW/uC3BbyziUxLzp3JIfHYNKW5GWxj3T/cu qRUiUYF/SyWNvKM4YbP7+2PIEQ448giht6SdXxMc8foZU4cZV8H4zgqvryNvyq3hryFD PNTUYbaAxy9+1qE1UIpPfilMvJYY8kDghLDqNAAiPk1tC47DXBLMvz5gnCVWLBmLnUXR ga8d9uMw1l3D46TOUMvzlZBii2zahrjnxyy7GSY1tMHmUMhDgcN+7eKvBXb7cVXSSXVj G690AmppyoHG9XkRxGfOOfxYEMTLAd/wjhjDcwwH+6Y/d/S6nTdglPG9msQpZYUZiz7H ip/w== X-Gm-Message-State: ACgBeo0toGgEVHGOsHkSYT6AQYu9pH/P9cYZnEVwkbicZSfKz0EsnNHz BqaVx/SyGmZ9PcRn4YT5KVu33x56DZE= X-Google-Smtp-Source: AA6agR55Nd+GF+Zicb9UzLXVsBAJG/nkDrQRMgHX77YRUR2vsXmmAEpB7Hc955x1MuY3F3Ah7dc0fEbCssM= X-Received: from jeffxud.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:e37]) (user=jeffxu job=sendgmr) by 2002:a25:9c87:0:b0:671:82fd:9106 with SMTP id y7-20020a259c87000000b0067182fd9106mr7167620ybo.546.1659738110679; Fri, 05 Aug 2022 15:21:50 -0700 (PDT) Date: Fri, 5 Aug 2022 22:21:23 +0000 In-Reply-To: <20220805222126.142525-1-jeffxu@google.com> Message-Id: <20220805222126.142525-3-jeffxu@google.com> Mime-Version: 1.0 References: <20220805222126.142525-1-jeffxu@google.com> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v2 2/5] mm/memfd: add MFD_NOEXEC flag to memfd_create From: To: skhan@linuxfoundation.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, keescook@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, mnissler@chromium.org, jannh@google.com, Jeff Xu Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Daniel Verkamp The new MFD_NOEXEC flag allows the creation of a permanently non-executable memfd. This is accomplished by creating it with a different set of file mode bits (0666) than the default (0777) and applying the F_SEAL_EXEC seal at creation time, so there is no window between memfd creation and seal application. Unfortunately, the default for memfd must remain executable, since changing this would be an API break, and some programs depend on being able to exec code from a memfd directly. However, this new flag will allow programs to create non-executable memfds, and a distribution may choose to enforce use of this flag in memfd_create calls via other security mechanisms. Co-developed-by: Jeff Xu Signed-off-by: Jeff Xu Signed-off-by: Daniel Verkamp --- include/uapi/linux/memfd.h | 1 + mm/memfd.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/memfd.h b/include/uapi/linux/memfd.h index 7a8a26751c23..140e125c9f65 100644 --- a/include/uapi/linux/memfd.h +++ b/include/uapi/linux/memfd.h @@ -8,6 +8,7 @@ #define MFD_CLOEXEC 0x0001U #define MFD_ALLOW_SEALING 0x0002U #define MFD_HUGETLB 0x0004U +#define MFD_NOEXEC 0x0008U /* * Huge page size encoding when MFD_HUGETLB is specified, and a huge page diff --git a/mm/memfd.c b/mm/memfd.c index 4ebeab94aa74..b841514eb0fd 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -263,7 +263,7 @@ 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) SYSCALL_DEFINE2(memfd_create, const char __user *, uname, @@ -333,6 +333,14 @@ SYSCALL_DEFINE2(memfd_create, *file_seals &= ~F_SEAL_SEAL; } + if (flags & MFD_NOEXEC) { + struct inode *inode = file_inode(file); + + inode->i_mode &= ~0111; + file_seals = memfd_file_seals_ptr(file); + *file_seals |= F_SEAL_EXEC; + } + fd_install(fd, file); kfree(name); return fd; From patchwork Fri Aug 5 22:21:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 12937862 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D7AF1C3F6B0 for ; Fri, 5 Aug 2022 22:22:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241821AbiHEWWB (ORCPT ); Fri, 5 Aug 2022 18:22:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36368 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241790AbiHEWVy (ORCPT ); Fri, 5 Aug 2022 18:21:54 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8722E1B786 for ; Fri, 5 Aug 2022 15:21:53 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id c9-20020a5b0989000000b0067b7758254cso3093171ybq.14 for ; Fri, 05 Aug 2022 15:21:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=8AvsEq4SstPGeW7QF9LLj/CM82M+f11wZB7WzW/AmUg=; b=mMb+PeyF4VQkekJjv1Q+X2LF/3kKZ0J2TCbHkTTU/n5K6SxiBoS32IjQbd7vR1JBuY KK5mNxKRvJhbNpXkBgLNsjozyQGZZykaqk9VJaar90tvBTvpEwaJWc/oPcu8lkQsledi CfI3NYgAM5qa/N6/BrSW4XoQzQJwhjQqwzUAlLdH+uaizI1Yde5jEVhQMh4/W4ts0DRC nTZKmQYKwiV5MoJ69N1hpt8b+LYHYMNfd2Tl2jK9YjWAMNbaO4NhjiFuji/3ZwNy8TCO iFrzR+jYcS+CMSO5r4DA1Bvpyvedk6yb/v6haitjoDbX9YF4zss9+D/gTqEGtTKwy5vd 1RBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=8AvsEq4SstPGeW7QF9LLj/CM82M+f11wZB7WzW/AmUg=; b=kILoaI1Z7zLNFsCSg9yiNZonnymwB9VHyVZQXVUcp5daZKBcr3xy6hWNZW6FqUj6sh gWYeKSnoh7Wy6tny8btkMGEQdZIUoCCd/9AvoatB/k9zK9HTbdFehOmfuPI7aF4uyVe+ Jw8SpJyTjM/8y69rHu5fre7CWwiKgQzcmECjo58TS9wwfU6Lvv15yC+5VVX/Eay1xkc1 PPx3r/JijJYIzRzd+489X7yUCV/qRBIMER0TyXBN85WSo9gc5vnAZzrKCzifeR1BdljA M0K+HmJn/K43EeQGGVM8y6Q6jyftJzqsTBSQuqb2K4SMsZud+SOCsYD0VGdrDpsXICVC a0rQ== X-Gm-Message-State: ACgBeo3+bBJIWmzszOs/Sh9/N5kPQ+LyFTaEq3al8nFwglOtb9YabFIN fbhvfy7NGxTWlDkbrRfI0CGzbbwbk/U= X-Google-Smtp-Source: AA6agR7MhJWGNuJekXT5wplu+5rroD6wgWIQKDgy1c8mBYuUwU+BizAsUUXtqWQTJ2dbcZa+Q1JevcSWC98= X-Received: from jeffxud.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:e37]) (user=jeffxu job=sendgmr) by 2002:a81:7b85:0:b0:321:119:5a0d with SMTP id w127-20020a817b85000000b0032101195a0dmr8242026ywc.55.1659738112795; Fri, 05 Aug 2022 15:21:52 -0700 (PDT) Date: Fri, 5 Aug 2022 22:21:24 +0000 In-Reply-To: <20220805222126.142525-1-jeffxu@google.com> Message-Id: <20220805222126.142525-4-jeffxu@google.com> Mime-Version: 1.0 References: <20220805222126.142525-1-jeffxu@google.com> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v2 3/5] selftests/memfd: add tests for F_SEAL_EXEC From: To: skhan@linuxfoundation.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, keescook@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, mnissler@chromium.org, jannh@google.com, Jeff Xu Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Daniel Verkamp Basic tests to ensure that user/group/other execute bits cannot be changed after applying F_SEAL_EXEC to a memfd. Co-developed-by: Jeff Xu Signed-off-by: Jeff Xu Signed-off-by: Daniel Verkamp --- 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 Fri Aug 5 22:21:25 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 12937863 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 93611C19F2D for ; Fri, 5 Aug 2022 22:22:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241813AbiHEWWA (ORCPT ); Fri, 5 Aug 2022 18:22:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36414 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241771AbiHEWV4 (ORCPT ); Fri, 5 Aug 2022 18:21:56 -0400 Received: from mail-pg1-x54a.google.com (mail-pg1-x54a.google.com [IPv6:2607:f8b0:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9FA101BE83 for ; Fri, 5 Aug 2022 15:21:55 -0700 (PDT) Received: by mail-pg1-x54a.google.com with SMTP id p35-20020a631e63000000b0041992866de0so1752003pgm.19 for ; Fri, 05 Aug 2022 15:21:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=18f+8YL6aOvEHaZ2GuJdUMnF89FwCoTjUmHERMQZXDE=; b=FsK4U64sZVq+y1SyuqOQStvSBS7X8QECCn6LIsVMr2xn0nkzLI8+c5D4j5EMd+AUhk j3t/30i3HkCUWA8GRrEV/n5la5QXWMAMmnEib1Gi4341JdPl8J5TfnHLWNa+y5fVP+eV oJ9bBE123va/TwKlbkn1J19gX+WOPS5lk3FwZlPtz0EcE3ZPCeaSKNYq9YOdEzFcDRFj lzgI8luSNRGb7P0bwY+aM7gsZ7WkQblht0scSjo8RmMJapESKs0qw+DFJAb+seJ/d+fa mzUs1GKxmI0hZowF1OygbHCwUgPDBmTWHAd9Z5XtwUGQJ2j7xvAyT0Qa4igHULcSRtrM vWkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=18f+8YL6aOvEHaZ2GuJdUMnF89FwCoTjUmHERMQZXDE=; b=nDYRd+SPiqSlLoGt93nqG++XDS7eUWncMLwvaOKsmcF5/BKrm7ooVtufjLyqFJYJHh fMuzJ+gzXLIq8/btjNnc7njjIfJ6PNd3qp+Y/FfHOx1EutFmV5h/6HqmkaafnqFRbw36 ++1offTuiE+A1AEsD6Zx1e9YXCoFIZwX+MzRfXNSxTTDmLmHn7J31Yxu1ROCLkbs/JZP MKhvuYnWqd/4GCSnsVjibOOPB+E0JgzqMA+mhjaoqZvyikt718zJawmZUh1L+uTCsLvn YBFOKYWE48X1eBBcI2BKWKsRluMNp5+42VPXD71b2DwBT8UNFryuV/qfpiXT+LVBPmx7 oCIQ== X-Gm-Message-State: ACgBeo0JYf291JOaGap5KwlscZGV5STJoP8sSiyUkhtM7RpMVqMJoZCn PBnUx4hCi0g2w6upKFXczVT6fnDdr3I= X-Google-Smtp-Source: AA6agR5SYNgjRPD70HCAO4QbLAX75hHQo60LfWD/m1Gc2TjfjizdokqQLPw4iq40ChDMtnBNielltDU4BD0= X-Received: from jeffxud.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:e37]) (user=jeffxu job=sendgmr) by 2002:a05:6a00:22d0:b0:52e:49f3:3f52 with SMTP id f16-20020a056a0022d000b0052e49f33f52mr8783529pfj.54.1659738115213; Fri, 05 Aug 2022 15:21:55 -0700 (PDT) Date: Fri, 5 Aug 2022 22:21:25 +0000 In-Reply-To: <20220805222126.142525-1-jeffxu@google.com> Message-Id: <20220805222126.142525-5-jeffxu@google.com> Mime-Version: 1.0 References: <20220805222126.142525-1-jeffxu@google.com> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v2 4/5] selftests/memfd: add tests for MFD_NOEXEC From: To: skhan@linuxfoundation.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, keescook@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, mnissler@chromium.org, jannh@google.com, Jeff Xu Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Daniel Verkamp Tests that ensure MFD_NOEXEC memfds have the appropriate mode bits and cannot be chmod-ed into being executable. Co-developed-by: Jeff Xu Signed-off-by: Jeff Xu Signed-off-by: Daniel Verkamp --- tools/testing/selftests/memfd/memfd_test.c | 34 ++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c index 1d7e7b36bbdd..4906f778564e 100644 --- a/tools/testing/selftests/memfd/memfd_test.c +++ b/tools/testing/selftests/memfd/memfd_test.c @@ -36,6 +36,10 @@ #define MAX_PATH 256 #endif +#ifndef MFD_NOEXEC +#define MFD_NOEXEC 0x0008U +#endif + /* * Default is not to test hugetlbfs */ @@ -1006,6 +1010,35 @@ static void test_seal_exec(void) close(fd); } +/* + * Test memfd_create with MFD_NOEXEC flag + * Test that MFD_NOEXEC applies F_SEAL_EXEC and prevents change of exec bits + */ +static void test_noexec(void) +{ + int fd; + + printf("%s NOEXEC\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); + 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); + mfd_assert_mode(fd, 0666); + mfd_assert_has_seals(fd, F_SEAL_EXEC | F_SEAL_SEAL); + mfd_fail_chmod(fd, 0777); + close(fd); +} + /* * Test sharing via dup() * Test that seals are shared between dupped FDs and they're all equal. @@ -1179,6 +1212,7 @@ int main(int argc, char **argv) test_create(); test_basic(); + test_noexec(); test_seal_write(); test_seal_future_write(); From patchwork Fri Aug 5 22:21:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 12937861 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5FFA8C00140 for ; Fri, 5 Aug 2022 22:22:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241688AbiHEWWA (ORCPT ); Fri, 5 Aug 2022 18:22:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:36224 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241813AbiHEWV7 (ORCPT ); Fri, 5 Aug 2022 18:21:59 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 39BDA1BEB9 for ; Fri, 5 Aug 2022 15:21:58 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id k13-20020a056902024d00b0066fa7f50b97so3103125ybs.6 for ; Fri, 05 Aug 2022 15:21:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=p3xudRLR9dNuWUK9U/ylm6O3b8FVaNLRrb9pQqFzR0w=; b=tEC+w7ZCMSi41gOV32xpW1cs0vFZd0pjxoK1AeJyyH01noSX4dLvRhywvBcccI9kdU JKFh83XKg1Si8IMewvVtmvDTWjRKjw3vuzZtx6w3xA2KeuXUxoU/6vRz//098kabUzjE eFwl26ps6MG+nYqCcCI1foMbFHepHOTyrxI0z85iwM8dIVVGbzs366K/ASaVu+V0zPT/ uJ/lsElcVWzYS8YYewDpoOAwFTi+w1gRSdsGaOWMYHEI+AEzCyag0hQVzUs3cU93g+T8 p0Ut/ZVPUs8LdBcNe3+7UfinveQxYxEtWF7YFesMt+DabZUIKwIYMEaR3aoNOvIbKV0C 8E5Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=p3xudRLR9dNuWUK9U/ylm6O3b8FVaNLRrb9pQqFzR0w=; b=mwISkIe/97Sy6/c1xmVJjiBWdRt4clOSCZZjPi0NrxNK7WtG1Re7yud6GFBVpRPMWo AKhnH1Bratp0xyAWKfXZyuhABy9wWfnouq0oxZf3bkjQPelZ9bDNWRkNzQdHYdj7OZET +hXOTMYl+scG04CqTkvOXuiBix4D8pSeJVrBSVcdjj2YVgUJKj8Z8LEV86X+UdV0+JTw UNQzX2G5bziIeKaEXPk28qNHUU2j1NZb8K/ljm4ZZTD0BqDeiJfJVBMT2XexCzhU8NK4 mlusOhaAurMwy6he4g4YFwjrtCGKSGYBnCWYY4rG7nrmif+p8Pj7t4twnoL7HODBGmdY WCSg== X-Gm-Message-State: ACgBeo1nYiBt4KG1ppOjFmFzJKkoH5kx86aRgKEVIv3kdbYRyYvBKF7x oml8esnDI55/5SZ1vuySqI1xRws5Oy8= X-Google-Smtp-Source: AA6agR7Pdt67CAVIWF/fYp+P3xXpceR93JSbt9+i7cJEfvpa+CoelR+6dqwVhJxpBe3viA/07hQjowUu1E0= X-Received: from jeffxud.c.googlers.com ([fda3:e722:ac3:cc00:20:ed76:c0a8:e37]) (user=jeffxu job=sendgmr) by 2002:a25:33c5:0:b0:67a:6950:c188 with SMTP id z188-20020a2533c5000000b0067a6950c188mr7334020ybz.175.1659738117501; Fri, 05 Aug 2022 15:21:57 -0700 (PDT) Date: Fri, 5 Aug 2022 22:21:26 +0000 In-Reply-To: <20220805222126.142525-1-jeffxu@google.com> Message-Id: <20220805222126.142525-6-jeffxu@google.com> Mime-Version: 1.0 References: <20220805222126.142525-1-jeffxu@google.com> X-Mailer: git-send-email 2.37.1.559.g78731f0fdb-goog Subject: [PATCH v2 5/5] sysctl: add support for mfd_noexec From: To: skhan@linuxfoundation.org Cc: akpm@linux-foundation.org, dmitry.torokhov@gmail.com, dverkamp@chromium.org, hughd@google.com, jeffxu@google.com, jorgelo@chromium.org, keescook@chromium.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, mnissler@chromium.org, jannh@google.com, Jeff Xu Precedence: bulk List-ID: X-Mailing-List: linux-kselftest@vger.kernel.org From: Jeff Xu Add vm.mfd_noexec. When the value is 1 (enabled), memfd_create syscall will created non-executable memfd. The default value is 0 (disabled), admin can change the setting from 0 => 1, however 1 => 0 is not allowed, unless reboot. Signed-off-by: Jeff Xu Reported-by: kernel test robot Reported-by: kernel test robot --- include/linux/mm.h | 4 ++++ kernel/sysctl.c | 9 +++++++++ mm/memfd.c | 27 +++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index 7898e29bcfb5..1c66cf4aca11 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -203,6 +203,10 @@ extern int sysctl_overcommit_memory; extern int sysctl_overcommit_ratio; extern unsigned long sysctl_overcommit_kbytes; +extern int sysctl_mfd_noexec_scope; +extern int mfd_noexec_dointvec_minmax(struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos); + int overcommit_ratio_handler(struct ctl_table *, int, void *, size_t *, loff_t *); int overcommit_kbytes_handler(struct ctl_table *, int, void *, size_t *, diff --git a/kernel/sysctl.c b/kernel/sysctl.c index b233714a1c78..54510da007ff 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2362,6 +2362,15 @@ static struct ctl_table vm_table[] = { .mode = 0644, .proc_handler = mmap_min_addr_handler, }, + { + .procname = "mfd_noexec", + .data = &sysctl_mfd_noexec_scope, + .maxlen = sizeof(sysctl_mfd_noexec_scope), + .mode = 0644, + .proc_handler = mfd_noexec_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, #endif #ifdef CONFIG_NUMA { diff --git a/mm/memfd.c b/mm/memfd.c index b841514eb0fd..c6ccb8481ed2 100644 --- a/mm/memfd.c +++ b/mm/memfd.c @@ -20,6 +20,11 @@ #include #include +#define MFD_NOEXEC_SCOPE_DISABLED 0 +#define MFD_NOEXEC_SCOPE_ENABLED 1 + +int sysctl_mfd_noexec_scope __read_mostly = MFD_NOEXEC_SCOPE_DISABLED; + /* * We need a tag: a new tag would expand every xa_node by 8 bytes, * so reuse a tag which we firmly believe is never set or cleared on tmpfs @@ -275,6 +280,10 @@ SYSCALL_DEFINE2(memfd_create, char *name; long len; + if (sysctl_mfd_noexec_scope == MFD_NOEXEC_SCOPE_ENABLED) { + flags |= MFD_NOEXEC; + } + if (!(flags & MFD_HUGETLB)) { if (flags & ~(unsigned int)MFD_ALL_FLAGS) return -EINVAL; @@ -351,3 +360,21 @@ SYSCALL_DEFINE2(memfd_create, kfree(name); return error; } + +#ifdef CONFIG_SYSCTL +int mfd_noexec_dointvec_minmax(struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table table_copy; + + if (write && !capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* Lock the max value if it ever gets set. */ + table_copy = *table; + if (*(int *)table_copy.data == *(int *)table_copy.extra2) + table_copy.extra1 = table_copy.extra2; + + return proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos); +} +#endif