From patchwork Fri Mar 31 23:50:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ackerley Tng X-Patchwork-Id: 13196693 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 66D58C761A6 for ; Fri, 31 Mar 2023 23:50:53 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id C118A6B0074; Fri, 31 Mar 2023 19:50:52 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id BC2636B0075; Fri, 31 Mar 2023 19:50:52 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A63226B0078; Fri, 31 Mar 2023 19:50:52 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 979A66B0074 for ; Fri, 31 Mar 2023 19:50:52 -0400 (EDT) Received: from smtpin28.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 5B8551C6C5B for ; Fri, 31 Mar 2023 23:50:52 +0000 (UTC) X-FDA: 80630841144.28.796E065 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) by imf15.hostedemail.com (Postfix) with ESMTP id 9AD0DA0007 for ; Fri, 31 Mar 2023 23:50:49 +0000 (UTC) Authentication-Results: imf15.hostedemail.com; dkim=pass header.d=google.com header.s=20210112 header.b=aqbsmcr2; spf=pass (imf15.hostedemail.com: domain of 32HEnZAsKCIEfhpjwqj3ysllttlqj.htrqnsz2-rrp0fhp.twl@flex--ackerleytng.bounces.google.com designates 209.85.216.73 as permitted sender) smtp.mailfrom=32HEnZAsKCIEfhpjwqj3ysllttlqj.htrqnsz2-rrp0fhp.twl@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=1680306649; 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=67aN/B+WtOaSUEhiQW5ieKe9kdphJ9yXXZLhFTmAYCY=; b=nhokEBskJ6wc4EHh5awKkYulMRYuATIphRyP9VOkvKtkpcdQYuVeCWaForRXB7l0b6dG/G mumbEqnbVDR66w3R7kegY/00T1HLENl+1MOZNDDdCLAkj/y93oBCY2NGdN3zbpUPjXcG5D qgEw1sEc+x7yjynj6XIpn0zLy9iTQVA= ARC-Authentication-Results: i=1; imf15.hostedemail.com; dkim=pass header.d=google.com header.s=20210112 header.b=aqbsmcr2; spf=pass (imf15.hostedemail.com: domain of 32HEnZAsKCIEfhpjwqj3ysllttlqj.htrqnsz2-rrp0fhp.twl@flex--ackerleytng.bounces.google.com designates 209.85.216.73 as permitted sender) smtp.mailfrom=32HEnZAsKCIEfhpjwqj3ysllttlqj.htrqnsz2-rrp0fhp.twl@flex--ackerleytng.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1680306649; a=rsa-sha256; cv=none; b=70m9gGF7+Y+U/2V/3Fx53acdymdKET02/MKyYM+qMJLWiJCqOLJPxxAXub+kU+D7sywzWm KLmUXOhIxhuCSFSZkK5kip47WTlgQdkSXGXCCYBotcFjvvQ0UfDgV/m4LhbNpK0M+dThPu NdGIHUQdm3S9jwaJ1mTGDbFXqo/zjFM= Received: by mail-pj1-f73.google.com with SMTP id ml17-20020a17090b361100b0023f9e99ab95so11505516pjb.1 for ; Fri, 31 Mar 2023 16:50:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; t=1680306648; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=67aN/B+WtOaSUEhiQW5ieKe9kdphJ9yXXZLhFTmAYCY=; b=aqbsmcr2pK1zJc/QddLocmFe7u0eN9wv3vYw/b6U0d43YucmpKQusaaQyAaVSa0brL LpSKYapJtGiMflg5mvZkz3d5j4vniDYYeKTW9Q4ay1SgV2A+IZ22Cf6Rxm/yGJKvgMN8 SMKUd9my6zvqI6T79WbKu7yBu6efMqRgxeGWTlGD4T7pNs+f8J8J0byx5Zn/rGxIBacK RO2pdC/oG+kndVLe0/EN60h+Ufhb6JX9aJrTNcBTxw5DYOj8yvfJ2FTBeGdPqfrf3kJN vw3lhr7RqWCr8GoHdH9B4JRBqn6YLWfmu0XgDDbuD1vuUAihW3PD1pSNBYYD+O6dlOsv bwXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680306648; 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=67aN/B+WtOaSUEhiQW5ieKe9kdphJ9yXXZLhFTmAYCY=; b=fHid7dP8ctGxXh6NJnkpgQlL01CnsLjJB5MWiQuB/7LAK9VrOTi1EKxXpdjkbIf526 0s9yB6Y6LgPPrmOmGV9lzFh4VJWufzZd89SUjspP0U2xJ+/nWUn7ZL/7Dozl2OnOxPkV Z7NzfcP4fN+IHlCy0vSUtRh1XFJEmWwE2oOq+xr05tm2EylvHXdpXIjGJDgauJx5quCj wqWube4FLgPKolPubEU6rR9M92pZF2TGVztOVfxRUIXhdXGgFq9UWvRZ//B5wBUIXD+F EkfhQ+gCFhbP0C+l2k2HzStLAgdSIVv1gqdXYV5SVFdAXLlfGV0n98AeaEadst7EhILy EKcw== X-Gm-Message-State: AAQBX9dUyXWgrNuA6GwPIKu/fGCXTJEoleMBLLbHzPqrHzgT4TTwX9N+ Rw9du7Bn1Tsq9Lm35WuhU0MzAAct5Aoy88bCTA== X-Google-Smtp-Source: AKy350Y16oanl4juVqg+eyN21vJExuVR4y0XGk1EcBSjqL6yTWS/45m6tpDkpZOf1psTO3M9dHBN9cOBWfihqWNDiA== X-Received: from ackerleytng-cloudtop.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:1f5f]) (user=ackerleytng job=sendgmr) by 2002:a17:90a:ba0a:b0:23f:6eff:9430 with SMTP id s10-20020a17090aba0a00b0023f6eff9430mr9066957pjr.3.1680306648452; Fri, 31 Mar 2023 16:50:48 -0700 (PDT) Date: Fri, 31 Mar 2023 23:50:39 +0000 In-Reply-To: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.40.0.348.gf938b09366-goog Message-ID: <592ebd9e33a906ba026d56dc68f42d691706f865.1680306489.git.ackerleytng@google.com> Subject: [RFC PATCH v3 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-Rspamd-Queue-Id: 9AD0DA0007 X-Stat-Signature: xhfwhkws9fjhm67ktnq66i7yna8gkek8 X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1680306649-331081 X-HE-Meta: U2FsdGVkX1+es7sWHq0uAZS/yvtRmpR/oJ43kJ7kxUxtsC0k6g3tQe/bTnbOrI8n2WE7Lpv1EiWDjU/Og9OK6dLcmfLWxjgg3Hj2Jryh7J1ehlsDB3xDd3DYSl7V1NXHr5+yjJNR45XewQK/IyT89X+EePFBqIVt9lHYuqXdH7sCtpj983PQawmETbyTV97ELQv5GQMZm7wuITDWxFeWU/O7eU0IDJPKxYpuLaXqGLcbz1MoPowWEiyGdBMoyhKjOvKX2FMQAtS0mm2gWH8GG6JolcGIRtBY3x4wNU9ZUF9Ul4XJ+DLrkVmsDlf/OzHFWP6EuX5ibjh/nNNvy7bkrm0LYpJWCJM6Zf+5fpMKVu1ksgAPEaLUGNHa38U61wJPOZKeh2O9VyxxjqvAACG8s2VUOHzO+G2qO6aPL6gWE0SHIS02LYvUAQOqqBXyGOKWQb2yCFcu1d8lLhJzAYzJhldekMLphoySOgCxudiD0NVB6NXJuTh+WOI86V7hXT+L9A0gzZCz9dKXtoR0LmbUC9iPwY/N6kpnRTv+DbHNVhIaBbZYHf/V2Nrn2s0JAbNNS89PQ8ASAIsQa5Y4RVV2xD8I2gPuJvyz3+3EffHiT0nxUuyBFFDFVaArlH1YPnWZ5JXPT9T0cMfjTpzIWed2yforuwfmPOGCJymd8xj25ajTZL6NRKGwUdkO1mn2yOlw87WLGw0ZokBPW8H/iUrsdt6Crw1QBFvbVd5BHJHMXtrxxbpzSTuRV4rWHaIMqPwyn5/jUG8Qky1LQN1XplzLOImuY+tRgj+OieI+mrRu4HG/hvtXaPpe0G1VY17qGqV0A0NoSC3gSTsLMulyvemQXuzRuUziEUJ4VjKCZfyh4m0qkvH3bGB9UCyWKS27mIEDwItIwCUtyijblhcwu5ekQhVMkABp+MbetbDWeOjMvX/2dObD8CoDxH5Seg0gWlsQvb5Ug8z+xDutexSYyyu BQ7785fV RwR9NFmAysl+Qp+dRiFefztzIFYglON3mbyFTRxdFSQSmNG99Ry7XkzTqv2g77NROIy5gWSZHcfn+bUmEdgT2jrbQOr5WkY+I5YJCU4KkKWBCI9t7a5MqC7isWO6pocDenlGu7/4K7lkwD4oU/ISoBI9rKE6IvTrbWZAGLDBepMo0tZqURYuGsfgMwlL1bnNljTmyvNr7+21m5w3hsfYqeiX9nvxxjMQdCzk751BIgutzDORwAX3BwE0F0cK2c2SIF7JsAYV4fVnvqhkMVcIh3W0KuLvnwzs/GnAmIF2Dzz8M9JFj6n+MaEqnliuN++TD+N8la4P1a+n4PZbGv4jkGCZzY0o3oeiRR1UXjBitiQPBfpvBa6WQ0P50Zs/s8DZnbwwHVdN5c1FA9NEd3dDZHa2AoMOUs9M86L9T6Ew9uDrYYb2SHpzkmePbwxk6UCkry3myshDYQWmZ5RpMqlNHmOjow/jw6O30OFusxhLD4xg2ZIRU99dGuKDppWmq5NotuE/KG1lVXU5b8BbFPQxulUZpAxAU6tf4a89v4k1fD2RZo96zVnrZ3FVg/8MkuwMY0UlrxyquLtlQv2GqBg9L4fQIzykSyLMdGGeigdbERGcgcBORPfXKqaNXxvj+l4sL1Ve8gJfSnn0XnZ2hc8uAl6A5YJ44103+EbrAD6oc3O70BpnBKVdS0U4PJzgkBuT17HCo7OJok8npPis= 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 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 | 74 +++++++++++++++++++++++++++--- 3 files changed, 77 insertions(+), 7 deletions(-) create mode 100644 include/uapi/linux/restrictedmem.h -- 2.40.0.348.gf938b09366-goog diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index f9e9e0c820c5..a23c4c385cd3 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -1056,7 +1056,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..22d6f2285f6d --- /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 RMFD_USERMNT 0x0001U + +#endif /* _UAPI_LINUX_RESTRICTEDMEM_H */ diff --git a/mm/restrictedmem.c b/mm/restrictedmem.c index c5d869d8c2d8..f7b62364a31a 100644 --- a/mm/restrictedmem.c +++ b/mm/restrictedmem.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#include "linux/sbitmap.h" +#include #include #include #include #include #include #include +#include #include struct restrictedmem { @@ -189,19 +190,20 @@ static struct file *restrictedmem_file_create(struct file *memfd) return file; } -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; @@ -223,6 +225,66 @@ SYSCALL_DEFINE1(memfd_restricted, unsigned int, flags) return err; } +static bool is_shmem_mount(struct vfsmount *mnt) +{ + return mnt && mnt->mnt_sb && mnt->mnt_sb->s_magic == TMPFS_MAGIC; +} + +static bool is_mount_root(struct file *file) +{ + return file->f_path.dentry == file->f_path.mnt->mnt_root; +} + +static int restrictedmem_create_on_user_mount(int mount_fd) +{ + int ret; + struct fd f; + struct vfsmount *mnt; + + f = fdget_raw(mount_fd); + if (!f.file) + return -EBADF; + + ret = -EINVAL; + if (!is_mount_root(f.file)) + goto out; + + mnt = f.file->f_path.mnt; + if (!is_shmem_mount(mnt)) + goto out; + + ret = file_permission(f.file, MAY_WRITE | MAY_EXEC); + if (ret) + goto out; + + ret = mnt_want_write(mnt); + if (unlikely(ret)) + goto out; + + ret = restrictedmem_create(mnt); + + mnt_drop_write(mnt); +out: + fdput(f); + + return ret; +} + +SYSCALL_DEFINE2(memfd_restricted, unsigned int, flags, int, mount_fd) +{ + if (flags & ~RMFD_USERMNT) + return -EINVAL; + + if (flags == RMFD_USERMNT) { + if (mount_fd < 0) + return -EINVAL; + + return restrictedmem_create_on_user_mount(mount_fd); + } else { + return restrictedmem_create(NULL); + } +} + int restrictedmem_bind(struct file *file, pgoff_t start, pgoff_t end, struct restrictedmem_notifier *notifier, bool exclusive) { From patchwork Fri Mar 31 23:50:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ackerley Tng X-Patchwork-Id: 13196694 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 A6DE5C77B6D for ; Fri, 31 Mar 2023 23:50:54 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 5F8336B0075; Fri, 31 Mar 2023 19:50:53 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 533486B0078; Fri, 31 Mar 2023 19:50:53 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 35EEA6B007B; Fri, 31 Mar 2023 19:50:53 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 244A36B0075 for ; Fri, 31 Mar 2023 19:50:53 -0400 (EDT) Received: from smtpin23.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id EEC474045D for ; Fri, 31 Mar 2023 23:50:52 +0000 (UTC) X-FDA: 80630841144.23.BF3C6EE Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) by imf01.hostedemail.com (Postfix) with ESMTP id 21EE440003 for ; Fri, 31 Mar 2023 23:50:50 +0000 (UTC) Authentication-Results: imf01.hostedemail.com; dkim=pass header.d=google.com header.s=20210112 header.b=ZPr0CTfb; spf=pass (imf01.hostedemail.com: domain of 32nEnZAsKCIMhjrlysl50unnvvnsl.jvtspu14-ttr2hjr.vyn@flex--ackerleytng.bounces.google.com designates 209.85.210.202 as permitted sender) smtp.mailfrom=32nEnZAsKCIMhjrlysl50unnvvnsl.jvtspu14-ttr2hjr.vyn@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=1680306651; 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=Yv+bJRbiulgPDrVW+Ntj4qt2F44S0ehE7+7p24oSzGY=; b=pg7nyS5MhitMmOEercA4DM40qTD+9TVnpWwW/6RTe769xQVliG7xIgCp4v8wg+xkOQJpDw mPl4EU6CfTyIRfmeR8BKVFQlSjSjSXTOgil6EkPwtVE88HMrQRMLA9+9OQzoG1Ns0lvw0Z vqhAmUS+GJFYTb5PHOG1QgpEdK+izu0= ARC-Authentication-Results: i=1; imf01.hostedemail.com; dkim=pass header.d=google.com header.s=20210112 header.b=ZPr0CTfb; spf=pass (imf01.hostedemail.com: domain of 32nEnZAsKCIMhjrlysl50unnvvnsl.jvtspu14-ttr2hjr.vyn@flex--ackerleytng.bounces.google.com designates 209.85.210.202 as permitted sender) smtp.mailfrom=32nEnZAsKCIMhjrlysl50unnvvnsl.jvtspu14-ttr2hjr.vyn@flex--ackerleytng.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1680306651; a=rsa-sha256; cv=none; b=EoXZV58k2IIRTQCh833qbbFyC4UAwkzSFxUoUE/N70lGC1zLnNYxZ2VVqGXV/y5KzBR0OY /GXSwo13EOPUjCMij1PyqQwNYM0bvcFy29kcqzqh8vW1S8whEwjI/8j5dERczfViXUxZ2C trp2qaooID8N4T5i0TMKNpRgrZQke28= Received: by mail-pf1-f202.google.com with SMTP id o14-20020a62f90e000000b0062d87d997eeso7823141pfh.18 for ; Fri, 31 Mar 2023 16:50:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; t=1680306650; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Yv+bJRbiulgPDrVW+Ntj4qt2F44S0ehE7+7p24oSzGY=; b=ZPr0CTfb/tH7rHskMazGeo8qEcPjauh+3nEpfnvyi9HesclCI6wUsgfBntTVJaHV61 Ve2hb2Lcjuq9EEh3zWW2DZKg6i3cwk8rwHFCiDAMrN1GO0TyPOafpQ64w7rkWNPtqRo3 5mwT0InUsDZCN/MDIXw/7vH8dKWKkC/7QyySt6outKdQajOVOgvAnVLJPjUFTeXaM9Ch oOjfZremNFYARiEuegGbGr6mqDzTDj+3xZgt4T2/4UGtCc9S/l/iYqZ/tE7DFUHRBa28 42ghD5E2cxl9+fNv6H6nYftp/Ml2nVjBvzPjlXzupHRWN3QKEjdbashtSPXNv6bYakqk i/dQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680306650; 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=Yv+bJRbiulgPDrVW+Ntj4qt2F44S0ehE7+7p24oSzGY=; b=Cb/0xxPzxAlpmOmyUfAXkkMhkblaHzRqY01OSo7crw6KmNqMgOtYs1lDumd4lApXOI PrkWuKKqKpX6Kb4ZUXfqkPOH6oOooxbP+JbsF1xDj/9Q3NrHWwyVcwgbL02diResj51E OcJmZGUFplWljt25wBMqc4aobJ6zrlLfOX1IYCBBZHQ7JsIHBb1xC08DaNpJp1mzAAg8 Mkqb/u35Az7ntukkIn5nHTvxvXj+br7GtCNjwZEsnXD1dkOP/zElDW6adW9EbceAQsQK OufVDn9f1Xpw1EyjBwn7jX2fCPy8xV3zk6x1aqEuA3Jb8ar7307DrfHMiy/hYXURKxs3 frqA== X-Gm-Message-State: AAQBX9enZ7Rb6E+Bxr9B4zyO/Hmb/RLHbN93jqSbf7wufPFfvpx/1lHP tznlHArsInjgmkAEidM7b6n5JOkZ8EztCNNxLQ== X-Google-Smtp-Source: AKy350bxpzbU0SLGbWA3Z/8DDd0OHXnIYWpMUBO36ZClt21VelE3VqWos4IR7t9ntPAPdKOErOoQbSSKkDl1d4PGaQ== X-Received: from ackerleytng-cloudtop.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:1f5f]) (user=ackerleytng job=sendgmr) by 2002:a17:902:e545:b0:1a2:8c7e:f30a with SMTP id n5-20020a170902e54500b001a28c7ef30amr2779130plf.1.1680306650125; Fri, 31 Mar 2023 16:50:50 -0700 (PDT) Date: Fri, 31 Mar 2023 23:50:40 +0000 In-Reply-To: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.40.0.348.gf938b09366-goog Message-ID: <0061b62966d34952fb9f51235d31100df0baf450.1680306489.git.ackerleytng@google.com> Subject: [RFC PATCH v3 2/2] selftests: restrictedmem: Check hugepage-ness of shmem file backing restrictedmem fd 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-Rspam-User: X-Rspamd-Server: rspam03 X-Stat-Signature: eah5a65q5q9snjrgg8naxnr1fezam5wq X-Rspamd-Queue-Id: 21EE440003 X-HE-Tag: 1680306650-644505 X-HE-Meta: U2FsdGVkX180SOwcY/SlmK3L9vEO8Czw9BEsDR6q53UT0JDi1pYrJtBIT9Q1dwE9mXGKXHKBDS4oKLaRlB5hsD9uyljlUOrzqt7ZTanpgYkal7Xz8aabN/eWpBM9j3qEVQoFIC0/ros8JJn1V3JG7Vdtq/IS9MPUdoRf/jjiHUup1KxBj78pA6Q0Ktb24AdE6yCZDkCC2BG5aDoSN8vdyk0Ocl86va8/UXY3VLp07OclRCRI9NpDb1TMbpCGPiK4tjuTRjh5QeE1FrGlPOOGdzy6KQITNIdIoN52eEdg1zc3tddnlLqemxcS7I7iEzr7aHxzSGJrXDabbmCcpUP5aHAU1q/65jW1wyxBDr2TQEsw9Oa+h6nhIPyMMLl9tMtH37dxfzA2TZnBw6TXvTB9RyEC0/oRyGu5l6fEM5Pfwrrjyu8vlwJalgjwoOLmX7K2jj3uAu67blZcm7bhzTMLaeoTmQKkgc9r/HZiVHvjefLB6s/eYQscP03Uz5eRe8hECCClgf6TcWn9o87MRNurrQl2eVfYUIATL6CODPD1MZmKvtigYR0lI8Jkjvuc9irKkUrD7VmjyfXxCgMS6tKQ7Ptnu0ggPsYFJW3MBopUQzr5QK4QJBmhk/Mt9qaBFkw22mZHJCmgzuE6dhdbNIJMlMKDb6RM3i/rVbAIIUok5cfzOGf/ZgjgQ6O9IQdoyH8Zkd2o0HHQv6goW9vRjC8gxLhonyzmgBX6eVutmOWcNW5isOj6Mkg4F5ObKX30UB1jbJN7JdRY3QKNCzqV1v6vZJ0L+SzJ5ra15pvzZP1Jb+Ra2cWF9jBdQcO55Mr0M7HCNYJ9F6p0ZLT6j6hJh0Es3YcIkiOjs581YSfSUrNm9ZaTfLisYyq5ArZMPCApCyzc+KkPOKxTGxkA/G9FQJVyPaOC9wGCnUV2fgz+CGtxj4ZhwU378umiGwI/wfpsuxwMq+nU9PPs61KSjq4k/8L z/xFnn37 T7ef2lc/lIDGx+uDVba1ifVHHoSWaWBqtpCzH1bAxBh5Psk6EU4AEpJsBNm/amfiH9V/n1VkgDlwShTY09LHCQOVKmw+HtKgH1uewAMraQ2PtPQFYgONknqxTz8Xk3rmRZamBQDPsgWrY3ZpJm3Q1c/lwG7ifE2IrELbWmMrD0SvYTcy8+xundONn0ycYouTToTYswYrxzYI5VAj5rq+3Ls1qmXnbLVyT96Z0G44q1McUYmodTe4jSFR3OCjsnP+T98RyLRBJDWG9+Q9mDw8jaHY4Li2/Kn+Zr9ND/dP1xC9xaCQjgZtf7NDwh+i/KTFgK4J3ENd6LJKyOicBcOTo1+DiJu5hOansZPaKsIUvALHtV4dhf3CPGOJ60tEDiaz924icyV4DxubeWcsmdOHwAh0X0w2pSHlOLQCJozHYCr7FTxZfgvuEAYEWNQrO62awH392YpOpVMI2SwoFT8ffcWLPs4yUxFWtyFKBAj1quEerm7HfsLqYBuiWRjWGwPnXTdOtYj+ab6OkzyY/3L16ngKbAo8jhtBSW5gZwwqiw/9b+ne2ur6v4RcGW6MkKlpIeBMBIyrvIPntfQqpmMRvwdAlSRUIS8BlhZ2YdRbN6ooK7N5QJUMAKca1oEHxOaIV2zJ//fSOw1XDwMdc3CRs4nGPHNHA0LCDZaxG 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/Makefile | 1 + .../selftests/restrictedmem/.gitignore | 3 + .../testing/selftests/restrictedmem/Makefile | 15 + .../testing/selftests/restrictedmem/common.c | 9 + .../testing/selftests/restrictedmem/common.h | 8 + .../restrictedmem_hugepage_test.c | 486 ++++++++++++++++++ 6 files changed, 522 insertions(+) create mode 100644 tools/testing/selftests/restrictedmem/.gitignore create mode 100644 tools/testing/selftests/restrictedmem/Makefile create mode 100644 tools/testing/selftests/restrictedmem/common.c create mode 100644 tools/testing/selftests/restrictedmem/common.h create mode 100644 tools/testing/selftests/restrictedmem/restrictedmem_hugepage_test.c diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index f07aef7c592c..44078eeefb79 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -60,6 +60,7 @@ TARGETS += pstore TARGETS += ptrace TARGETS += openat2 TARGETS += resctrl +TARGETS += restrictedmem TARGETS += rlimits TARGETS += rseq TARGETS += rtc diff --git a/tools/testing/selftests/restrictedmem/.gitignore b/tools/testing/selftests/restrictedmem/.gitignore new file mode 100644 index 000000000000..2581bcc8ff29 --- /dev/null +++ b/tools/testing/selftests/restrictedmem/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +restrictedmem_hugepage_test diff --git a/tools/testing/selftests/restrictedmem/Makefile b/tools/testing/selftests/restrictedmem/Makefile new file mode 100644 index 000000000000..8e5378d20226 --- /dev/null +++ b/tools/testing/selftests/restrictedmem/Makefile @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0 + +CFLAGS = $(KHDR_INCLUDES) +CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -std=gnu99 + +TEST_GEN_PROGS += restrictedmem_hugepage_test + +include ../lib.mk + +EXTRA_CLEAN = $(OUTPUT)/common.o + +$(OUTPUT)/common.o: common.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -ffreestanding $< -o $@ + +$(TEST_GEN_PROGS): $(OUTPUT)/common.o diff --git a/tools/testing/selftests/restrictedmem/common.c b/tools/testing/selftests/restrictedmem/common.c new file mode 100644 index 000000000000..03dac843404f --- /dev/null +++ b/tools/testing/selftests/restrictedmem/common.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +int memfd_restricted(unsigned int flags, int mount_fd) +{ + return syscall(__NR_memfd_restricted, flags, mount_fd); +} diff --git a/tools/testing/selftests/restrictedmem/common.h b/tools/testing/selftests/restrictedmem/common.h new file mode 100644 index 000000000000..06284ed86baf --- /dev/null +++ b/tools/testing/selftests/restrictedmem/common.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef SELFTESTS_RESTRICTEDMEM_COMMON_H +#define SELFTESTS_RESTRICTEDMEM_COMMON_H + +int memfd_restricted(unsigned int flags, int mount_fd); + +#endif // SELFTESTS_RESTRICTEDMEM_COMMON_H diff --git a/tools/testing/selftests/restrictedmem/restrictedmem_hugepage_test.c b/tools/testing/selftests/restrictedmem/restrictedmem_hugepage_test.c new file mode 100644 index 000000000000..9ed319b83cb8 --- /dev/null +++ b/tools/testing/selftests/restrictedmem/restrictedmem_hugepage_test.c @@ -0,0 +1,486 @@ +// 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 +#include +#include + +#include "linux/restrictedmem.h" + +#include "common.h" +#include "../kselftest_harness.h" + +/* + * Expect policy to be one of always, within_size, advise, never, + * deny, force + */ +#define POLICY_BUF_SIZE 12 + +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 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 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; +} + +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(RMFD_USERMNT, -2); + + ASSERT_EQ(fd, -1); + ASSERT_EQ(errno, EINVAL); +} + +TEST(restrictedmem_tmpfile_fd_not_a_mount) +{ + int fd = memfd_restricted(RMFD_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(RMFD_USERMNT, mfd); + + ASSERT_EQ(fd, -1); + ASSERT_EQ(errno, EINVAL); +} + +FIXTURE(tmpfs_hugepage_sfd) +{ + int sfd; +}; + +FIXTURE_SETUP(tmpfs_hugepage_sfd) +{ + self->sfd = fsopen("tmpfs", 0); + ASSERT_NE(self->sfd, -1); +} + +FIXTURE_TEARDOWN(tmpfs_hugepage_sfd) +{ + EXPECT_EQ(close(self->sfd), 0); +} + +TEST_F(tmpfs_hugepage_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(RMFD_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_hugepage_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(RMFD_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_hugepage_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(RMFD_USERMNT, mfd); + ASSERT_EQ(fd, -1); + ASSERT_EQ(errno, EROFS); + + ret = close(mfd); + ASSERT_EQ(ret, 0); +} + +TEST_F(tmpfs_hugepage_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(RMFD_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(tmpfs_hugepage_mount_path) +{ + char *mount_path; +}; + +FIXTURE_SETUP(tmpfs_hugepage_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(tmpfs_hugepage_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(tmpfs_hugepage_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(RMFD_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(tmpfs_hugepage_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(RMFD_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(tmpfs_hugepage_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(RMFD_USERMNT, ffd); + ASSERT_LT(fd, 0); + ASSERT_EQ(errno, EINVAL); + + ret = close(ffd); + ASSERT_EQ(ret, 0); + + close(fd); + remove(tmp_file_path); + rmdir(tmp_dir_path); +} + +TEST_HARNESS_MAIN