xref: /aosp_15_r20/external/llvm-libc/test/src/string/memory_utils/protected_pages.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1 //===-- protected_pages.h -------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // This file provides protected pages that fault when accessing prior or past
9 // it. This is useful to check memory functions that must not access outside of
10 // the provided size limited buffer.
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LIBC_TEST_SRC_STRING_MEMORY_UTILS_PROTECTED_PAGES_H
14 #define LIBC_TEST_SRC_STRING_MEMORY_UTILS_PROTECTED_PAGES_H
15 
16 #include "src/__support/macros/properties/os.h" // LIBC_TARGET_OS_IS_LINUX
17 #if defined(LIBC_FULL_BUILD) || !defined(LIBC_TARGET_OS_IS_LINUX)
18 #error "Protected pages requires mmap and cannot be used in full build mode."
19 #endif // defined(LIBC_FULL_BUILD) || !defined(LIBC_TARGET_OS_IS_LINUX)
20 
21 #include "src/__support/macros/attributes.h" // LIBC_INLINE
22 #include <stddef.h>                          // size_t
23 #include <stdint.h>                          // uint8_t
24 #include <sys/mman.h>                        // mmap, munmap
25 #include <unistd.h>                          // sysconf, _SC_PAGESIZE
26 
27 // Returns mmap page size.
GetPageSize()28 LIBC_INLINE size_t GetPageSize() {
29   static const size_t PAGE_SIZE = sysconf(_SC_PAGESIZE);
30   return PAGE_SIZE;
31 }
32 
33 // Represents a page of memory whose access can be configured throught the
34 // 'WithAccess' function. Accessing data above or below this page will trap as
35 // it is sandwiched between two pages with no read / write access.
36 struct Page {
37   // Returns an aligned pointer that can be accessed up to page_size. Accessing
38   // data at ptr[-1] will fault.
bottomPage39   LIBC_INLINE uint8_t *bottom(size_t size) const {
40     if (size >= page_size)
41       __builtin_trap();
42     return page_ptr;
43   }
44   // Returns a pointer to a buffer that can be accessed up to size. Accessing
45   // data at ptr[size] will trap.
topPage46   LIBC_INLINE uint8_t *top(size_t size) const {
47     return page_ptr + page_size - size;
48   }
49 
50   // protection is one of PROT_READ / PROT_WRITE.
WithAccessPage51   LIBC_INLINE Page &WithAccess(int protection) {
52     if (mprotect(page_ptr, page_size, protection) != 0)
53       __builtin_trap();
54     return *this;
55   }
56 
57   const size_t page_size;
58   uint8_t *const page_ptr;
59 };
60 
61 // Allocates 5 consecutive pages that will trap if accessed.
62 // | page layout | access | page name |
63 // |-------------|--------|:---------:|
64 // | 0           | trap   |           |
65 // | 1           | custom |     A     |
66 // | 2           | trap   |           |
67 // | 3           | custom |     B     |
68 // | 4           | trap   |           |
69 //
70 // The pages A and B can be retrieved as with 'GetPageA' / 'GetPageB' and their
71 // accesses can be customized through the 'WithAccess' function.
72 struct ProtectedPages {
73   static constexpr size_t PAGES = 5;
74 
ProtectedPagesProtectedPages75   ProtectedPages()
76       : page_size(GetPageSize()),
77         ptr(mmap(/*address*/ nullptr, /*length*/ PAGES * page_size,
78                  /*protection*/ PROT_NONE,
79                  /*flags*/ MAP_PRIVATE | MAP_ANONYMOUS, /*fd*/ -1,
80                  /*offset*/ 0)) {
81     if (reinterpret_cast<intptr_t>(ptr) == -1)
82       __builtin_trap();
83   }
~ProtectedPagesProtectedPages84   ~ProtectedPages() { munmap(ptr, PAGES * page_size); }
85 
GetPageAProtectedPages86   LIBC_INLINE Page GetPageA() const { return Page{page_size, page<1>()}; }
GetPageBProtectedPages87   LIBC_INLINE Page GetPageB() const { return Page{page_size, page<3>()}; }
88 
89 private:
pageProtectedPages90   template <size_t index> LIBC_INLINE uint8_t *page() const {
91     static_assert(index < PAGES);
92     return static_cast<uint8_t *>(ptr) + (index * page_size);
93   }
94 
95   const size_t page_size;
96   void *const ptr = nullptr;
97 };
98 
99 #endif // LIBC_TEST_SRC_STRING_MEMORY_UTILS_PROTECTED_PAGES_H
100