From patchwork Tue Apr 11 01:29:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ackerley Tng X-Patchwork-Id: 13206945 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2A303C77B77 for ; Tue, 11 Apr 2023 01:29:42 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 9A70C280041; Mon, 10 Apr 2023 21:29:41 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 9576528003C; Mon, 10 Apr 2023 21:29:41 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 78345280041; Mon, 10 Apr 2023 21:29:41 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 6A72B28003C for ; Mon, 10 Apr 2023 21:29:41 -0400 (EDT) Received: from smtpin07.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 3A98CABDF8 for ; Tue, 11 Apr 2023 01:29:41 +0000 (UTC) X-FDA: 80667378162.07.8AF7EE4 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) by imf16.hostedemail.com (Postfix) with ESMTP id 75280180010 for ; Tue, 11 Apr 2023 01:29:39 +0000 (UTC) Authentication-Results: imf16.hostedemail.com; dkim=pass header.d=google.com header.s=20210112 header.b=XXnjZgXz; spf=pass (imf16.hostedemail.com: domain of 3Arg0ZAsKCG0LNVPcWPjeYRRZZRWP.NZXWTYfi-XXVgLNV.ZcR@flex--ackerleytng.bounces.google.com designates 209.85.210.202 as permitted sender) smtp.mailfrom=3Arg0ZAsKCG0LNVPcWPjeYRRZZRWP.NZXWTYfi-XXVgLNV.ZcR@flex--ackerleytng.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1681176579; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=jBCdWjTPDV7u7tywdkOEhqA30FFTo51cVFS76tLVdIk=; b=zD5HYHi/9luyGsgaLRm1xY2misZkdFBsHUYeI4Jh8HIslOmAYuRfjOCADY62RX8nNZvgkq h3ZKZDv1+H4PgyrxPL+l6a5N+8YrmbqLHl5qOExex3aRmOsTQTsfd6bOiW5yuSuRXKYu4q hXmC0em+q0dRJfv9XEUaP+PJX0rJ0Jc= ARC-Authentication-Results: i=1; imf16.hostedemail.com; dkim=pass header.d=google.com header.s=20210112 header.b=XXnjZgXz; spf=pass (imf16.hostedemail.com: domain of 3Arg0ZAsKCG0LNVPcWPjeYRRZZRWP.NZXWTYfi-XXVgLNV.ZcR@flex--ackerleytng.bounces.google.com designates 209.85.210.202 as permitted sender) smtp.mailfrom=3Arg0ZAsKCG0LNVPcWPjeYRRZZRWP.NZXWTYfi-XXVgLNV.ZcR@flex--ackerleytng.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1681176579; a=rsa-sha256; cv=none; b=H6orwosAhQ2iv9YZBND1oqwH3S5Pxv4OiWzwXE9QY8AXrroiBkNGCSyZo8XGJcKLLBpqRi hms4Epm7QKodgBOxCxIoOuivUfxcjHMy9oK6jKY45xQ2kX+eXwzlkZW2FV0tkgEG/1RiE8 ccxrFRkfxn4PxBh+nHetoZ1PiOU4CXY= Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-63243c02cceso602405b3a.2 for ; Mon, 10 Apr 2023 18:29:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; t=1681176578; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=jBCdWjTPDV7u7tywdkOEhqA30FFTo51cVFS76tLVdIk=; b=XXnjZgXzwtwzC9wPP7936MOH1Bh6PiD2hqfXsgLbzkeGH7jGOqDvWazEmiyAzxPEXN HOXn2bdQRnFFlnJUMCqgw4px9COwSYMyn3YVtfmzMWvKtYBIfUSMShHDLtLIFs/2YTUR ZIlb/4bJS9MEL7swsNJzi4YAZKTAsbO10KC0Ds2cNLC22Pg9HmCMPpjEwtsK0gp8xNc3 mZO89Ov6XW97TbXx3Qad8uCoGve6ai+6KRHCABfhvY1sO8p+sNfAEeAPFhpBXQq5q71+ Ao9iCqyyDHst/xqAqkZjIbwaUW4f94Yk0iTSASX0LtcD2fSwJLyo8HMt+YM3EG3m5HrO XxOw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1681176578; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=jBCdWjTPDV7u7tywdkOEhqA30FFTo51cVFS76tLVdIk=; b=ys4Ijd9ASMxP8HhvBv+67IlXLjAEJwQ+swgTfL49wZYxhetyaG/bDHpNrUKTgN8OiQ KQ4Uqwe9MDjfUHIzprkeX0C8T466ModUh1cPM+DP8YijVwtLBvplQGkHfql1Y6up32cE y8aR+51K7OOkHH4tNqn4xYWE19gs2yh0Ste7Vx2qepJ+qD0teJxbrJusbrKnqBomHg+r WI5A4i3QdBw1xMynMtKgLU+1bMm3wiO5KImTINuuHodOh1KfjYXGUcfh2fg/L5plT1xm LwF8WBR8BCvi5q4i8R1Oc95Wih056kqWEKiRPj8cH1VYEe4bmNIivUgYStfEAbXdrdjg BkyQ== X-Gm-Message-State: AAQBX9cnz290pbHN1JeigiCjHH1bm52/m6QS93tmgTfB/r+4stPOc4Q+ s18lTz0YD1csl1EYP9+f9xBBqTZIOgvnkvlIug== X-Google-Smtp-Source: AKy350aUc53Va1zkms/tZeMPTaKwPOXFpbnBKZFuGedztjHPQD03PotiB50/sPjZNhzfTmekJxf45Wmqylq6+Y7Cgw== X-Received: from ackerleytng-cloudtop.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:1f5f]) (user=ackerleytng job=sendgmr) by 2002:a05:6a00:a1b:b0:62d:dade:825 with SMTP id p27-20020a056a000a1b00b0062ddade0825mr6152408pfh.3.1681176578151; Mon, 10 Apr 2023 18:29:38 -0700 (PDT) Date: Tue, 11 Apr 2023 01:29:32 +0000 In-Reply-To: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.40.0.577.gac1e443424-goog Message-ID: Subject: [RFC PATCH v4 1/2] mm: restrictedmem: Allow userspace to specify mount for memfd_restricted From: Ackerley Tng To: kvm@vger.kernel.org, linux-api@vger.kernel.org, linux-arch@vger.kernel.org, linux-doc@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, qemu-devel@nongnu.org Cc: aarcange@redhat.com, ak@linux.intel.com, akpm@linux-foundation.org, arnd@arndb.de, bfields@fieldses.org, bp@alien8.de, chao.p.peng@linux.intel.com, corbet@lwn.net, dave.hansen@intel.com, david@redhat.com, ddutile@redhat.com, dhildenb@redhat.com, hpa@zytor.com, hughd@google.com, jlayton@kernel.org, jmattson@google.com, joro@8bytes.org, jun.nakajima@intel.com, kirill.shutemov@linux.intel.com, linmiaohe@huawei.com, luto@kernel.org, mail@maciej.szmigiero.name, mhocko@suse.com, michael.roth@amd.com, mingo@redhat.com, naoya.horiguchi@nec.com, pbonzini@redhat.com, qperret@google.com, rppt@kernel.org, seanjc@google.com, shuah@kernel.org, steven.price@arm.com, tabba@google.com, tglx@linutronix.de, vannapurve@google.com, vbabka@suse.cz, vkuznets@redhat.com, wanpengli@tencent.com, wei.w.wang@intel.com, x86@kernel.org, yu.c.zhang@linux.intel.com, Ackerley Tng X-Stat-Signature: 9entxgwtb83168dsykkpwpxtyy19qu1b X-Rspam-User: X-Rspamd-Queue-Id: 75280180010 X-Rspamd-Server: rspam06 X-HE-Tag: 1681176579-626222 X-HE-Meta: U2FsdGVkX18gy+1KnEFctfRM7hUkoSoRAABe/rF2ko7FFxfXmMp5wuL0AYDSARK9kwbfXzU80siERYBTf8RBOsM88z7CedPvK1HMJT8I2D1mr+AYj7myohZT3kObDgS/6ydv+echIkeQgr8trVkgmBC1YxR3bJgS4BHV22a65ObVZFXc+rtTkDcd6MBU9bBvDMUH7ajwnLBSWLWknHkzSvDNa4eaaeW5YGtBG3J7FpKN13XWrIyrgE9p+rJjCW6/3UPmTPReqSqgBEClykMlhH04jDsZQhk56OnyimNMqIAb7Tu5jeKE8pQkQHYSITpnuSNEC4+W1XJ1Npg2MzdWxqMLLXlV5xjXfFTaHK5sLB/q9NjSYR93NBxYaCk75Crc0FXeVcU7N5sGS62YIvjhXUbFa2Llg1IMRkSbV8JHqQtd+2iUvdsTqpRizmPl8W9mVVGnlvJ/B0UNEGKXtkbCrpJDOG7GtwPBbmf4B4wmWxSR99CaF9Snb1nXuMqtzvA3saDsGs4FnJVTdr+7zcMi4jgJTk/AZryx6xECOV5xA3mL8HnCN6ubDlXXGOXmEA53ivygL0Kn/rjTgFeLyquZbQlZiyfHI/o4M738vMb4xrRhBWm400OQhFwsVK8xsGbEtOHyynk5w0vJ3MUsxPzp+0vxFnQgehQ04nyEt/5RtUe+jjDBwuqQraQkm40sHe+B54MtTvm9IoH6JIZUw7ebSZ8QdzsV6oMLGbBRk0+67PEa10+waE7XoEHQ0h3tw45yA5xuLBr/KSnW9KkVWzUVRKHhqJloKsEvM8vxKyyr8FRvRAHY5fzTKgqKraqy94MMXLiYp+faocC8AQyHqxVUeOe46gHXFY1Y91066/VibFOBzjhkh0v/ZoSIy4b0D/NvXOjDG62lirxSk5c7Sxlz71EQ4rVURbB6E8yjuIeRK//pgaK535hrvXwEI77ortVNA3ZqXaVlU4cNPUqw0dp KkRJLUtb ZyOxR6PU9EQmtxm9nG9DqXry5gJJ1zjtzzfRBTSaMmO1fv+mlL+CUyDjPiYwzBeUFBVbYYAB48ogFPFCeTUyoumKDr0ywOUdaOg2m2SEirDqXLPosm+sLj5v2mrAp1Y3p6SJcBeDlXE5iVtws1+LrLUphptIhsAZa6Ajg9pmnMjLToFbDL/I4UUkq00QlDuON3HGm2uVdQz1mrnQ86AbEh5RRcfhh7Q6L9Nw9rr1pme3AZ3Py/z0EXI6qGYnxuakdjYS4dJaRqnDFymiYeAPUBSVaZA6srhkbet+ZalzVN7jnhlxyRfMw5GHfvHzaM3x+VDadVezslyfJeVACg2wnck5IDd9uHPC688iqCx8GLhOeo67i3rIJ+9roFF4RAk40ZW/O9ieydP5SLREY+F9MFvgnQNX8x1n7sH3nxQnGeHMTh+APFiLgEsncrgH6Hx9pQSRxzJJgsaXRmHKCegGYgRJiJEpD+hvlzyP3nYkgZbOvQ5wJh+n2kNCvECgBPMhgaY4UNfxPSmJq1DesK5ZewhPuHk5eQSekzzfMEiclxDHZcM2VMVoZ71h8cNcL9iZ+mrsxLC3e9rrzeGDsUnPp3VBAVijNvVzhX1JdUEqJYvpGrVPTOo96KE5NTp1YoEVYz0eBexRRQC9mXnpHwxKTmYF4Ih4L0YldnYYn6IbWyyuf6q7s+H5sfCSv9/8Vv3nMDy6V8amDQXabnSp4cV7o3O6kjw== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: By default, the backing shmem file for a restrictedmem fd is created on shmem's kernel space mount. With this patch, an optional tmpfs mount can be specified via an fd, which will be used as the mountpoint for backing the shmem file associated with a restrictedmem fd. This will help restrictedmem fds inherit the properties of the provided tmpfs mounts, for example, hugepage (THP) allocation hints, NUMA binding hints, etc. Permissions for the fd passed to memfd_restricted() is modeled after the openat() syscall, since both of these allow creation of a file upon a mount/directory. Permission to reference the mount the fd represents is checked upon fd creation by other syscalls (e.g. fsmount(), open(), or open_tree(), etc) and any process that can present memfd_restricted() with a valid fd is expected to have obtained permission to use the mount represented by the fd. This behavior is intended to parallel that of the openat() syscall. memfd_restricted() will check that the tmpfs superblock is writable, and that the mount is also writable, before attempting to create a restrictedmem file on the mount. Signed-off-by: Ackerley Tng --- include/linux/syscalls.h | 2 +- include/uapi/linux/restrictedmem.h | 8 ++++ mm/restrictedmem.c | 73 ++++++++++++++++++++++++++++-- 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 include/uapi/linux/restrictedmem.h diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 660be0bf89d5..90c73b9e14e5 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -1058,7 +1058,7 @@ asmlinkage long sys_memfd_secret(unsigned int flags); asmlinkage long sys_set_mempolicy_home_node(unsigned long start, unsigned long len, unsigned long home_node, unsigned long flags); -asmlinkage long sys_memfd_restricted(unsigned int flags); +asmlinkage long sys_memfd_restricted(unsigned int flags, int mount_fd); /* * Architecture-specific system calls diff --git a/include/uapi/linux/restrictedmem.h b/include/uapi/linux/restrictedmem.h new file mode 100644 index 000000000000..73e31bce73dc --- /dev/null +++ b/include/uapi/linux/restrictedmem.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_LINUX_RESTRICTEDMEM_H +#define _UAPI_LINUX_RESTRICTEDMEM_H + +/* flags for memfd_restricted */ +#define MEMFD_RSTD_USERMNT 0x0001U + +#endif /* _UAPI_LINUX_RESTRICTEDMEM_H */ diff --git a/mm/restrictedmem.c b/mm/restrictedmem.c index 55e99e6c09a1..032ad1f15138 100644 --- a/mm/restrictedmem.c +++ b/mm/restrictedmem.c @@ -6,6 +6,7 @@ #include #include #include +#include #include struct restrictedmem { @@ -250,19 +251,20 @@ static struct address_space_operations restricted_aops = { #endif }; -SYSCALL_DEFINE1(memfd_restricted, unsigned int, flags) +static int restrictedmem_create(struct vfsmount *mount) { struct file *file, *restricted_file; int fd, err; - if (flags) - return -EINVAL; - fd = get_unused_fd_flags(0); if (fd < 0) return fd; - file = shmem_file_setup("memfd:restrictedmem", 0, VM_NORESERVE); + if (mount) + file = shmem_file_setup_with_mnt(mount, "memfd:restrictedmem", 0, VM_NORESERVE); + else + file = shmem_file_setup("memfd:restrictedmem", 0, VM_NORESERVE); + if (IS_ERR(file)) { err = PTR_ERR(file); goto err_fd; @@ -286,6 +288,67 @@ SYSCALL_DEFINE1(memfd_restricted, unsigned int, flags) return err; } +static struct vfsmount *restrictedmem_get_user_mount(struct file *file) +{ + int ret; + struct vfsmount *mnt; + struct path *path; + + path = &file->f_path; + if (path->dentry != path->mnt->mnt_root) + return ERR_PTR(-EINVAL); + + /* + * Disallow bind-mounts that aren't bind-mounts of the whole + * filesystem + */ + mnt = path->mnt; + if (mnt->mnt_root != mnt->mnt_sb->s_root) + return ERR_PTR(-EINVAL); + + if (mnt->mnt_sb->s_magic != TMPFS_MAGIC) + return ERR_PTR(-EINVAL); + + ret = mnt_want_write(mnt); + if (ret) + return ERR_PTR(ret); + + return mnt; +} + +SYSCALL_DEFINE2(memfd_restricted, unsigned int, flags, int, mount_fd) +{ + int ret; + struct fd f = {}; + struct vfsmount *mnt = NULL; + + if (flags & ~MEMFD_RSTD_USERMNT) + return -EINVAL; + + if (flags & MEMFD_RSTD_USERMNT) { + f = fdget_raw(mount_fd); + if (!f.file) + return -EBADF; + + mnt = restrictedmem_get_user_mount(f.file); + if (IS_ERR(mnt)) { + ret = PTR_ERR(mnt); + goto out; + } + } + + ret = restrictedmem_create(mnt); + + if (mnt) + mnt_drop_write(mnt); + +out: + if (f.file) + fdput(f); + + return ret; +} + int restrictedmem_bind(struct file *file, pgoff_t start, pgoff_t end, struct restrictedmem_notifier *notifier, bool exclusive) { From patchwork Tue Apr 11 01:29:33 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ackerley Tng X-Patchwork-Id: 13206946 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4FB74C77B70 for ; Tue, 11 Apr 2023 01:29:43 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id DA0F1280042; Mon, 10 Apr 2023 21:29:42 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id CDAE528003C; Mon, 10 Apr 2023 21:29:42 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id ADF61280042; Mon, 10 Apr 2023 21:29:42 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 9A53328003C for ; Mon, 10 Apr 2023 21:29:42 -0400 (EDT) Received: from smtpin24.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id 6D793120925 for ; Tue, 11 Apr 2023 01:29:42 +0000 (UTC) X-FDA: 80667378204.24.A380C8D Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.201]) by imf06.hostedemail.com (Postfix) with ESMTP id 9A122180007 for ; Tue, 11 Apr 2023 01:29:40 +0000 (UTC) Authentication-Results: imf06.hostedemail.com; dkim=pass header.d=google.com header.s=20210112 header.b="dNu/0kye"; dmarc=pass (policy=reject) header.from=google.com; spf=pass (imf06.hostedemail.com: domain of 3A7g0ZAsKCG4MOWQdXQkfZSSaaSXQ.OaYXUZgj-YYWhMOW.adS@flex--ackerleytng.bounces.google.com designates 209.85.128.201 as permitted sender) smtp.mailfrom=3A7g0ZAsKCG4MOWQdXQkfZSSaaSXQ.OaYXUZgj-YYWhMOW.adS@flex--ackerleytng.bounces.google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1681176580; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=SUMdFa7+PPMn99YcGlnAfohLLYbWjlEJWXPRhdQ3G0w=; b=Hjq8OdYuCy6L7bQONtQEGTWpeEoFMVoIPCJGncFG6pElBL9+TzGqPUNvyIP9JU1sJ4nX0Y Alzs0GmrqkOOczmq5YbSfcyoX98QpCryHpRm9JAt2SyZbw2TYYQz0R/CZei4jGseDZuB25 rrXg8d/ouoC71/WMTyv5wIi271CDCb8= ARC-Authentication-Results: i=1; imf06.hostedemail.com; dkim=pass header.d=google.com header.s=20210112 header.b="dNu/0kye"; dmarc=pass (policy=reject) header.from=google.com; spf=pass (imf06.hostedemail.com: domain of 3A7g0ZAsKCG4MOWQdXQkfZSSaaSXQ.OaYXUZgj-YYWhMOW.adS@flex--ackerleytng.bounces.google.com designates 209.85.128.201 as permitted sender) smtp.mailfrom=3A7g0ZAsKCG4MOWQdXQkfZSSaaSXQ.OaYXUZgj-YYWhMOW.adS@flex--ackerleytng.bounces.google.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1681176580; a=rsa-sha256; cv=none; b=t2z4Q8JiwFmMwaZHOYa93bb+ExP9xU+9hm9Fah5OqWSx3ngsobSsIXkPs/n0aKRD+yC7GN go4tpkJPl+frT5xfaB5kW1Tv6Vv5yJ8cIzFGUX9qaaMQQ6TW3aDrhs/RBy7ffnZW66LiOy DZ/TlmVdNcFEx7wDDrrXdPINKGP3Sgc= Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-54ee12aa4b5so69674857b3.4 for ; Mon, 10 Apr 2023 18:29:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; t=1681176579; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=SUMdFa7+PPMn99YcGlnAfohLLYbWjlEJWXPRhdQ3G0w=; b=dNu/0kyeO3qOPRZoLxVrEerm7CEz0UanDuC4SpEIAgDGGUUTxG9O1Shz6EbKjLQiwb yoUIt/+hkqHAEpHwZGwN8kETFVGwAf4SHl4l6Azw2KSG5wC8sfnwLqJmRk4iEeyEQf9f oSO0XGYUjrAvPuxbiAzo6eftA4Ww7y0Y8f+f1aVbAtv8GrYrfAYfqPbRhutYYAA7QZko SSFw/1BdUEQB6U6kJroFjmRbZ9hGtSB/MCPD5AQBubHHM7fgMQAPHPYfHIJu6R9HKC6m 72CFtjnQm040lc/QhC3VxSLpCyTV1P5hyFF+/KkqtiTZjjxQQV2TR19srrLtSl1HfCKJ ScRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1681176580; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=SUMdFa7+PPMn99YcGlnAfohLLYbWjlEJWXPRhdQ3G0w=; b=ekmYZ7GyLAOyqMZV7WJkYEwj4SpHz/CG3PWUGOMdAR1m9cqH9CKsOavU5hMpdqLtkL 5cRm63NazCxErinu4hG2D5iCiz/J2J0TltePzrD2xdg9CgfwJFMUESTYZYCOlXhQetuN 8CU/TkgyjkhRNL0eS8J1uaJ3+vflBeTTcvQ+IEaAjYuf4PYDE8hhaRpBZ+gXyk+00SET JFj20K2QAUZuZHTH8QpHHdh9gSEc+bL7miZUCx7s++N46A+ZGc4Ok+DBeQ8E9L7hsAsw c4nLK2CanPFTCf+t0k+yG3qyhpU/m7ncO789Xy7MUlXO1FsxxiA5ND+25+6qKMFTGC01 lQXg== X-Gm-Message-State: AAQBX9cu8CxX0E7Zg/a0caKWYduPi9tiMEHfRW7LWtXxwZigvGu2RPNG 9V4ytqcHNpWm0jI1z61Ww47V0MMa93nLavnTpw== X-Google-Smtp-Source: AKy350aWx1LEWUOf1FrnrMDEm7YGoW5Jf5E4LFqJ8ZnxfEUyPVRZ2iMsx9R9r5E7bVHQTgok7giMc8dxwwldHsZMKw== X-Received: from ackerleytng-cloudtop.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:1f5f]) (user=ackerleytng job=sendgmr) by 2002:a05:6902:909:b0:a27:3ecc:ffe7 with SMTP id bu9-20020a056902090900b00a273eccffe7mr10712313ybb.3.1681176579771; Mon, 10 Apr 2023 18:29:39 -0700 (PDT) Date: Tue, 11 Apr 2023 01:29:33 +0000 In-Reply-To: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.40.0.577.gac1e443424-goog Message-ID: <2a733e3ed673c3b9d6b1a5fcb6625953da042f42.1681176340.git.ackerleytng@google.com> Subject: [RFC PATCH v4 2/2] selftests: restrictedmem: Check memfd_restricted()'s handling of provided userspace mount From: Ackerley Tng To: kvm@vger.kernel.org, linux-api@vger.kernel.org, linux-arch@vger.kernel.org, linux-doc@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, qemu-devel@nongnu.org Cc: aarcange@redhat.com, ak@linux.intel.com, akpm@linux-foundation.org, arnd@arndb.de, bfields@fieldses.org, bp@alien8.de, chao.p.peng@linux.intel.com, corbet@lwn.net, dave.hansen@intel.com, david@redhat.com, ddutile@redhat.com, dhildenb@redhat.com, hpa@zytor.com, hughd@google.com, jlayton@kernel.org, jmattson@google.com, joro@8bytes.org, jun.nakajima@intel.com, kirill.shutemov@linux.intel.com, linmiaohe@huawei.com, luto@kernel.org, mail@maciej.szmigiero.name, mhocko@suse.com, michael.roth@amd.com, mingo@redhat.com, naoya.horiguchi@nec.com, pbonzini@redhat.com, qperret@google.com, rppt@kernel.org, seanjc@google.com, shuah@kernel.org, steven.price@arm.com, tabba@google.com, tglx@linutronix.de, vannapurve@google.com, vbabka@suse.cz, vkuznets@redhat.com, wanpengli@tencent.com, wei.w.wang@intel.com, x86@kernel.org, yu.c.zhang@linux.intel.com, Ackerley Tng X-Rspamd-Queue-Id: 9A122180007 X-Rspamd-Server: rspam09 X-Rspam-User: X-Stat-Signature: mmpp8b1trqyabn5pxga76ss9y871aon1 X-HE-Tag: 1681176580-694893 X-HE-Meta: U2FsdGVkX1+Sy0CvPmka6ixoCCJjNNUvUBssKSLTzH+yL+ww86D9wYEehGLj98zEuLn9WOHFuo8d2Xyq/MpbJk7dbEwW07vyhL6qRLYVtb8/HCisMS6ytagONP2TwNpr57KzAy3VL5mkS/3Jkh6PXsR/vj1CVO/8QhSxP/9oN1kxN+flRKNEh+je/Uq33zl8sh2zh660xusODzQ5lNK/tgH6YD5VQKreIUu9ln5IB5fcj/70BtcAYTkIQm/e+HlziAkWSPxhTM0GH67tAS7GPOsoFu3+9lCCQrB8AnTbP083enuZOfQQuywPwwsi8yqllMXWOOTZAkLdiewRefNaq4C30UBfQ5oID3bePiNwtpoYDoWVwBM05I2o3saJGFVCmIBaJEN7jpD7vVzrpanNW5kfrBL+i+rLVQdeWgoscpcueTwc/FPFzVh2o1Fq5QYO62AdJLutKHzvtEAUriuhDEZui+20qthBOzASRUNHxcOxC17Hzu/p16MmyTroNPFQECXLawmNrvnr4nobf1bxSYdXbO0BeDxlHyITwqHy6kXSAZGIIDF2W8XjWA87bY78vACYaoOVSk8TvSzOiUakNMtFLBFQKi2zR138lbK3f3PRpeG7o5ARt93QBHbh2YW3AccAFWL2evSkVoIUcsDa7mwvpLvkhtopsnAOwrS+BQ+Nfo782/ue1ksrkT1Y0u/OVh7AvuvN/0kZqwQGj2MJ8tXuBr/ve+MjnBEZC91/gxx3I735jpoa9rNPSiYjknRrOd42TVedHwIWkY2FhWnGf8p3W2A8VlbZ8VZz+twllkLV2aFpTvHRU3/Qo7FkDhKVHNnE43495zDblXAA7DEH7FAQUVweYlbjDwr6qLeA7QN6sjAzjcJtCUyxKxnddQ3Kmqu5vVCdyK4lDnuPtBTY8n7AhIfEaCJ9ELVdHq1hN6cWf57vAHd4qaL3obiR3oBJLn8/jao9IFRP+WzhtBN YrIIr3SU 34y7cq5so2PZLfPMXq9w5TUWBufWdRf3xcOulh/8RJOtFhPIPKbZfcnMRSdS7peX9g4h1aBXUIyru7AeGIdv9DdKZKevZZ+KgPJ6K/Q7jjXMkYiUWC3KlXOw11H9OhZp4ZG2d0XVgTtOO8KoFjdKzLi2G8pCsccpUKJbDJquQ4ZMqQsTgH9VMx1wmHvDgR27rXYAe7Z0YApaLPlurWIhiSNxzdXI2+datbvAIgbk6+ucOUybZgJQWcFVXtk9te+p9OAza4AIlbfdUx1D/EohxqJb+V8y5Oz0U7Lct7COxCW0y8GKidDSlIA+APxesML7Q8+Qfp2ujEOpH4azj29zXRbjG9bhBe1LxdPDpExe+f8wt9T3sY9E6Paragf3NBfJaaDaHJSRN7oTT6MW80GeeOKDWwaETWWMy3KT8lu1+F4MOrUhT013lEGoij7vllMnUCGxdIE39DB7WT7a5VJ6Wb/WRzVhrtKVtPEC/eolb7vqcgn16ZBmhPuDavWTkysVvG/0TKiOfu8kk3E1wPaV/hu5r3G1dOZszy05mZzXm3YjcpMmHNs9uewgRaLS7k/5+QyTZ+ExG4tCvV7Cxl8JdHDD3br/ga+yHU3Ff84/pYc+JXRlSO2MYa+VRKy/X2PG+RrG7QgdhC+GT8iDvRQGXSYxESXMq+ax6EaZf9RpW0j4UWG1GxTxOqwc/0hsf8NEz6ZJJBMizM1JR1JWjz3mN7nLI6g== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: For memfd_restricted() calls without a userspace mount, the backing file should be the shmem mount in the kernel, and the size of backing pages should be as defined by system-wide shmem configuration. If a userspace mount is provided, the size of backing pages should be as defined in the mount. Also includes negative tests for invalid inputs, including fds representing read-only superblocks/mounts. Signed-off-by: Ackerley Tng --- tools/testing/selftests/mm/.gitignore | 1 + tools/testing/selftests/mm/Makefile | 1 + .../selftests/mm/memfd_restricted_usermnt.c | 529 ++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 3 + 4 files changed, 534 insertions(+) create mode 100644 tools/testing/selftests/mm/memfd_restricted_usermnt.c diff --git a/tools/testing/selftests/mm/.gitignore b/tools/testing/selftests/mm/.gitignore index fb6e4233374d..dba320c8151a 100644 --- a/tools/testing/selftests/mm/.gitignore +++ b/tools/testing/selftests/mm/.gitignore @@ -31,6 +31,7 @@ map_fixed_noreplace write_to_hugetlbfs hmm-tests memfd_restricted +memfd_restricted_usermnt memfd_secret soft-dirty split_huge_page_test diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index 5ec338ea1fed..2f5df7a12ea5 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -46,6 +46,7 @@ TEST_GEN_FILES += map_fixed_noreplace TEST_GEN_FILES += map_hugetlb TEST_GEN_FILES += map_populate TEST_GEN_FILES += memfd_restricted +TEST_GEN_FILES += memfd_restricted_usermnt TEST_GEN_FILES += memfd_secret TEST_GEN_FILES += migration TEST_GEN_FILES += mlock-random-test diff --git a/tools/testing/selftests/mm/memfd_restricted_usermnt.c b/tools/testing/selftests/mm/memfd_restricted_usermnt.c new file mode 100644 index 000000000000..0be04e3d714d --- /dev/null +++ b/tools/testing/selftests/mm/memfd_restricted_usermnt.c @@ -0,0 +1,529 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define _GNU_SOURCE /* for O_PATH */ +#define _POSIX_C_SOURCE /* for PATH_MAX */ +#include +#include +#include +#include + +#include "linux/restrictedmem.h" + +#include "../kselftest_harness.h" + +static int memfd_restricted(unsigned int flags, int fd) +{ + return syscall(__NR_memfd_restricted, flags, fd); +} + +static int get_hpage_pmd_size(void) +{ + FILE *fp; + char buf[100]; + char *ret; + int size; + + fp = fopen("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", "r"); + if (!fp) + return -1; + + ret = fgets(buf, 100, fp); + if (ret != buf) { + size = -1; + goto out; + } + + if (sscanf(buf, "%d\n", &size) != 1) + size = -1; + +out: + fclose(fp); + + return size; +} + +static int write_string_to_file(const char *path, const char *string) +{ + FILE *fp; + size_t len = strlen(string); + int ret = -1; + + fp = fopen(path, "w"); + if (!fp) + return ret; + + if (fwrite(string, 1, len, fp) != len) + goto out; + + ret = 0; + +out: + fclose(fp); + return ret; +} + +/* + * Expect shmem thp policy to be one of always, within_size, advise, never, + * deny, force + */ +#define POLICY_BUF_SIZE 12 + +static bool is_valid_shmem_thp_policy(char *policy) +{ + if (strcmp(policy, "always") == 0) + return true; + if (strcmp(policy, "within_size") == 0) + return true; + if (strcmp(policy, "advise") == 0) + return true; + if (strcmp(policy, "never") == 0) + return true; + if (strcmp(policy, "deny") == 0) + return true; + if (strcmp(policy, "force") == 0) + return true; + + return false; +} + +static int get_shmem_thp_policy(char *policy) +{ + FILE *fp; + char buf[100]; + char *left = NULL; + char *right = NULL; + int ret = -1; + + fp = fopen("/sys/kernel/mm/transparent_hugepage/shmem_enabled", "r"); + if (!fp) + return -1; + + if (fgets(buf, 100, fp) != buf) + goto out; + + /* + * Expect shmem_enabled to be of format like "always within_size advise + * [never] deny force" + */ + left = memchr(buf, '[', 100); + if (!left) + goto out; + + right = memchr(buf, ']', 100); + if (!right) + goto out; + + memcpy(policy, left + 1, right - left - 1); + + ret = !is_valid_shmem_thp_policy(policy); + +out: + fclose(fp); + return ret; +} + +static int set_shmem_thp_policy(char *policy) +{ + int ret = -1; + /* +1 for newline */ + char to_write[POLICY_BUF_SIZE + 1] = { 0 }; + + if (!is_valid_shmem_thp_policy(policy)) + return ret; + + ret = snprintf(to_write, POLICY_BUF_SIZE + 1, "%s\n", policy); + if (ret != strlen(policy) + 1) + return -1; + + ret = write_string_to_file( + "/sys/kernel/mm/transparent_hugepage/shmem_enabled", to_write); + + return ret; +} + +FIXTURE(reset_shmem_enabled) +{ + char shmem_enabled[POLICY_BUF_SIZE]; +}; + +FIXTURE_SETUP(reset_shmem_enabled) +{ + memset(self->shmem_enabled, 0, POLICY_BUF_SIZE); + ASSERT_EQ(get_shmem_thp_policy(self->shmem_enabled), 0); +} + +FIXTURE_TEARDOWN(reset_shmem_enabled) +{ + ASSERT_EQ(set_shmem_thp_policy(self->shmem_enabled), 0); +} + +TEST_F(reset_shmem_enabled, restrictedmem_fstat_shmem_enabled_never) +{ + int fd = -1; + struct stat stat; + + ASSERT_EQ(set_shmem_thp_policy("never"), 0); + + fd = memfd_restricted(0, -1); + ASSERT_GT(fd, 0); + + ASSERT_EQ(fstat(fd, &stat), 0); + + /* + * st_blksize is set based on the superblock's s_blocksize_bits. For + * shmem, this is set to PAGE_SHIFT + */ + ASSERT_EQ(stat.st_blksize, getpagesize()); + + close(fd); +} + +TEST_F(reset_shmem_enabled, restrictedmem_fstat_shmem_enabled_always) +{ + int fd = -1; + struct stat stat; + + ASSERT_EQ(set_shmem_thp_policy("always"), 0); + + fd = memfd_restricted(0, -1); + ASSERT_GT(fd, 0); + + ASSERT_EQ(fstat(fd, &stat), 0); + + ASSERT_EQ(stat.st_blksize, get_hpage_pmd_size()); + + close(fd); +} + +TEST(restrictedmem_tmpfile_invalid_fd) +{ + int fd = memfd_restricted(MEMFD_RSTD_USERMNT, -2); + + ASSERT_EQ(fd, -1); + ASSERT_EQ(errno, EBADF); +} + +TEST(restrictedmem_tmpfile_fd_not_a_mount) +{ + int fd = memfd_restricted(MEMFD_RSTD_USERMNT, STDOUT_FILENO); + + ASSERT_EQ(fd, -1); + ASSERT_EQ(errno, EINVAL); +} + +TEST(restrictedmem_tmpfile_not_tmpfs_mount) +{ + int fd = -1; + int mfd = -1; + + mfd = open("/proc", O_PATH); + ASSERT_NE(mfd, -1); + + fd = memfd_restricted(MEMFD_RSTD_USERMNT, mfd); + + ASSERT_EQ(fd, -1); + ASSERT_EQ(errno, EINVAL); +} + +FIXTURE(tmpfs_sfd) +{ + int sfd; +}; + +FIXTURE_SETUP(tmpfs_sfd) +{ + self->sfd = fsopen("tmpfs", 0); + ASSERT_NE(self->sfd, -1); +} + +FIXTURE_TEARDOWN(tmpfs_sfd) +{ + EXPECT_EQ(close(self->sfd), 0); +} + +TEST_F(tmpfs_sfd, restrictedmem_fstat_tmpfs_huge_always) +{ + int ret = -1; + int fd = -1; + int mfd = -1; + struct stat stat; + + fsconfig(self->sfd, FSCONFIG_SET_STRING, "huge", "always", 0); + fsconfig(self->sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); + + mfd = fsmount(self->sfd, 0, 0); + ASSERT_NE(mfd, -1); + + fd = memfd_restricted(MEMFD_RSTD_USERMNT, mfd); + ASSERT_GT(fd, 0); + + /* User can close reference to mount */ + ret = close(mfd); + ASSERT_EQ(ret, 0); + + ret = fstat(fd, &stat); + ASSERT_EQ(ret, 0); + ASSERT_EQ(stat.st_blksize, get_hpage_pmd_size()); + + close(fd); +} + +TEST_F(tmpfs_sfd, restrictedmem_fstat_tmpfs_huge_never) +{ + int ret = -1; + int fd = -1; + int mfd = -1; + struct stat stat; + + fsconfig(self->sfd, FSCONFIG_SET_STRING, "huge", "never", 0); + fsconfig(self->sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); + + mfd = fsmount(self->sfd, 0, 0); + ASSERT_NE(mfd, -1); + + fd = memfd_restricted(MEMFD_RSTD_USERMNT, mfd); + ASSERT_GT(fd, 0); + + /* User can close reference to mount */ + ret = close(mfd); + ASSERT_EQ(ret, 0); + + ret = fstat(fd, &stat); + ASSERT_EQ(ret, 0); + ASSERT_EQ(stat.st_blksize, getpagesize()); + + close(fd); +} + +TEST_F(tmpfs_sfd, restrictedmem_check_mount_flags) +{ + int ret = -1; + int fd = -1; + int mfd = -1; + + fsconfig(self->sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); + + mfd = fsmount(self->sfd, 0, MOUNT_ATTR_RDONLY); + ASSERT_NE(mfd, -1); + + fd = memfd_restricted(MEMFD_RSTD_USERMNT, mfd); + ASSERT_EQ(fd, -1); + ASSERT_EQ(errno, EROFS); + + ret = close(mfd); + ASSERT_EQ(ret, 0); +} + +TEST_F(tmpfs_sfd, restrictedmem_check_superblock_flags) +{ + int ret = -1; + int fd = -1; + int mfd = -1; + + fsconfig(self->sfd, FSCONFIG_SET_FLAG, "ro", NULL, 0); + fsconfig(self->sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0); + + mfd = fsmount(self->sfd, 0, 0); + ASSERT_NE(mfd, -1); + + fd = memfd_restricted(MEMFD_RSTD_USERMNT, mfd); + ASSERT_EQ(fd, -1); + ASSERT_EQ(errno, EROFS); + + ret = close(mfd); + ASSERT_EQ(ret, 0); +} + +static bool directory_exists(const char *path) +{ + struct stat sb; + + return stat(path, &sb) == 0 && S_ISDIR(sb.st_mode); +} + +FIXTURE(restrictedmem_test_mount_path) +{ + char *mount_path; +}; + +FIXTURE_SETUP(restrictedmem_test_mount_path) +{ + int ret = -1; + + /* /tmp is an FHS-mandated world-writable directory */ + self->mount_path = "/tmp/restrictedmem-selftest-mnt"; + + if (!directory_exists(self->mount_path)) { + ret = mkdir(self->mount_path, 0777); + ASSERT_EQ(ret, 0); + } +} + +FIXTURE_TEARDOWN(restrictedmem_test_mount_path) +{ + int ret = -1; + + if (!directory_exists(self->mount_path)) + return; + + ret = umount2(self->mount_path, MNT_FORCE); + EXPECT_EQ(ret, 0); + if (ret == -1 && errno == EINVAL) + fprintf(stderr, " %s was not mounted\n", self->mount_path); + + ret = rmdir(self->mount_path); + EXPECT_EQ(ret, 0); + if (ret == -1) + fprintf(stderr, " rmdir(%s) failed: %m\n", self->mount_path); +} + +/* + * memfd_restricted() syscall can only be used with the fd of the root of the + * mount. When the restrictedmem's fd is open, a user should not be able to + * unmount or remove the mounted directory + */ +TEST_F(restrictedmem_test_mount_path, restrictedmem_umount_rmdir_while_file_open) +{ + int ret = -1; + int fd = -1; + int mfd = -1; + struct stat stat; + + ret = mount("name", self->mount_path, "tmpfs", 0, "huge=always"); + ASSERT_EQ(ret, 0); + + mfd = open(self->mount_path, O_PATH); + ASSERT_NE(mfd, -1); + + fd = memfd_restricted(MEMFD_RSTD_USERMNT, mfd); + ASSERT_GT(fd, 0); + + /* We don't need this reference to the mount anymore */ + ret = close(mfd); + ASSERT_EQ(ret, 0); + + /* restrictedmem's fd should still be usable */ + ret = fstat(fd, &stat); + ASSERT_EQ(ret, 0); + ASSERT_EQ(stat.st_blksize, get_hpage_pmd_size()); + + /* User should not be able to unmount directory */ + ret = umount2(self->mount_path, MNT_FORCE); + ASSERT_EQ(ret, -1); + ASSERT_EQ(errno, EBUSY); + + ret = rmdir(self->mount_path); + ASSERT_EQ(ret, -1); + ASSERT_EQ(errno, EBUSY); + + close(fd); +} + +/* The fd of a file on the mount cannot be provided as mount_fd */ +TEST_F(restrictedmem_test_mount_path, restrictedmem_provide_fd_of_file) +{ + int ret = -1; + int fd = -1; + int ffd = -1; + char tmp_file_path[PATH_MAX] = { 0 }; + + ret = mount("name", self->mount_path, "tmpfs", 0, "huge=always"); + ASSERT_EQ(ret, 0); + + snprintf(tmp_file_path, PATH_MAX, "%s/tmp-file", self->mount_path); + ret = write_string_to_file(tmp_file_path, "filler\n"); + ASSERT_EQ(ret, 0); + + ffd = open(tmp_file_path, O_RDWR); + ASSERT_GT(ffd, 0); + + fd = memfd_restricted(MEMFD_RSTD_USERMNT, ffd); + ASSERT_LT(fd, 0); + ASSERT_EQ(errno, EINVAL); + + ret = close(ffd); + ASSERT_EQ(ret, 0); + + close(fd); + remove(tmp_file_path); +} + +/* The fd of files on the mount cannot be provided as mount_fd */ +TEST_F(restrictedmem_test_mount_path, restrictedmem_provide_fd_of_file_in_subdir) +{ + int ret = -1; + int fd = -1; + int ffd = -1; + char tmp_dir_path[PATH_MAX] = { 0 }; + char tmp_file_path[PATH_MAX] = { 0 }; + + ret = mount("name", self->mount_path, "tmpfs", 0, "huge=always"); + ASSERT_EQ(ret, 0); + + snprintf(tmp_dir_path, PATH_MAX, "%s/tmp-subdir", self->mount_path); + ret = mkdir(tmp_dir_path, 0777); + ASSERT_EQ(ret, 0); + + snprintf(tmp_file_path, PATH_MAX, "%s/tmp-subdir/tmp-file", + self->mount_path); + ret = write_string_to_file(tmp_file_path, "filler\n"); + ASSERT_EQ(ret, 0); + + ffd = open(tmp_file_path, O_RDWR); + ASSERT_NE(ffd, -1); + + fd = memfd_restricted(MEMFD_RSTD_USERMNT, ffd); + ASSERT_LT(fd, 0); + ASSERT_EQ(errno, EINVAL); + + ret = close(ffd); + ASSERT_EQ(ret, 0); + + remove(tmp_file_path); + rmdir(tmp_dir_path); +} + +/* + * fds representing bind mounts must represent the root of the original + * filesystem + */ +TEST_F(restrictedmem_test_mount_path, restrictedmem_provide_fd_of_original_fs) +{ + int ret = -1; + int fd = -1; + int mfd = -1; + char tmp_dir_path_0[PATH_MAX] = { 0 }; + char tmp_dir_path_1[PATH_MAX] = { 0 }; + + ret = mount("name", self->mount_path, "tmpfs", 0, "huge=always"); + ASSERT_EQ(ret, 0); + + snprintf(tmp_dir_path_0, PATH_MAX, "%s/tmp-subdir-0", self->mount_path); + ret = mkdir(tmp_dir_path_0, 0777); + ASSERT_EQ(ret, 0); + + snprintf(tmp_dir_path_1, PATH_MAX, "%s/tmp-subdir-1", self->mount_path); + ret = mkdir(tmp_dir_path_1, 0777); + ASSERT_EQ(ret, 0); + + ret = mount(tmp_dir_path_0, tmp_dir_path_1, "tmpfs", MS_BIND, NULL); + ASSERT_EQ(ret, 0); + + mfd = open(tmp_dir_path_1, O_PATH); + ASSERT_NE(mfd, -1); + + fd = memfd_restricted(MEMFD_RSTD_USERMNT, mfd); + ASSERT_LT(fd, 0); + ASSERT_EQ(errno, EINVAL); + + ret = close(mfd); + ASSERT_EQ(ret, 0); + + ret = umount2(tmp_dir_path_1, MNT_FORCE); + ASSERT_EQ(ret, 0); + + rmdir(tmp_dir_path_0); + rmdir(tmp_dir_path_1); +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh index 53de84e3ec2c..04238f86f037 100644 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -40,6 +40,8 @@ separated by spaces: test memadvise(2) MADV_POPULATE_{READ,WRITE} options - memfd_restricted_ test memfd_restricted(2) +- memfd_restricted_usermnt + test memfd_restricted(2)'s handling of provided userspace mounts - memfd_secret test memfd_secret(2) - process_mrelease @@ -239,6 +241,7 @@ CATEGORY="hmm" run_test ./test_hmm.sh smoke CATEGORY="madv_populate" run_test ./madv_populate CATEGORY="memfd_restricted" run_test ./memfd_restricted +CATEGORY="memfd_restricted_usermnt" run_test ./memfd_restricted_usermnt CATEGORY="memfd_secret" run_test ./memfd_secret