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
27 struct handle_node {
28 struct handle_node *next;
29 void *handle;
30 struct dso *dso;
31 };
32
33 // linked list for handle randomization
34 static struct handle_node *handle_map_list = NULL;
35
36 static uintptr_t saved_handle = 0;
37
add_handle_node(void * handle,struct dso * dso)38 void *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
find_dso_by_handle(void * handle)51 struct 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
find_handle_by_dso(struct dso * dso)63 void *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
remove_handle_node(void * handle)75 void 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
gen_handle(void)95 static 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
assign_valid_handle(struct dso * p)107 void *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
create_loadtasks(void)119 struct 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
append_loadtasks(struct loadtasks * tasks,struct loadtask * item)131 bool 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
free_task(struct loadtask * task)154 void free_task(struct loadtask *task)
155 {
156 if (task == NULL) {
157 return;
158 }
159 if (task->name) {
160 __libc_free((void *)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
get_loadtask(struct loadtasks * tasks,size_t index)188 struct 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
free_loadtasks(struct loadtasks * tasks)197 void 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
shuffle_loadtasks(struct loadtasks * tasks)215 void 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
create_loadtask(const char * name,struct dso * needed_by,ns_t * ns,bool check_inherited)232 struct 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