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 #include "malloc_impl.h"
24
25 #define HANDLE_INCREASE 2
26 #define TASK_BASE_CAPACITY 8
27
28 // linked list node for handle randomization
29 struct handle_node {
30 struct handle_node *next;
31 void *handle;
32 struct dso *dso;
33 };
34
35 // linked list for handle randomization
36 static struct handle_node *handle_map_list = NULL;
37
38 static uintptr_t saved_handle = 0;
39
add_handle_node(void * handle,struct dso * dso)40 void *add_handle_node(void *handle, struct dso *dso)
41 {
42 struct handle_node *node = internal_malloc(sizeof(*node));
43 if (!node) {
44 return NULL;
45 }
46 node->handle = handle;
47 node->dso = dso;
48 node->next = handle_map_list;
49 handle_map_list = node;
50 return node;
51 }
52
find_dso_by_handle(void * handle)53 struct dso *find_dso_by_handle(void *handle)
54 {
55 struct handle_node *node = handle_map_list;
56 while (node) {
57 if (node->handle == handle) {
58 return node->dso;
59 }
60 node = node->next;
61 }
62 return NULL;
63 }
64
find_handle_by_dso(struct dso * dso)65 static void *find_handle_by_dso(struct dso *dso)
66 {
67 struct handle_node *node = handle_map_list;
68 while (node) {
69 if (node->dso == dso) {
70 return node->handle;
71 }
72 node = node->next;
73 }
74 return 0;
75 }
76
remove_handle_node(void * handle)77 void remove_handle_node(void *handle)
78 {
79 struct handle_node *node = handle_map_list;
80 struct handle_node *pre_node = NULL;
81 while (node) {
82 if (node->handle == handle) {
83 if (pre_node) {
84 pre_node->next = node->next;
85 } else {
86 handle_map_list = node->next;
87 }
88 internal_free(node);
89 return;
90 } else {
91 pre_node = node;
92 node = node->next;
93 }
94 }
95 }
96
gen_handle(void)97 static void *gen_handle(void)
98 {
99 uintptr_t handle = saved_handle;
100 do {
101 if (getrandom(&handle, sizeof handle, GRND_RANDOM | GRND_NONBLOCK) == -1) {
102 handle += HANDLE_INCREASE;
103 saved_handle = handle;
104 }
105 } while (find_dso_by_handle((void *)handle) || handle == 0);
106 return (void *)handle;
107 }
108
assign_valid_handle(struct dso * p)109 void *assign_valid_handle(struct dso *p)
110 {
111 void *handle = find_handle_by_dso(p);
112 if (handle == 0) {
113 handle = gen_handle();
114 if (!add_handle_node(handle, p)) {
115 handle = 0;
116 }
117 }
118 return handle;
119 }
120
create_loadtasks(void)121 struct loadtasks *create_loadtasks(void)
122 {
123 struct loadtasks *tasks = internal_malloc(sizeof(struct loadtasks));
124 if (tasks) {
125 tasks->array = NULL;
126 tasks->capacity = 0;
127 tasks->length = 0;
128 return tasks;
129 }
130 return NULL;
131 }
132
append_loadtasks(struct loadtasks * tasks,struct loadtask * item)133 bool append_loadtasks(struct loadtasks *tasks, struct loadtask *item)
134 {
135 if (tasks->length + 1 > tasks->capacity) {
136 size_t new_cap = 0;
137 new_cap = tasks->capacity + TASK_BASE_CAPACITY;
138 void *realloced = NULL;
139 if (tasks->array) {
140 realloced = internal_realloc(tasks->array, new_cap * sizeof(struct loadtask *));
141 } else {
142 realloced = internal_malloc(TASK_BASE_CAPACITY * sizeof(struct loadtask *));
143 }
144 if (realloced) {
145 tasks->array = realloced;
146 tasks->capacity = new_cap;
147 } else {
148 return false;
149 }
150 }
151 tasks->array[tasks->length] = item;
152 tasks->length += 1;
153 return true;
154 }
155
free_task(struct loadtask * task)156 void free_task(struct loadtask *task)
157 {
158 if (task == NULL) {
159 return;
160 }
161 if (task->name) {
162 internal_free(task->name);
163 task->name = NULL;
164 }
165 if (task->allocated_buf) {
166 internal_free(task->allocated_buf);
167 task->allocated_buf = NULL;
168 }
169 if (task->dyn_map_len) {
170 munmap(task->dyn_map, task->dyn_map_len);
171 task->dyn_map = NULL;
172 task->dyn_map_len = 0;
173 }
174 if (task->str_map_len) {
175 munmap(task->str_map, task->str_map_len);
176 task->str_map = NULL;
177 task->str_map_len = 0;
178 }
179 if (task->fd != -1 && task->fd) {
180 close(task->fd);
181 task->fd = -1;
182 }
183 internal_free(task);
184 }
185
get_loadtask(struct loadtasks * tasks,size_t index)186 struct loadtask *get_loadtask(struct loadtasks *tasks, size_t index)
187 {
188 if (tasks && tasks->array && (index < tasks->length)) {
189 return tasks->array[index];
190 } else {
191 return NULL;
192 }
193 }
194
free_loadtasks(struct loadtasks * tasks)195 void free_loadtasks(struct loadtasks *tasks)
196 {
197 if (tasks) {
198 if (tasks->length) {
199 for (int i = 0; i < tasks->length; i++) {
200 free_task(get_loadtask(tasks, i));
201 }
202 tasks->length = 0;
203 }
204 if (tasks->array) {
205 internal_free(tasks->array);
206 tasks->array = NULL;
207 }
208 tasks->capacity = 0;
209 internal_free(tasks);
210 }
211 }
212
shuffle_loadtasks(struct loadtasks * tasks)213 void shuffle_loadtasks(struct loadtasks *tasks)
214 {
215 size_t index = 0;
216 struct loadtask *task = NULL;
217 for (size_t i = 0; i < tasks->length; i++) {
218 if (getrandom(&index, sizeof index, GRND_RANDOM | GRND_NONBLOCK) == -1) {
219 return;
220 } else {
221 index %= tasks->length;
222 task = tasks->array[i];
223 tasks->array[i] = tasks->array[index];
224 tasks->array[index] = task;
225 }
226 }
227 }
228
create_loadtask(const char * name,struct dso * needed_by,ns_t * ns,bool check_inherited)229 struct loadtask *create_loadtask(const char *name, struct dso *needed_by, ns_t *ns, bool check_inherited)
230 {
231 size_t name_len = strlen(name);
232 char *name_buf = (char *)internal_malloc(name_len + 1);
233 if (!name_buf) {
234 return NULL;
235 }
236 struct loadtask *task = internal_calloc(1, sizeof(struct loadtask));
237 if (!task) {
238 return NULL;
239 }
240 strcpy(name_buf, name);
241 task->name = name_buf;
242 task->needed_by = needed_by;
243 task->namespace = ns;
244 task->check_inherited = check_inherited;
245 return task;
246 }
247