From patchwork Mon May 15 13:05:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 13241400 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 08BCFC77B75 for ; Mon, 15 May 2023 13:07:22 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 7B913900007; Mon, 15 May 2023 09:07:22 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 769BB900002; Mon, 15 May 2023 09:07:22 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 60B5B900007; Mon, 15 May 2023 09:07:22 -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 49E37900002 for ; Mon, 15 May 2023 09:07:22 -0400 (EDT) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id B7C64161251 for ; Mon, 15 May 2023 13:07:21 +0000 (UTC) X-FDA: 80792515482.21.CDC67CE Received: from mail-pl1-f172.google.com (mail-pl1-f172.google.com [209.85.214.172]) by imf02.hostedemail.com (Postfix) with ESMTP id E2E0380003 for ; Mon, 15 May 2023 13:06:07 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=Md2uy27i; dmarc=pass (policy=none) header.from=chromium.org; spf=pass (imf02.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.172 as permitted sender) smtp.mailfrom=jeffxu@chromium.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1684155968; 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-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=oD0d2al7XFldRkjYP37ZWtTdhmPaRGV8lU2SKIN3qFc=; b=5B/jbuiSapxDaZDY1n61yF9wdiznCh6BtnIGYZPlfcdcabmaH+HOP1joBo9CLiu57uX1Wl QYgYSoeZA17x+ig8OdhC1lIRoyhHegNfD9xqQxt7YsoUIHEQOdQYw6NRolFKhOPiukMkPY Kij1ESN86eCCAqGwKhwlh+iojBOWk4Y= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=Md2uy27i; dmarc=pass (policy=none) header.from=chromium.org; spf=pass (imf02.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.214.172 as permitted sender) smtp.mailfrom=jeffxu@chromium.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1684155968; a=rsa-sha256; cv=none; b=6unCaXrIF73vZh8HCZIEIKSBzjqxzFrz0HYK6xJhTTC2tW4qcLxurVpL7TKR1gaFDnxuQS LN0i+2of+idTnUKgO5TRHvFthVlmBo5FRQK0B4HkfsE7nNZwhECpD/Z3pI/iB0LrqMJJ7j XjK5k2qCe8PRy4e45hdAtlAgHSaXHM0= Received: by mail-pl1-f172.google.com with SMTP id d9443c01a7336-1aaf70676b6so90626255ad.3 for ; Mon, 15 May 2023 06:06:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1684155966; x=1686747966; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=oD0d2al7XFldRkjYP37ZWtTdhmPaRGV8lU2SKIN3qFc=; b=Md2uy27iyG56QmAk/eMUrPY9FgIbjWQ34NOlHqHXzvq/n+f6KFeUNnAfHdTfIROgpr i+HrFD3SDGN7cdg0bpeMPna+t3GxvzduQzy5yue646dWIIdgWqwFvGeyeP2WvGuBIaf9 lca9gTUHWxnlNULGlhCBRARLT0/pk0Uz/OAmw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684155966; x=1686747966; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=oD0d2al7XFldRkjYP37ZWtTdhmPaRGV8lU2SKIN3qFc=; b=aEXmFaG8IVtJOwOgzKB3etF0UNib7EaN/K0oVRVD0xoCgEwTPxRH7RD3C/c/SXYPXF 4ZsQCqB71iYd6yS7edgysJzE8Xkpix/pfHCV4MyJUmX6bhFqpDh3+/YuOFS7/01cZdSq g0be1NXpb8pE75ARu68s2gMRZY7sJvT7iL8dxSw0kAUye1+cHbhEOy40bMVOYaU9gUWj kHshbdfVJqwbbOWDKnfUVrtq8DVgOXLI9T9z0sfVqUYyr53tozEqpOXcZU32xkb2uXfd SuY6gjmwwypUSmWPXUmRzRzOLlilGb7iY9g7DiEUja3YBzdNCfYuOnMGTV17kzmnVUqm jlmg== X-Gm-Message-State: AC+VfDzRaSNKoYZtB1w5MCxMZtsCrgHbrfPGGc3qyfcS7SGIpAq2wWcU cNDSKOwlE7eRNAPp3GdIkJSC3g== X-Google-Smtp-Source: ACHHUZ7kRs6SmTa1z+RVcotvr+mhyGciDo5UlpdWfWoFRJZOmx9Unzfl0FpNuZrj13ngH72aAGPZ1g== X-Received: by 2002:a17:903:234f:b0:1ae:bf5:7b5 with SMTP id c15-20020a170903234f00b001ae0bf507b5mr6078985plh.34.1684155966087; Mon, 15 May 2023 06:06:06 -0700 (PDT) Received: from localhost (183.43.230.35.bc.googleusercontent.com. [35.230.43.183]) by smtp.gmail.com with UTF8SMTPSA id g13-20020a170902c38d00b0019f9fd10f62sm13454823plg.70.2023.05.15.06.06.05 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 15 May 2023 06:06:05 -0700 (PDT) From: jeffxu@chromium.org To: dave.hansen@intel.com, luto@kernel.org, jorgelo@chromium.org, keescook@chromium.org, groeck@chromium.org, jannh@google.com, sroettger@google.com Cc: akpm@linux-foundation.org, jeffxu@google.com, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-mm@kvack.org, linux-hardening@vger.kernel.org Subject: [PATCH 6/6] PKEY:selftest pkey_enforce_api for munmap Date: Mon, 15 May 2023 13:05:52 +0000 Message-ID: <20230515130553.2311248-7-jeffxu@chromium.org> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog In-Reply-To: <20230515130553.2311248-1-jeffxu@chromium.org> References: <20230515130553.2311248-1-jeffxu@chromium.org> MIME-Version: 1.0 X-Stat-Signature: pe3b4xhynp1udiqma6whahfm65gpdp9p X-Rspam-User: X-Rspamd-Queue-Id: E2E0380003 X-Rspamd-Server: rspam07 X-HE-Tag: 1684155967-562415 X-HE-Meta: U2FsdGVkX1+qotQtGKGbbKpkG84NKlmpjBOCzxPAkK4r/LmKxfKxUO1hGfNdy7GCY2PjNBCxeunUp/Mpj49Av7e+pGu5liy+3zQPfM9xQZqBEyoxGH5ZJk7vgeuDSpt6+qizWbPp7qMatcQclvTIMOoVZep6uUMJWJHEKEbklMME7dFOvdNmIgRIfOlENCVzT2tn4dCEGvvYebxthIlasb8HX07fqWeFv3BEm2lfQN/GNubtQ4NxONm0AryXizt+mgC6pReGrtVpOJ5IY1GeQtSwAbl4EIHZaV0qIEg3ce56qxV+QrrN5PuRI5zN6Q+Sv5uKJptY5N+G1eUXwJtp9exUfAS8AaBj73bq0SZqBBU2PhwqcPGQdtWFsliAnKQvXzUxNkN34cs+h7yjuy8wvw3Qnl0qPyw4Z7ak/3+6VhRHpjoSIZoSjwPhGbZ/pBcSiXVPSNwzQPmbm5kftvPg3RneTxJj8IgpnoAuJGCEDdfs/HJzQXeFlgZwkbLazB2Xc7sfdpA1tKuV6LXF6hOiNR8nrwyilmil0lJHAn127eHOfj/AYIL7yR+hVONUvp4u4SQkPVuz5CNRIWaxWqyxkkdzPqLqYFJw71H0hlX63K18Wj6fDR5AbTbxTJf2c6zX1j3Gb5D71MUfRnS5W+68GjgfZm+iXfabDqNO6jE2pOWSxAhzZJG2x4YOY28HZ36Lb+jRfkgSTfGDOFOlP5aTzehGZhH+bbl3OWMUvRAy7Ckpgx8vMMsMTUWLBhsW0YAVLi0tx/MuUTzJ/Iu6ZXS8oRFVNKVYp5vnw6Ztoy2V63ZOSBF26KXpd5kLKQJ1l5i3l/e5qEi+8SVVcq8hEnMMsUhNoluunII9VT2ztzVR5SNOgh7SoKqzPsmdQMRtBWuen+W70TUoDrp70Q/7hfETlentSRhPlWfsyygrjKjbc+U8Ww9eoOD9UOlh8KawqWIygbU99ZUmkeEmcOZBB1n NohGaeje urF8+QEoBMnnoIlCdh7FatAw6TIGZb4fRTJfibsG/8AcpREvqDoV0eXKrcmKYXXW0McpN7Iyn+272gXl56B1w/Ear9slZMgXRBhVQxr+zrwOw1DIZMDZML9UJJppI4qS1bqOHvSC7TFy/4xjGd8gsQ1OXzAdgdGMpZN+OT8FdPnphnixdXB71lpRBHfXOoK+eidD8WFTg4NRkUJLbQUdoyaU0p1l3AS0c2vG3ahrvYMfOWxg/wPUCGIlG9nFTByo40xqN7E9GgwgenyJd1zDeV/1LotFjALj+qB5aodbAvIhd7Yjr3iU00ced4ptyeWPykYCzMSFrXKSx+cLjhP+fHhL34qKUjYjLMIZoLu/vCJHJleCzn/T/Ceg+5Q== 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: From: Jeff Xu Add selftest for pkey_enforce_api for mprotect Signed-off-by: Jeff Xu --- tools/testing/selftests/mm/pkey_enforce_api.c | 437 ++++++++++++++++++ 1 file changed, 437 insertions(+) diff --git a/tools/testing/selftests/mm/pkey_enforce_api.c b/tools/testing/selftests/mm/pkey_enforce_api.c index 23663c89bc9c..92aa29248e1f 100644 --- a/tools/testing/selftests/mm/pkey_enforce_api.c +++ b/tools/testing/selftests/mm/pkey_enforce_api.c @@ -833,6 +833,429 @@ void test_mprotect_child_thread(bool enforce) clean_single_address_with_pkey(pkey, ptr, size); } +// mmap one address with one page. +// assign PKEY to the address. +// munmap on the address is protected. +void test_munmap_single_address(bool enforce) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_single_address_with_pkey(enforce, size, &pkey, &ptr); + + // disable write access. + pkey_write_deny(pkey); + + ret = munmap(ptr, size); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr, size); + assert(!ret); + } + + clean_single_address_with_pkey(pkey, ptr, size); +} + +// mmap two address (continuous two pages). +// assign PKEY to them with one mprotect_pkey call (merged address). +// munmap two address in one call (merged address). +void test_munmap_two_address_merge(bool enforce) +{ + int pkey; + int ret; + void *ptr; + void *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_two_continues_fixed_address_with_pkey(enforce, size, &pkey, &ptr, + &ptr2); + + // disable write. + pkey_write_deny(pkey); + + // munmap on both addresses with one call (merged). + ret = munmap(ptr, size * 2); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr, size * 2); + assert(!ret); + } + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap two address (continuous two pages). +// assign PKEY to the second address. +// munmap on the second address is protected. +void test_munmap_two_address_deny_second(bool enforce) +{ + int pkey; + int ret; + void *ptr; + void *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_two_continues_fixed_address_protect_second_with_pkey( + enforce, size, &pkey, &ptr, &ptr2); + + // disable write through pkey. + pkey_write_deny(pkey); + + ret = munmap(ptr2, size); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + ret = munmap(ptr, size); + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr2, size); + assert(!ret); + } + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap two address (continuous two pages). +// assign PKEY to the second address. +// munmap on the range that includes the second address. +void test_munmap_two_address_deny_range(bool enforce) +{ + int pkey; + int ret; + void *ptr; + void *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_two_continues_fixed_address_protect_second_with_pkey( + enforce, size, &pkey, &ptr, &ptr2); + + // disable write through pkey. + pkey_write_deny(pkey); + + ret = munmap(ptr, size * 2); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr, size * 2); + assert(!ret); + } + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// munmap on memory range that includes the second pages is protected. +void test_munmap_vma_middle_addr(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // munmap support merge, we are going to make sure we don't regress. + ret = munmap(addr1, size * 4); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr, size * 4); + assert(!ret); + } + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// munmap from 2nd page. +void test_munmap_shrink(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // munmap support merge, we are going to make sure we don't regress. + ret = munmap(ptr2, size * 3); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr2, size * 3); + assert(!ret); + } + + ret = munmap(ptr, size); + assert(!ret); + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// munmap from 2nd page but size is less than one page +void test_munmap_unaligned(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // munmap support merge, we are going to make sure we don't regress. + ret = munmap(ptr2, size - 1); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr2, size - 1); + assert(!ret); + } + + ret = munmap(ptr, size * 4); + assert(!ret); + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with 4 pages. +// assign PKEY to the second page only. +// munmap from 2nd page but size is less than one page +void test_munmap_unaligned2(bool enforce) +{ + int pkey; + int ret; + void *ptr, *ptr2, *ptr3; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_4pages_fixed_protect_second_page(enforce, size, &pkey, &ptr, + &ptr2, &ptr3); + + // disable write through pkey. + pkey_write_deny(pkey); + + // munmap support merge, we are going to make sure we don't regress. + ret = munmap(ptr2, size + 1); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(ptr2, size + 1); + assert(!ret); + } + + ret = munmap(ptr, size * 4); + assert(!ret); + + ret = sys_pkey_free(pkey); + assert(ret == 0); +} + +// mmap one address with one page. +// assign PKEY to the address. +// munmap on the address but with size of 4 pages(should OK). +void test_munmap_outbound_addr(bool enforce) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_single_fixed_address_with_pkey(enforce, size, &pkey, &ptr); + + // disable write through pkey. + pkey_write_deny(pkey); + + // Interesting enough, this is allowed, even the other 3 pages are not allocated. + ret = munmap(addr1, size * 4); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey); + + if (enforce) { + ret = munmap(addr1, size * 4); + assert(!ret); + } + + clean_single_address_with_pkey(pkey, ptr, size); +} +// mmap two addresses, with a page gap between two. +// assign pkeys on both address. +// disable access to the second address. +// munmap from start of address1 to the end of address 2, +// because there is a gap in the memory range, mprotect will fail. +void test_munmap_gapped_address_with_two_pkeys(bool enforce) +{ + int pkey, pkey2; + int ret; + void *ptr, *ptr2; + int size = PAGE_SIZE; + + LOG_TEST_ENTER(enforce); + + setup_address_with_gap_two_pkeys(enforce, size, &pkey, &pkey2, &ptr, + &ptr2); + + // disable write access. + pkey_write_deny(pkey2); + + // Interesting enough, this is allowed, even there is a gap beween address 1 and 2. + ret = munmap(addr1, size * 3); + if (enforce) + assert(ret < 0); + else + assert(!ret); + + pkey_write_allow(pkey2); + if (enforce) { + ret = munmap(addr1, size * 3); + assert(!ret); + } +} + +// use write-deny pkey and see if program can exit properly. +// This is manual test, run it at end if needed. +void test_exit_munmap_disable_write(void) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + + pkey = sys_pkey_alloc(PKEY_ENFORCE_API, 0); + assert(pkey > 0); + + // allocate 1 page. + ptr = mmap(addr1, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr == addr1); + + // assign pkey to the first address. + ret = sys_mprotect_pkey(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, + pkey); + assert(!ret); + + // disable write through pkey. + pkey_write_deny(pkey); + + ret = munmap(ptr, size); + assert(ret < 0); +} + +// use disable-all pkey and see if program can exit properly. +// This is manual test, run it at end if needed. +void test_exit_munmap_disable_all(void) +{ + int pkey; + int ret; + void *ptr; + int size = PAGE_SIZE; + + pkey = sys_pkey_alloc(PKEY_ENFORCE_API, 0); + assert(pkey > 0); + + // allocate 1 page. + ptr = mmap(addr2, size, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0); + assert(ptr == addr2); + + // assign pkey to the first address. + ret = sys_mprotect_pkey(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC, + pkey); + assert(!ret); + + // disable write through pkey. + pkey_access_deny(pkey); + + ret = munmap(addr1, size); + assert(ret < 0); +} + void test_enforce_api(void) { for (int i = 0; i < 2; i++) { @@ -848,7 +1271,21 @@ void test_enforce_api(void) test_mprotect_unaligned2(enforce); test_mprotect_child_thread(enforce); test_mprotect_gapped_address_with_two_pkeys(enforce); + + test_munmap_single_address(enforce); + test_munmap_two_address_merge(enforce); + test_munmap_two_address_deny_second(enforce); + test_munmap_two_address_deny_range(enforce); + test_munmap_vma_middle_addr(enforce); + test_munmap_outbound_addr(enforce); + test_munmap_shrink(enforce); + test_munmap_unaligned(enforce); + test_munmap_unaligned2(enforce); + test_munmap_gapped_address_with_two_pkeys(enforce); } + + test_exit_munmap_disable_write(); + test_exit_munmap_disable_all(); } int main(void)