1 /*
2 * Copyright 2018 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
18 #include <gtest/gtest.h>
19 #include <unistd.h>
20 #include <signal.h>
21 #include <stdio.h>
22 #include <malloc.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <sys/mman.h>
26 #include <vector>
27 #include <vulkan/vulkan.h>
28 #include <optional>
29
30 char *buffer;
31 volatile int counter = 0;
32
handler(int,siginfo_t * si,void *)33 static void handler (int, siginfo_t *si, void *) {
34 ++counter;
35 ASSERT_EQ(mprotect((void *)((size_t)si->si_addr & ~0xFFFull), 1, PROT_READ | PROT_WRITE), 0) <<
36 "mprotect() error. Can't reset privileges in signal handler.";
37 }
38
TEST(memory,mprotect)39 TEST(memory, mprotect) {
40 VkInstance instance;
41 VkApplicationInfo appInfo = {};
42 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
43 appInfo.pApplicationName = "mprotect test";
44 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
45 appInfo.pEngineName = "No Engine";
46 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
47 appInfo.apiVersion = VK_API_VERSION_1_0;
48
49 VkInstanceCreateInfo createInstanceInfo = {};
50 createInstanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
51 createInstanceInfo.pApplicationInfo = &appInfo;
52
53 ASSERT_EQ(vkCreateInstance(&createInstanceInfo, nullptr, &instance), VK_SUCCESS) << "vkCreateInstance() failed!";
54
55
56
57 VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
58 uint32_t deviceCount = 0;
59 vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
60 ASSERT_GT(deviceCount, 0) << "vkEnumeratePhysicalDevices() could not find a physical device";
61 std::vector<VkPhysicalDevice> devices(deviceCount);
62 vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
63 physicalDevice = devices[0];
64
65
66
67 uint32_t queueFamilyCount = 0;
68 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
69 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
70 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data());
71 uint32_t graphicsFamily = queueFamilyCount+1;
72
73 int i = 0;
74 for (const auto& queueFamily : queueFamilies) {
75 if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
76 graphicsFamily = i;
77 }
78
79 if (graphicsFamily < queueFamilyCount+1) {
80 break;
81 }
82
83 i++;
84 }
85
86 ASSERT_LT(graphicsFamily, queueFamilyCount + 1) << "No Graphics Queue. Can't init Vulkan";
87
88
89
90 VkDevice device;
91
92 VkDeviceQueueCreateInfo queueCreateInfo = {};
93 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
94 queueCreateInfo.queueFamilyIndex = graphicsFamily;
95 queueCreateInfo.queueCount = 1;
96 float queuePriority = 1.0f;
97 queueCreateInfo.pQueuePriorities = &queuePriority;
98
99 VkPhysicalDeviceFeatures deviceFeatures = {};
100 VkDeviceCreateInfo createDeviceInfo = {};
101 createDeviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
102 createDeviceInfo.pQueueCreateInfos = &queueCreateInfo;
103 createDeviceInfo.queueCreateInfoCount = 1;
104 createDeviceInfo.pEnabledFeatures = &deviceFeatures;
105 createDeviceInfo.enabledExtensionCount = 0;
106 createDeviceInfo.enabledLayerCount = 0;
107
108 ASSERT_EQ(vkCreateDevice(physicalDevice, &createDeviceInfo, nullptr, &device), VK_SUCCESS) << "vkCreateDevice() failed!";
109
110
111
112 int pagesize;
113 struct sigaction sa;
114
115 sa.sa_flags = SA_SIGINFO;
116 sigemptyset(&sa.sa_mask);
117 sa.sa_sigaction = handler;
118 ASSERT_EQ(sigaction(SIGSEGV, &sa, nullptr), 0) << "sigaction() failed!";
119
120 pagesize = sysconf(_SC_PAGE_SIZE);
121 ASSERT_GT(pagesize, -1) << "sysconf() failed!";
122
123
124 const int bufferOffset = 2;
125 const int pagesToWrite = 5;
126 const int pagesInBuffer = 4;
127
128
129 VkPhysicalDeviceMemoryProperties memProperties;
130 vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
131
132 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
133 if ((memProperties.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
134 VkMemoryAllocateInfo allocInfo = {};
135 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
136 allocInfo.allocationSize = pagesToWrite * pagesize;
137 allocInfo.memoryTypeIndex = i;
138
139 VkDeviceMemory testBufferMemory;
140
141 ASSERT_EQ(vkAllocateMemory(device, &allocInfo, nullptr, &testBufferMemory), VK_SUCCESS) << "vkAllocateMemory() failed!";
142
143 // Map a "misaligned" 4-page subset of the 5 pages allocated.
144 vkMapMemory(device, testBufferMemory, bufferOffset, pagesInBuffer * pagesize, 0, (void**)&buffer);
145
146 ASSERT_NE(buffer, nullptr) << "vkMapMemory() returned a null buffer.";
147
148 // mprotect requires the beginning of a page as its first parameter. We also map a little more than 4 pages
149 // to make sure we can attempt to write to the final page.
150 ASSERT_EQ(mprotect(buffer - bufferOffset, pagesInBuffer * pagesize + 1, PROT_READ), 0) << "mprotect() failed!";
151
152 for (char *p = buffer; p != (buffer + pagesInBuffer * pagesize); p++) {
153 *p = 'a';
154 }
155
156 vkUnmapMemory(device, testBufferMemory);
157 EXPECT_EQ(pagesToWrite, counter) << "Memory type " << i << " wrote " << counter << " pages instead of " << pagesToWrite;
158 }
159 counter = 0;
160 }
161 }