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(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->dyn_map_len) {
168 munmap(task->dyn_map, task->dyn_map_len);
169 task->dyn_map = NULL;
170 task->dyn_map_len = 0;
171 }
172 if (task->str_map_len) {
173 munmap(task->str_map, task->str_map_len);
174 task->str_map = NULL;
175 task->str_map_len = 0;
176 }
177 if (task->fd != -1 && task->fd) {
178 close(task->fd);
179 task->fd = -1;
180 }
181 __libc_free(task);
182 }
183
get_loadtask(struct loadtasks * tasks,size_t index)184 struct loadtask *get_loadtask(struct loadtasks *tasks, size_t index)
185 {
186 if (tasks && tasks->array && (index < tasks->length)) {
187 return tasks->array[index];
188 } else {
189 return NULL;
190 }
191 }
192
free_loadtasks(struct loadtasks * tasks)193 void free_loadtasks(struct loadtasks *tasks)
194 {
195 if (tasks) {
196 if (tasks->length) {
197 for (int i = 0; i < tasks->length; i++) {
198 free_task(get_loadtask(tasks, i));
199 }
200 tasks->length = 0;
201 }
202 if (tasks->array) {
203 __libc_free(tasks->array);
204 tasks->array = NULL;
205 }
206 tasks->capacity = 0;
207 __libc_free(tasks);
208 }
209 }
210
shuffle_loadtasks(struct loadtasks * tasks)211 void shuffle_loadtasks(struct loadtasks *tasks)
212 {
213 size_t index = 0;
214 struct loadtask *task = NULL;
215 for (size_t i = 0; i < tasks->length; i++) {
216 if (getrandom(&index, sizeof index, GRND_RANDOM | GRND_NONBLOCK) == -1) {
217 return;
218 } else {
219 index %= tasks->length;
220 task = tasks->array[i];
221 tasks->array[i] = tasks->array[index];
222 tasks->array[index] = task;
223 }
224 }
225 }
226
create_loadtask(const char * name,struct dso * needed_by,ns_t * ns,bool check_inherited)227 struct loadtask *create_loadtask(const char *name, struct dso *needed_by, ns_t *ns, bool check_inherited)
228 {
229 size_t name_len = strlen(name);
230 char *name_buf = (char *)__libc_malloc(name_len + 1);
231 if (!name_buf) {
232 return NULL;
233 }
234 struct loadtask *task = __libc_calloc(1, sizeof(struct loadtask));
235 if (!task) {
236 return NULL;
237 }
238 strcpy(name_buf, name);
239 task->name = name_buf;
240 task->needed_by = needed_by;
241 task->namespace = ns;
242 task->check_inherited = check_inherited;
243 task->shdr_allocated_buf = MAP_FAILED;
244 return task;
245 }
246