1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "dynlink_rand.h" 17 18#include <stdlib.h> 19#include <sys/mman.h> 20#include <sys/random.h> 21#include <unistd.h> 22 23#define HANDLE_INCREASE 2 24#define TASK_BASE_CAPACITY 8 25 26// linked list node for handle randomization 27struct handle_node { 28 struct handle_node *next; 29 void *handle; 30 struct dso *dso; 31}; 32 33// linked list for handle randomization 34static struct handle_node *handle_map_list = NULL; 35 36static uintptr_t saved_handle = 0; 37 38void *add_handle_node(void *handle, struct dso *dso) 39{ 40 struct handle_node *node = __libc_malloc(sizeof(*node)); 41 if (!node) { 42 return NULL; 43 } 44 node->handle = handle; 45 node->dso = dso; 46 node->next = handle_map_list; 47 handle_map_list = node; 48 return node; 49} 50 51struct dso *find_dso_by_handle(void *handle) 52{ 53 struct handle_node *node = handle_map_list; 54 while (node) { 55 if (node->handle == handle) { 56 return node->dso; 57 } 58 node = node->next; 59 } 60 return NULL; 61} 62 63void *find_handle_by_dso(struct dso *dso) 64{ 65 struct handle_node *node = handle_map_list; 66 while (node) { 67 if (node->dso == dso) { 68 return node->handle; 69 } 70 node = node->next; 71 } 72 return 0; 73} 74 75void remove_handle_node(void *handle) 76{ 77 struct handle_node *node = handle_map_list; 78 struct handle_node *pre_node = NULL; 79 while (node) { 80 if (node->handle == handle) { 81 if (pre_node) { 82 pre_node->next = node->next; 83 } else { 84 handle_map_list = node->next; 85 } 86 __libc_free(node); 87 return; 88 } else { 89 pre_node = node; 90 node = node->next; 91 } 92 } 93} 94 95static void *gen_handle(void) 96{ 97 uintptr_t handle = saved_handle; 98 do { 99 if (getrandom(&handle, sizeof handle, GRND_RANDOM | GRND_NONBLOCK) == -1) { 100 handle += HANDLE_INCREASE; 101 saved_handle = handle; 102 } 103 } while (find_dso_by_handle((void *)handle) || handle == 0); 104 return (void *)handle; 105} 106 107void *assign_valid_handle(struct dso *p) 108{ 109 void *handle = find_handle_by_dso(p); 110 if (handle == 0) { 111 handle = gen_handle(); 112 if (!add_handle_node(handle, p)) { 113 handle = 0; 114 } 115 } 116 return handle; 117} 118 119struct loadtasks *create_loadtasks(void) 120{ 121 struct loadtasks *tasks = __libc_malloc(sizeof(struct loadtasks)); 122 if (tasks) { 123 tasks->array = NULL; 124 tasks->capacity = 0; 125 tasks->length = 0; 126 return tasks; 127 } 128 return NULL; 129} 130 131bool append_loadtasks(struct loadtasks *tasks, struct loadtask *item) 132{ 133 if (tasks->length + 1 > tasks->capacity) { 134 size_t new_cap = 0; 135 new_cap = tasks->capacity + TASK_BASE_CAPACITY; 136 void *realloced = NULL; 137 if (tasks->array) { 138 realloced = __libc_realloc(tasks->array, new_cap * sizeof(struct loadtask *)); 139 } else { 140 realloced = __libc_malloc(TASK_BASE_CAPACITY * sizeof(struct loadtask *)); 141 } 142 if (realloced) { 143 tasks->array = realloced; 144 tasks->capacity = new_cap; 145 } else { 146 return false; 147 } 148 } 149 tasks->array[tasks->length] = item; 150 tasks->length += 1; 151 return true; 152} 153 154void free_task(struct loadtask *task) 155{ 156 if (task == NULL) { 157 return; 158 } 159 if (task->name) { 160 __libc_free(task->name); 161 task->name = NULL; 162 } 163 if (task->allocated_buf) { 164 __libc_free(task->allocated_buf); 165 task->allocated_buf = NULL; 166 } 167 if (task->shdr_allocated_buf != MAP_FAILED) { 168 munmap(task->shdr_allocated_buf, task->shsize); 169 task->shdr_allocated_buf = MAP_FAILED; 170 } 171 if (task->dyn_map_len) { 172 munmap(task->dyn_map, task->dyn_map_len); 173 task->dyn_map = NULL; 174 task->dyn_map_len = 0; 175 } 176 if (task->str_map_len) { 177 munmap(task->str_map, task->str_map_len); 178 task->str_map = NULL; 179 task->str_map_len = 0; 180 } 181 if (task->fd != -1 && task->fd) { 182 close(task->fd); 183 task->fd = -1; 184 } 185 __libc_free(task); 186} 187 188struct loadtask *get_loadtask(struct loadtasks *tasks, size_t index) 189{ 190 if (tasks && tasks->array && (index < tasks->length)) { 191 return tasks->array[index]; 192 } else { 193 return NULL; 194 } 195} 196 197void free_loadtasks(struct loadtasks *tasks) 198{ 199 if (tasks) { 200 if (tasks->length) { 201 for (int i = 0; i < tasks->length; i++) { 202 free_task(get_loadtask(tasks, i)); 203 } 204 tasks->length = 0; 205 } 206 if (tasks->array) { 207 __libc_free(tasks->array); 208 tasks->array = NULL; 209 } 210 tasks->capacity = 0; 211 __libc_free(tasks); 212 } 213} 214 215void shuffle_loadtasks(struct loadtasks *tasks) 216{ 217 size_t index = 0; 218 struct loadtask *task = NULL; 219 for (size_t i = 0; i < tasks->length; i++) { 220 // Use flag GRND_RANDOM should "block" or "nonblock with retry". This will result in performance loss. 221 if (getrandom(&index, sizeof index, GRND_NONBLOCK) == -1) { 222 return; 223 } else { 224 index %= tasks->length; 225 task = tasks->array[i]; 226 tasks->array[i] = tasks->array[index]; 227 tasks->array[index] = task; 228 } 229 } 230} 231 232struct loadtask *create_loadtask(const char *name, struct dso *needed_by, ns_t *ns, bool check_inherited) 233{ 234 size_t name_len = strlen(name); 235 char *name_buf = (char *)__libc_malloc(name_len + 1); 236 if (!name_buf) { 237 return NULL; 238 } 239 struct loadtask *task = __libc_calloc(1, sizeof(struct loadtask)); 240 if (!task) { 241 return NULL; 242 } 243 strcpy(name_buf, name); 244 task->name = name_buf; 245 task->needed_by = needed_by; 246 task->namespace = ns; 247 task->check_inherited = check_inherited; 248 task->shdr_allocated_buf = MAP_FAILED; 249 return task; 250} 251