1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "gtest/gtest.h"
18 
19 #include <sys/mman.h>
20 #include <unistd.h>  // sysconf(_SC_PAGESIZE)
21 
22 #include <cstdint>
23 #include <cstdio>
24 #include <cstring>
25 
26 // Make sure compiler doesn't recognize undefined behavior and doesn't optimize out call to nullptr.
27 volatile void* g_null_addr = nullptr;
28 
29 namespace {
30 
TEST(HandleNotExecutable,NotExecutable)31 TEST(HandleNotExecutable, NotExecutable) {
32   uint32_t* code = reinterpret_cast<uint32_t*>(mmap(0,
33                                                     sysconf(_SC_PAGESIZE),
34                                                     PROT_READ | PROT_WRITE,  // No PROT_EXEC!
35                                                     MAP_PRIVATE | MAP_ANONYMOUS,
36                                                     -1,
37                                                     0));
38   using Func = void (*)();
39   ASSERT_EXIT((reinterpret_cast<Func>(code))(), testing::KilledBySignal(SIGSEGV), "");
40   munmap(code, sysconf(_SC_PAGESIZE));
41 }
42 
TEST(HandleNotExecutable,PcLessThan4096)43 TEST(HandleNotExecutable, PcLessThan4096) {
44   using Func = void (*)();
45   ASSERT_EXIT((reinterpret_cast<Func>(const_cast<void*>(g_null_addr)))(),
46               testing::KilledBySignal(SIGSEGV),
47               "");
48   ASSERT_EXIT((reinterpret_cast<Func>(4095))(), testing::KilledBySignal(SIGSEGV), "");
49 }
50 
51 constexpr uint32_t kPageCrossingCode[] = {
52     //
53     // First page
54     //
55 
56     // str lr, [sp, #-8]! (push lr)
57     //
58     // We may need lr for graceful return if SIGSEGV doesn't happen.
59     0xf81f8ffe,
60     // blr x0
61     //
62     // The only way to check that this was executed (i.e. SIGSEGV didn't happen too early) is to
63     // print something to stderr. Call FirstPageExecutionHelper for this.
64     0xd63f0000,
65     // mov x0, x0
66     //
67     // Make sure we cross pages without jumps (i.e. we don't return from blx directly to the second
68     // page).
69     0xaa0003e0,
70 
71     //
72     // Second page
73     //
74 
75     // ldr lr, [sp], #8 (pop lr)
76     //
77     // If SIGSEGV doesn't happen, make sure we return cleanly.
78     0xf84087fe,
79     // ret
80     0xd65f03c0,
81 };
82 
83 constexpr size_t kFirstPageInsnNum = 3;
84 
FirstPageExecutionHelper()85 void FirstPageExecutionHelper() {
86   fprintf(stderr, "First page has executed");
87 }
88 
TEST(HandleNotExecutable,ExecutableToNotExecutablePageCrossing)89 TEST(HandleNotExecutable, ExecutableToNotExecutablePageCrossing) {
90   const long kPageSize = sysconf(_SC_PAGESIZE);
91   // Allocate two executable pages.
92   uint32_t* first_page = reinterpret_cast<uint32_t*>(mmap(
93       0, kPageSize * 2, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
94 
95   uint32_t* second_page = first_page + (kPageSize / sizeof(uint32_t));
96   // Make second page nonexecutable.
97   mprotect(second_page, kPageSize, PROT_READ | PROT_WRITE);
98 
99   uint32_t* start_addr = second_page - kFirstPageInsnNum;
100   memcpy(start_addr, kPageCrossingCode, sizeof(kPageCrossingCode));
101 
102   using Func = void (*)(void (*)());
103   ASSERT_EXIT((reinterpret_cast<Func>(start_addr))(&FirstPageExecutionHelper),
104               testing::KilledBySignal(SIGSEGV),
105               "First page has executed");
106 
107   munmap(first_page, kPageSize * 2);
108 }
109 
110 }  // namespace
111