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 // Add some valid code to the end of the first page and graceful failure rescue at the beginning of
52 // the second page.
53 constexpr uint32_t kPageCrossingCode[] = {
54     //
55     // First page
56     //
57 
58     // push {lr}
59     //
60     // We may need lr for graceful return if SIGSEGV doesn't happen.
61     0xe52de004,
62     // blx r0
63     //
64     // The only way to check that this was executed (i.e. SIGSEGV didn't happen too early) is to
65     // print something to stderr. Call FirstPageExecutionHelper for this.
66     0xe12fff30,
67     // nop
68     //
69     // Make sure we cross pages without jumps (i.e. we don't
70     // return from blx directly to the second page).
71     0xe320f000,
72 
73     //
74     // Second page
75     //
76 
77     // pop {pc}
78     //
79     // If SIGSEGV doesn't happen, make sure we return cleanly.
80     0xe49df004,
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