• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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