Received: by 2002:a05:6602:18e:0:0:0:0 with SMTP id m14csp1454697ioo; Fri, 27 May 2022 08:57:49 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxgzEpir8n2HY5XD+pdBcNFpsxQmGycaTnOo78mPlZfLtt/qi8yyaigOxlISVOk7kWsu1vt X-Received: by 2002:a17:90a:6441:b0:1e0:b413:c290 with SMTP id y1-20020a17090a644100b001e0b413c290mr9045596pjm.179.1653667068796; Fri, 27 May 2022 08:57:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1653667068; cv=none; d=google.com; s=arc-20160816; b=YWrSlhDIYqmK2MBp8BFIdBzEqTYrCjn4992xYoXNiQRgHeKe9bQbtmX1WsTw0sTfDf vvXBjQEAWedof1xMJy0Mu0DMXzVKW9tLwf9DjQqJ+zAXp6naZl9v0uuz8BajCJNpyzWu Nu/R6h8oNY2wlW99Y03qZ2caLxBJtPC+Qnd5LLe7wnOhngcT+gtyI/YY2isFo3IR5EBT YO2/UEWSozyuwbc69szXV8IY4aJyzu4b0PMW4ZSNk2LFAprhZ/HiJdoL0h+KWlkVYXA7 ARaItURahoFg/jBFNPmBdaWL2hhXQKuxWM4DTZpsMT2HPzsSsWKyYVJCaKe4YPQDQ4kk mjww== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:dkim-signature; bh=SXKeF9OqpGDpuoZVxsYVRtbB7K2x8FBA+P2quq827+Y=; b=MePpbRiyhMS/mdwaTnmEd//49dFWWJyJ8QYu8o6wYmrdrtBXgM9Lqo5lGhulBeLWvj DBCWW0GA0WKy1l1L6g3q3xI6yaHRsnh67CyyNgO255HlqngMScWUgky7cgiAZ9URf5HZ jECbEGeAZC+vviWXtMW0P1gOHqvylTocrLLq1xoYxBVJJ6DJfrh5YqRRSo3B8IxKRdH1 eiVGzvP4/qrD5h+MHuafqD+TTwqQITP6CB4fqjUcV55DNb5u0cT5NL974RxL/6AVZktP 9dyQt4GigY0WDA27KNwlDvQBNPDlXtSuhQVM0/yaAcGPh6ZnGs+MpmDoFDZhVKQLS6Tz Nv9A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="nQo/6U11"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id j15-20020a636e0f000000b003f9e1595faesi6595022pgc.783.2022.05.27.08.57.33; Fri, 27 May 2022 08:57:48 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b="nQo/6U11"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348390AbiEZRzM (ORCPT + 99 others); Thu, 26 May 2022 13:55:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50486 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348437AbiEZRyg (ORCPT ); Thu, 26 May 2022 13:54:36 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D4234B36F9 for ; Thu, 26 May 2022 10:54:28 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id d5-20020a17090a564500b001e031a8ad45so1446658pji.6 for ; Thu, 26 May 2022 10:54:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=SXKeF9OqpGDpuoZVxsYVRtbB7K2x8FBA+P2quq827+Y=; b=nQo/6U11xPzxsdoihbiqFl4qSug+H3g3Qb7ocCUM0EGUDx+1gRyq8RPo8YXgvdyVMy Z1XDj1eysHJdfANHU0+Cn8tAQsjUhNIuM5a+0C982JyL4frVMd5XBhHq0AWED6DouJ9N eGwPRmd6l9dnqL0R+CyGOKYIidCD/mZEub53/pLOeSryTO92bRuPZWZUoprtCBvsmIKm ALwjBsCaiC/cZvspVuy4i/SFAaej7vjrSZH55yzFfmGPh0qPSHrASwKE5aO+j6w4zvwT 42kSICns53DkkOkeb6unR/OhSg6ta3PTI160HerUDSXTHf2VWeVD8k533Q2egV+3XnHd gk6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=SXKeF9OqpGDpuoZVxsYVRtbB7K2x8FBA+P2quq827+Y=; b=yV8vTrFYs7I3WHjF05OjC06+OSkzt+TQu1e1axIUJK6XkQryAvjeBVryIxJlHk+3wV H8C5QsI6OGeTNzJAJ4C0z6E6E002ufuizBGFo4ZSjW2YL+zx2jOG4YcK469xdEcEKnqw IhoiTtr6fRjvvD2wMCi3PhIIH6xIuztsJhapdoEembC4zMTNHxcziYr8bpOugdoXlMK0 hSGz1NW/hcsh3yUXxIzvtKe1yPsgPP/0mulmdUCyyF6GEks8U4joHTVS46cTVyAnZ9MR V0f7OLoUpJzAAe2ZyLGlJbARunYwX3bLUGBD8gEyS0DhVKK/ynyHOHre/K/gIWljnO1Z c46Q== X-Gm-Message-State: AOAM531kxtj6foQ1M70mNNOjwPZr54QXDT10XHoMA3gupj1V4Qf2R9HY Yv1+8I2A5C2ZUo8kVriXLC5aYA0tqkPN X-Received: from sweer.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:e45]) (user=bgardon job=sendgmr) by 2002:a17:90a:778c:b0:1df:56a5:8474 with SMTP id v12-20020a17090a778c00b001df56a58474mr3839118pjk.63.1653587667713; Thu, 26 May 2022 10:54:27 -0700 (PDT) Date: Thu, 26 May 2022 17:54:07 +0000 In-Reply-To: <20220526175408.399718-1-bgardon@google.com> Message-Id: <20220526175408.399718-11-bgardon@google.com> Mime-Version: 1.0 References: <20220526175408.399718-1-bgardon@google.com> X-Mailer: git-send-email 2.36.1.124.g0e6072fb45-goog Subject: [PATCH v8 10/11] KVM: selftests: Test disabling NX hugepages on a VM From: Ben Gardon To: kvm@vger.kernel.org, Paolo Bonzini Cc: linux-kernel@vger.kernel.org, Peter Xu , Sean Christopherson , David Matlack , Jim Mattson , David Dunn , Jing Zhang , Junaid Shahid , Ben Gardon Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add an argument to the NX huge pages test to test disabling the feature on a VM using the new capability. Reviewed-by: David Matlack Signed-off-by: Ben Gardon --- .../selftests/kvm/include/kvm_util_base.h | 2 + tools/testing/selftests/kvm/lib/kvm_util.c | 27 +++- .../selftests/kvm/x86_64/nx_huge_pages_test.c | 140 ++++++++++++------ .../kvm/x86_64/nx_huge_pages_test.sh | 14 +- 4 files changed, 133 insertions(+), 50 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 3c9898c59ea1..6aa06a312250 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -447,4 +447,6 @@ static inline uint64_t vm_get_stat(struct kvm_vm *vm, const char *stat_name) uint32_t guest_get_vcpuid(void); +int __vm_disable_nx_huge_pages(struct kvm_vm *vm); + #endif /* SELFTEST_KVM_UTIL_BASE_H */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 385f249c2dc5..33d4d64c1391 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -112,6 +112,11 @@ int vm_check_cap(struct kvm_vm *vm, long cap) return ret; } +static int __vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) +{ + return ioctl(vm->fd, KVM_ENABLE_CAP, cap); +} + /* VM Enable Capability * * Input Args: @@ -128,7 +133,7 @@ int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) { int ret; - ret = ioctl(vm->fd, KVM_ENABLE_CAP, cap); + ret = __vm_enable_cap(vm, cap); TEST_ASSERT(ret == 0, "KVM_ENABLE_CAP IOCTL failed,\n" " rc: %i errno: %i", ret, errno); @@ -2718,3 +2723,23 @@ void __vm_get_stat(struct kvm_vm *vm, const char *stat_name, uint64_t *data, free(stats_desc); close(stats_fd); } + +/* VM disable NX huge pages + * + * Input Args: + * vm - Virtual Machine + * + * Output Args: None + * + * Return: On success, 0. -ERRNO on failure. + * + * Disables NX huge pages for the VM. + */ +int __vm_disable_nx_huge_pages(struct kvm_vm *vm) +{ + struct kvm_enable_cap cap = { 0 }; + + cap.cap = KVM_CAP_VM_DISABLE_NX_HUGE_PAGES; + cap.args[0] = 0; + return __vm_enable_cap(vm, &cap); +} diff --git a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c index 09e05cda3dcd..9ff554a572c0 100644 --- a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c +++ b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c @@ -107,52 +107,37 @@ static void wait_for_reclaim(int reclaim_period_ms) nanosleep(&ts, NULL); } -static void help(char *name) -{ - puts(""); - printf("usage: %s [-h] [-p period_ms] [-t token]\n", name); - puts(""); - printf(" -p: The NX reclaim period in miliseconds.\n"); - printf(" -t: The magic token to indicate environment setup is done.\n"); - puts(""); - exit(0); -} - -int main(int argc, char **argv) +void run_test(int reclaim_period_ms, bool disable_nx_huge_pages, + bool reboot_permissions) { - int reclaim_period_ms = 0, token = 0, opt; struct kvm_vm *vm; + uint64_t pages; void *hva; - - while ((opt = getopt(argc, argv, "hp:t:")) != -1) { - switch (opt) { - case 'p': - reclaim_period_ms = atoi(optarg); - break; - case 't': - token = atoi(optarg); - break; - case 'h': - default: - help(argv[0]); - break; + int r; + + pages = vm_pages_needed(VM_MODE_DEFAULT, 1, DEFAULT_GUEST_PHY_PAGES, + 0, 0); + vm = vm_create_without_vcpus(VM_MODE_DEFAULT, pages); + + if (disable_nx_huge_pages) { + /* + * Cannot run the test without NX huge pages if the kernel + * does not support it. + */ + if (!kvm_check_cap(KVM_CAP_VM_DISABLE_NX_HUGE_PAGES)) + return; + + r = __vm_disable_nx_huge_pages(vm); + if (reboot_permissions) { + TEST_ASSERT(!r, "Disabling NX huge pages should succeed if process has reboot permissions"); + } else { + TEST_ASSERT(r == -1 && errno == EPERM, + "This process should not have permission to disable NX huge pages"); + return; } } - if (token != MAGIC_TOKEN) { - print_skip("This test must be run with the magic token %d.\n" - "This is done by nx_huge_pages_test.sh, which\n" - "also handles environment setup for the test.", - MAGIC_TOKEN); - exit(KSFT_SKIP); - } - - if (!reclaim_period_ms) { - print_skip("The NX reclaim period must be specified and non-zero"); - exit(KSFT_SKIP); - } - - vm = vm_create_default(0, 0, guest_code); + vm_vcpu_add_default(vm, 0, guest_code); vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS_HUGETLB, HPAGE_GPA, HPAGE_SLOT, @@ -185,31 +170,38 @@ int main(int argc, char **argv) /* * Next, the guest will execute from the first huge page, causing it * to be remapped at 4k. + * + * If NX huge pages are disabled, this should have no effect. */ vcpu_run(vm, 0); - check_2m_page_count(vm, 1); - check_split_count(vm, 1); + check_2m_page_count(vm, disable_nx_huge_pages ? 2 : 1); + check_split_count(vm, disable_nx_huge_pages ? 0 : 1); /* * Executing from the third huge page (previously unaccessed) will * cause part to be mapped at 4k. + * + * If NX huge pages are disabled, it should be mapped at 2M. */ vcpu_run(vm, 0); - check_2m_page_count(vm, 1); - check_split_count(vm, 2); + check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 1); + check_split_count(vm, disable_nx_huge_pages ? 0 : 2); /* Reading from the first huge page again should have no effect. */ vcpu_run(vm, 0); - check_2m_page_count(vm, 1); - check_split_count(vm, 2); + check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 1); + check_split_count(vm, disable_nx_huge_pages ? 0 : 2); /* Give recovery thread time to run. */ wait_for_reclaim(reclaim_period_ms); /* * Now that the reclaimer has run, all the split pages should be gone. + * + * If NX huge pages are disabled, the relaimer will not run, so + * nothing should change from here on. */ - check_2m_page_count(vm, 1); + check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 1); check_split_count(vm, 0); /* @@ -217,10 +209,62 @@ int main(int argc, char **argv) * reading from it causes a huge page mapping to be installed. */ vcpu_run(vm, 0); - check_2m_page_count(vm, 2); + check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 2); check_split_count(vm, 0); kvm_vm_free(vm); +} + +static void help(char *name) +{ + puts(""); + printf("usage: %s [-h] [-p period_ms] [-t token]\n", name); + puts(""); + printf(" -p: The NX reclaim period in miliseconds.\n"); + printf(" -t: The magic token to indicate environment setup is done.\n"); + printf(" -r: The test has reboot permissions and can disable NX huge pages.\n"); + puts(""); + exit(0); +} + +int main(int argc, char **argv) +{ + int reclaim_period_ms = 0, token = 0, opt; + bool reboot_permissions = false; + + while ((opt = getopt(argc, argv, "hp:t:r")) != -1) { + switch (opt) { + case 'p': + reclaim_period_ms = atoi(optarg); + break; + case 't': + token = atoi(optarg); + break; + case 'r': + reboot_permissions = true; + break; + case 'h': + default: + help(argv[0]); + break; + } + } + + if (token != MAGIC_TOKEN) { + print_skip("This test must be run with the magic token %d.\n" + "This is done by nx_huge_pages_test.sh, which\n" + "also handles environment setup for the test.", + MAGIC_TOKEN); + exit(KSFT_SKIP); + } + + if (!reclaim_period_ms) { + print_skip("The NX reclaim period must be specified and non-zero"); + exit(KSFT_SKIP); + } + + run_test(reclaim_period_ms, false, reboot_permissions); + run_test(reclaim_period_ms, true, reboot_permissions); return 0; } diff --git a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh index 4e090a84f5f3..6bd8e026ee61 100755 --- a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh +++ b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh @@ -20,6 +20,8 @@ function sudo_echo () { echo "$1" | sudo tee -a "$2" > /dev/null } +NXECUTABLE="$(dirname $0)/nx_huge_pages_test" + ( set -e @@ -28,7 +30,17 @@ function sudo_echo () { sudo_echo 100 /sys/module/kvm/parameters/nx_huge_pages_recovery_period_ms sudo_echo "$(( $HUGE_PAGES + 3 ))" /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages - "$(dirname $0)"/nx_huge_pages_test -t 887563923 -p 100 + # Test with reboot permissions + if [ $(whoami) != "root" ] ; then + sudo setcap cap_sys_boot+ep $NXECUTABLE + fi + $NXECUTABLE -t 887563923 -p 100 -r + + # Test without reboot permissions + if [ $(whoami) != "root" ] ; then + sudo setcap cap_sys_boot-ep $NXECUTABLE + $NXECUTABLE -t 887563923 -p 100 + fi ) RET=$? -- 2.36.1.124.g0e6072fb45-goog