From patchwork Fri May 19 01:19:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Xu X-Patchwork-Id: 13247586 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 E3D54C77B7A for ; Fri, 19 May 2023 01:19:41 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 1163B280006; Thu, 18 May 2023 21:19:36 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 09F9C280001; Thu, 18 May 2023 21:19:35 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id CABE0280006; Thu, 18 May 2023 21:19:35 -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 B1EA1280001 for ; Thu, 18 May 2023 21:19:35 -0400 (EDT) Received: from smtpin07.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 85A67408D4 for ; Fri, 19 May 2023 01:19:35 +0000 (UTC) X-FDA: 80805247110.07.81B61C2 Received: from mail-pf1-f182.google.com (mail-pf1-f182.google.com [209.85.210.182]) by imf02.hostedemail.com (Postfix) with ESMTP id 9FDC68000C for ; Fri, 19 May 2023 01:19:33 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=jyj0rZJ2; dmarc=pass (policy=none) header.from=chromium.org; spf=pass (imf02.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.210.182 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=1684459173; 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=OkihmIsEpFH/VYAMXMoO3h+Anplam+eErHYf1B/hq9vc9FGNjFnkj2fxWZDfCBaDVjbFnG HlPYDh1MH19Fh44Xc8BPigDQdeM70gr6kCDFnjJApmNZW7NFrv9QUYvS77YD6CtmJdXlAp taG4ak12PxuWgWrvt5Z7hdDr/fK4IFM= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=chromium.org header.s=google header.b=jyj0rZJ2; dmarc=pass (policy=none) header.from=chromium.org; spf=pass (imf02.hostedemail.com: domain of jeffxu@chromium.org designates 209.85.210.182 as permitted sender) smtp.mailfrom=jeffxu@chromium.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1684459173; a=rsa-sha256; cv=none; b=VQEQokHMHcVvYNbnWHzX4qE6uhm1eF2z/azduB3M0IU4xf1YhC1A9hguOzDga7VNSgGwCd D/4Kf3r3TEn5nIgqqi8aJCO/0tHt5vrElO+yhxeQ+xSElk8FaLhrn7vixqDPg2leaaGt1T fE5raqEXhvmiRqbu4c6t7MVT+hHJQdc= Received: by mail-pf1-f182.google.com with SMTP id d2e1a72fcca58-64d2f99c8c3so185521b3a.0 for ; Thu, 18 May 2023 18:19:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1684459172; x=1687051172; 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=jyj0rZJ2+kbh8T1zO6wM8DlV8sGh/w75MLMPMO9zUvD75OwqU1+pvdIyqLBxBdrY3a rXB8rBUenQPxYI61rjx4jyVBrs9t9RT0RsQbQNuzyJdowe7fQEFAAgCJnY1Fu+bAdVH6 13412jqIvJM2IWcUlxkkmtmlW5xdC2AjmAUT8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684459172; x=1687051172; 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=UI3/SUXDbgwwnFpTEu5f1GvoFyboaodHIluTVp9goRK0iOqI6Sql4/s+Qyu+DuL3yI CWYAdNHD9994JwIrLbD9xwpjBi1Q0fXgybGWF2N3YQjEx8MukLCqGExA44NwqSTh3SEK wcmRRU1+Onu/UYqsbHs/OcKTegTcpGZmWTSd9pyxPk9lJ0DB3JWKA5yrc9iQtGnk9zqv TCUpkbr5FILEDQlsmRernDuy04MCcOAZ9XgcglmD8n8SfGZPRqtpYYTw70lMzT4vbRtB rUnWjWvYxYDR6vmaTI3f9qmJ9S8u6ehdQ/zDCCExQPU6wkk/f2f1pZbnH3ikRD+kSVi2 13HA== X-Gm-Message-State: AC+VfDwLPg2XKzgKM64yL9ekOS1IthPwqaUByYs+aJJuLqJQmBC/WXKA 7NFXVmk2shuHSWcTIEQBV0YSMA== X-Google-Smtp-Source: ACHHUZ42BZjasyTlYVo4TSyJkLSwklWvipEkYbBHJRJJtGjHJCThYSy2w2UYA4ZbbF07O8znAL15AQ== X-Received: by 2002:a05:6a00:a91:b0:64a:fa71:a98f with SMTP id b17-20020a056a000a9100b0064afa71a98fmr926851pfl.13.1684459172511; Thu, 18 May 2023 18:19:32 -0700 (PDT) Received: from localhost (183.43.230.35.bc.googleusercontent.com. [35.230.43.183]) by smtp.gmail.com with UTF8SMTPSA id p15-20020a63c14f000000b00528db73ed70sm1870456pgi.3.2023.05.18.18.19.31 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 18 May 2023 18:19:32 -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 v1 6/6] PKEY:selftest pkey_enforce_api for munmap Date: Fri, 19 May 2023 01:19:14 +0000 Message-ID: <20230519011915.846407-7-jeffxu@chromium.org> X-Mailer: git-send-email 2.40.1.698.g37aff9b760-goog In-Reply-To: <20230519011915.846407-1-jeffxu@chromium.org> References: <20230519011915.846407-1-jeffxu@chromium.org> MIME-Version: 1.0 X-Rspamd-Server: rspam09 X-Rspamd-Queue-Id: 9FDC68000C X-Stat-Signature: w45tht187qxodf7r33rzaqy35zfq6h76 X-Rspam-User: X-HE-Tag: 1684459173-742605 X-HE-Meta: U2FsdGVkX18+1Pq47a26dkZXL2L9P8RIMoQHshEDMuUUeuVzbSaleBEnng9i86LOJohUHNmUOWc9o2Dj5hPLQzaJ6eVCQ6EH8crjjsfVtRgGHpWYHXUz2K9gEo7N/1R42YpgP+SbMz251/P6a9yxy6JNnO7KIHMIBCDnuktlnzue0wxD7zHsc73WGq/ITufVRkmmoIP7UBdbGenxHBMnJ14D/H7P2nHICTTG+6nobsq4LS1pe66rnTjbD9nZMkD7jpWtjf9MeKomAV7llEcxJmsg8Hqnn393lRCIzUMXoohaYxH85nc6T06LmB8S+VbzkiA9mYon78MjGrbS7SuE1M9VkD0WB25KWe1UTTlsq9X0/qag8D5eUAKVVsW0NSTvo82WoObGLG0XjbFG8FdcQzZwcty5/nO0WntRRPBFHogqmRqBj+75WK4i8vPbJh/rW59AQbLzXVmzw0vZANpZTpI+q6VEChfdlcr6Zgf+XQSDHyQAtNKuVFlmnDyWJ4CoprMTq0ZC139OkJBZKKPO465qBH7qlaVB1Alh1jx2NuyTApmNKpHsGxxHHHb51EOCE1hughGL9A7i9rMkpjdVkIATTZQl9ySFhAkaYCm58mNoR+zfwQlMyW9P3XzRyWT6vjV1cc+lJpHQsIBO9sZ/xdeYmYWxARS0cUYSLn1Ab7Jn2JyKg1cr7rZDKz6oLSfYGNcN54keoUVB0j+5ah0g8L1VkmUIvy3E5Uprdu1etEWl91PQC1XS7b0CVelCZV7C0/pO62eeKnYakaE32Piiue6b3Hx7vXyERZeN5bbL1YjkMiax3KZGfC6SDRXtCBUcqItg4bgK1XN7B7I+cb5U6qQXV+CQkYerXSMGBAEbgCWlMMCzaFrp/UHW8g5LETOIhlcGAjxKtrcGI5Ugwhh7FclunP6o2AyVIWFe+OBvTD1alKV1941kA+gKZq/BupHo0tF4SJ6EIM7GTuTLhm7 04yVnVcT FK0NWsG9Cfz00txY+4nh1HFtRP/yof/qzWGWy/5bVHUluwWGMXa0wE83GS1Sw/W/JbaW58XmXjJf1W9xwWKGjcXEmV3mtiejspUvWOb+x+JCdKzhnURG2sO9+oeI2E1gMGUQBtNd6vWPDImHrYIdJa0V5KMG7+byhTyvejTxULwnhVhOZnXi+2qf1wwWoR4Ta904V6+5iIxVOGMyFwWXtHMSptMAPN4emCoMnMdGI4dJuFiqC7XhViIJekYsA24VOcccRAHNMqLOZhi5UKKTK6CBjl/u1Hmiw2Rk0pwizBSRRCfQE0SKLoUiDR+FW2OCQXyK45g11zr70KeycwUr458+Gam04rR0g1F2mmivgSlSTOyJXljYg1oV36g== 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)