From mboxrd@z Thu Jan 1 00:00:00 1970 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 810E7C76196 for ; Mon, 3 Apr 2023 08:24:49 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 095F36B0072; Mon, 3 Apr 2023 04:24:49 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 01E226B0074; Mon, 3 Apr 2023 04:24:48 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id DDBF46B0075; Mon, 3 Apr 2023 04:24:48 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id C81FA6B0072 for ; Mon, 3 Apr 2023 04:24:48 -0400 (EDT) Received: from smtpin27.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id 8FC08A02C9 for ; Mon, 3 Apr 2023 08:24:48 +0000 (UTC) X-FDA: 80639393856.27.EC51AAE Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by imf20.hostedemail.com (Postfix) with ESMTP id 4B8901C0012 for ; Mon, 3 Apr 2023 08:24:45 +0000 (UTC) Authentication-Results: imf20.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b="VUEHiFr/"; spf=pass (imf20.hostedemail.com: domain of david@redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=david@redhat.com; dmarc=pass (policy=none) header.from=redhat.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1680510285; 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:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=0FWcmCzHAgUO3hqFJcPx5rDExk6o6HKiqb/A1eQCBFg=; b=pVUZmFj7GViM/vQFDQenEXAmvsjLYM3fCp/7suR+zIHPKUXUOWOlXIy5nX1HGtCyEZBbav e+RaKWNUYtL8yflKE2eExb7HiQ8XLB9fJyf4FIK5fO+Ow/+PrrO/2bno+H93oHH+Sf54yj 90Q3RZiacLpK6EmwavVCz/Wyh2h8AlI= ARC-Authentication-Results: i=1; imf20.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b="VUEHiFr/"; spf=pass (imf20.hostedemail.com: domain of david@redhat.com designates 170.10.129.124 as permitted sender) smtp.mailfrom=david@redhat.com; dmarc=pass (policy=none) header.from=redhat.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1680510285; a=rsa-sha256; cv=none; b=jMagd0A/+P3vmPhUgBhnFmaC5xPgiXSrm0AA1y9tTLCESpLWKNwOFuCCqTVjB63NZb00RS nBfvpRN3MpeUIK2lmIUBihXUoglYxlTlOTKGjtH8IJdg2wFtEuAgja7rrL+2Blo6hq3uQZ Lo0CKqiTcp4jyQpyEDL3onURA3tN4jQ= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1680510284; h=from:from: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:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0FWcmCzHAgUO3hqFJcPx5rDExk6o6HKiqb/A1eQCBFg=; b=VUEHiFr/8Co/o0Fx2BKgfjA8nw2TuUmb2Ux9XsPdWoznuokfzkpIG+STcWbPHE3Uyu+Xg1 g97gKwaR0to68HoSBSC2sulmbGScKqzl+1OPkNote14VM6ixwQEf1ryVZwwO1NenxTYh23 cblaMukB4HZ4zxHI4lUsKGi2DxHpXYM= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-57--NIMi8Q0NkSy6Rgsa0kMgA-1; Mon, 03 Apr 2023 04:24:41 -0400 X-MC-Unique: -NIMi8Q0NkSy6Rgsa0kMgA-1 Received: by mail-wm1-f69.google.com with SMTP id r11-20020a05600c458b00b003eea8d25f06so14372475wmo.1 for ; Mon, 03 Apr 2023 01:24:41 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680510280; h=content-transfer-encoding:in-reply-to:organization:from:references :cc:to:content-language:subject:user-agent:mime-version:date :message-id:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=0FWcmCzHAgUO3hqFJcPx5rDExk6o6HKiqb/A1eQCBFg=; b=AkoL6sSjuA6gY7FUYnUY803XzWiH82TWQqE42HhZLJlJhe3sEsGwsL4l7pRSnaB59v 2ZRgFtcbdonOhSljDErGD1ssYuKl8+XZKwGIj8xIODPvsI+FMXo1b+gh2I+pvXy5f5ma vkrCwcA8G5Uu5/NvD2Hn4WW+5vn/iG7gpTIvzOAJ5oc4AeS7wIltrbQZ7w2ABfOg8+Sh VTxJGCLOPSLLenOqNplVfJUv4TTp8qcMJ3pTi6yi+Psi6Gck2lCJaWFwWnHekLcOYbJ9 qMGLiJa6mY8x1zX27Vp5A3xcjOjyFVLkkCjiFcj3nuYktlrg2ZdeXsY9xU9tswCH4XLJ bL5Q== X-Gm-Message-State: AAQBX9fLuPE1YQG95BGWPbiXV6a0CI9v0Ul33ii5eTwWECU6WxirD0HA DznkagJToDIh6vmofR3aCvKko5wKFnEtrZpSnnv5Q1BAVlaTAhQc4/ILSTIMg3QvksXtS29cKXh paxm4alNEWfI= X-Received: by 2002:a7b:c001:0:b0:3f0:3d41:bda3 with SMTP id c1-20020a7bc001000000b003f03d41bda3mr8610617wmb.5.1680510280257; Mon, 03 Apr 2023 01:24:40 -0700 (PDT) X-Google-Smtp-Source: AKy350ZJ101z9V0fCnzfOt+5d2ege5d2bsm7iDiCgbDLQDkFM+patuJMLvgOw0mhrTzUSdRLe9tDtQ== X-Received: by 2002:a7b:c001:0:b0:3f0:3d41:bda3 with SMTP id c1-20020a7bc001000000b003f03d41bda3mr8610605wmb.5.1680510279889; Mon, 03 Apr 2023 01:24:39 -0700 (PDT) Received: from ?IPV6:2003:cb:c702:5e00:8e78:71f3:6243:77f0? (p200300cbc7025e008e7871f3624377f0.dip0.t-ipconnect.de. [2003:cb:c702:5e00:8e78:71f3:6243:77f0]) by smtp.gmail.com with ESMTPSA id i2-20020a05600c290200b003edc11c2ecbsm11376835wmd.4.2023.04.03.01.24.37 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 03 Apr 2023 01:24:39 -0700 (PDT) Message-ID: <9bbdc378-e66e-0a44-244b-33dffe888a2b@redhat.com> Date: Mon, 3 Apr 2023 10:24:37 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.9.1 Subject: Re: [RFC PATCH v3 2/2] selftests: restrictedmem: Check hugepage-ness of shmem file backing restrictedmem fd To: Ackerley Tng , 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, 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 References: <0061b62966d34952fb9f51235d31100df0baf450.1680306489.git.ackerleytng@google.com> From: David Hildenbrand Organization: Red Hat In-Reply-To: <0061b62966d34952fb9f51235d31100df0baf450.1680306489.git.ackerleytng@google.com> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 4B8901C0012 X-Stat-Signature: dbdhgfy7nkxqkdje69r3ohqmg6jy65y7 X-Rspam-User: X-HE-Tag: 1680510285-318948 X-HE-Meta: U2FsdGVkX1914Wkul5CfkaeSnpesGzyusdz3e0ltHSwCLnjzANpqydtH9jKznvjRLuVvhB+f7yzVjWvdlEJOre8yoJNLQT0koS6GO1os5eIoBYcnAc725Q1qza/0R99saasj0ZSgDBUIEW9D2YZwt9kXP633NWugV/6xBd3VGG1Ftk/5ufnTsqxnRakRjgTYkoKQeFmHCugMz21EnGr801l81vVlNbEGp034MBNMsRfAz/T6C4ipr6aAQx9KaZbG3oC1UGGP+X/1L1oi0lH3yo8RKyDpXcALq5QQJ8Kb7UMfBWmA+HHPLaGdYRJ7G/X8/rv9U240iql8v2BnwgWDGxmWKvaK5PBz++u3klryR9FDRps1WZkLTCpWOVi1VnuxatOzG/bgWTFLVc+ocyhNLf/fpHGjwsmr30orwbpoCXLDzSsOTQioZ1kNCarafoadFsMoEs4sF58qS1JNGsymhgx79kuvKpgIoNCzBK2lh8SFqhPQFKmW2fGPWBf7jpxE1vVprNBElMIg9d7Y9uAB+ZMZ6U6vgeGZ25x4ubUTvi1HvpCG+JJhwNtLFszrh/0rwxJRZ7WlyiPhkQ0Rx/gcUUL4p6ZTZOimqwxpHTaXMk1AEnt4b53CPfLZtuwIeHRJG6eqCddumO7a96N4aiOgmIYPVvTQK6frFxdD1ZNylbBXjyu0kzvdoVQMx1nkzW2Mtw9kUaVUjvKiRcb2kkOu5/M9dFqG5NfjAfTw1vLKnarzpalkIqIfpfx4w4gZtSI9IT/c/5Dw+yvWOvb/99Zgr32YOK2m8/DYd0crzE6OwX6mQHYReeTeccu371QVXMpkkx3m3CX5BIYWHzI5EjqHno9MQhV8u4OegzVCNJ9tKnEcP4cCovzTBFuxHvERtCTBVN02hZHOwO+qyu7+HkFsfFURWGysRS/FZKX29txCw/e87p+1IsGy+ScDcTo0behyUhdbUMRAeF07YXofLNT ceF62Sbf Sy5kEPMGUJae6dv6zBtS2hDy2s4zoeXA0CHZJ6sTjPE2BSGKGVjt9c61/osaYesiCFr2S0Q+fdvTkOah0bsm2etwt7qMuCXZsbR+EYatjLLUmo4cr/+3ghlbd/cyBCMfkLqFv4LK8eZjNTHtdq0V+yDSzTsfdB4JFReYr4FzcYuMYiMPLEPp/CJeaIuWZSsMGmGUTQ7pNM85ooVR7O5BZJczoKXgY7wOpyhid4dvzxvszqnu6Rc2WwNk2QlIUTtMBpHK+WRGb0eCWwBHWtD8eecvTys/b3MdeufrEc+PkwSffpZ0wNQbPo5YcP/l8SlLZBSyt5IEVMGZnfPibf1/g1v6Evkd1zpoSext7mW83Qk5UbInggaMikDzlgj8cK7dMyBpgBb6Nhfakepy5IwPX/da3qbOrZ5rMp/xqgdb+nLqTkVo= 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: On 01.04.23 01:50, Ackerley Tng wrote: > 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. > When you talk about "hugepage" in this patch, do you mean THP or hugetlb? I suspect thp, so it might be better to spell that out. IIRC, there are plans to support actual huge pages in the future, at which point "hugepage" terminology could be misleading. > 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 -- Thanks, David / dhildenb