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 "namespace.h"
17
18 #include "ld_log.h"
19 #include "strops.h"
20
21 static ns_t g_ns_default;
22 static nslist g_ns_list;
23
24 #ifndef NSLIST_DEFAULT_SIZE
25 #define NSLIST_DEFAULT_SIZE 16
26 #endif
27 #ifndef DSOLIST_DEFAULT_SIZE
28 #define DSOLIST_DEFAULT_SIZE 16
29 #endif
30 #ifndef INHERIT_DEFAULT_SIZE
31 #define INHERIT_DEFAULT_SIZE 16
32 #endif
33
34 #ifdef UNIT_TEST_STATIC
35 #define UT_STATIC
36 #else
37 #define UT_STATIC static
38 #endif
39
40 #define ALLOW_ALL_SHARED_LIBS "allow_all_shared_libs"
41
nsinherits_alloc()42 static ns_inherit_list *nsinherits_alloc()
43 {
44 ns_inherit_list *nsinl;
45 nsinl = (ns_inherit_list *)__libc_calloc(1, sizeof *nsinl);
46
47 if (nsinl) {
48 nsinl->size = INHERIT_DEFAULT_SIZE;
49 nsinl->inherits = (ns_inherit **)__libc_calloc(INHERIT_DEFAULT_SIZE, sizeof *nsinl->inherits);
50 if (!nsinl->inherits) {
51 LD_LOGE("nsinherits_alloc failed,return NULL!");
52 __libc_free(nsinl);
53 nsinl = NULL;
54 }
55 }
56 return nsinl;
57 }
58
nsinherits_free(ns_inherit_list * nsinl)59 static void nsinherits_free(ns_inherit_list *nsinl)
60 {
61 if (!nsinl) {
62 return;
63 }
64 for (size_t i = 0; i < nsinl->num; i++) {
65 strlist_free(nsinl->inherits[i]->shared_libs);
66 __libc_free(nsinl->inherits[i]);
67 }
68 __libc_free(nsinl->inherits);
69 __libc_free(nsinl);
70 }
71
nsinherits_realloc(ns_inherit_list * nsinl)72 UT_STATIC void nsinherits_realloc(ns_inherit_list *nsinl)
73 {
74 if (!nsinl) {
75 return;
76 }
77 size_t size = 2 * nsinl->size;
78 if (size) {
79 ns_inherit **inherits;
80 inherits = (ns_inherit **)__libc_realloc(nsinl->inherits, size * (sizeof *nsinl->inherits));
81 if (!inherits) {
82 LD_LOGE("nsinherits_realloc failed!");
83 return;
84 }
85 nsinl->size = size;
86 nsinl->inherits = inherits;
87 }
88 return;
89 }
90
dsolist_alloc()91 static dsolist *dsolist_alloc()
92 {
93 dsolist *dsol;
94 dsol = (dsolist *)__libc_calloc(1, sizeof *dsol);
95
96 if (dsol) {
97 dsol->size = DSOLIST_DEFAULT_SIZE;
98 dsol->dsos = (struct dso **)__libc_calloc(DSOLIST_DEFAULT_SIZE, sizeof *dsol->dsos);
99 if (!dsol->dsos) {
100 LD_LOGE("dsolist_alloc failed,return NULL!");
101 __libc_free(dsol);
102 dsol = NULL;
103 }
104 }
105 return dsol;
106 }
107
dsolist_realloc(dsolist * dsol)108 static void dsolist_realloc(dsolist *dsol)
109 {
110 if (!dsol) {
111 return;
112 }
113 size_t size = 2 * dsol->size;
114 if (size) {
115 struct dso **ds;
116 ds = (struct dso **)__libc_realloc(dsol->dsos, size * (sizeof *dsol->dsos));
117 if (!ds) {
118 LD_LOGE("dsolist_realloc failed!");
119 return;
120 }
121 dsol->size = size;
122 dsol->dsos = ds;
123 }
124 return;
125 }
126
ns_alloc()127 ns_t *ns_alloc()
128 {
129 ns_t *nst = (ns_t *)__libc_calloc(1, sizeof *nst);
130 nst->ns_dsos = dsolist_alloc();
131 if (!nst->ns_dsos) {
132 LD_LOGE("ns_alloc failed,return NULL!");
133 __libc_free(nst);
134 nst = NULL;
135 }
136 return nst;
137 }
138
ns_free(ns_t * ns)139 void ns_free(ns_t *ns)
140 {
141 if (!ns) {
142 return;
143 }
144 if (ns->ns_dsos) {
145 __libc_free(ns->ns_dsos);
146 ns->ns_dsos = NULL;
147 }
148 if (ns->ns_name) {
149 __libc_free(ns->ns_name);
150 ns->ns_name = NULL;
151 }
152 if (ns->env_paths) {
153 __libc_free(ns->env_paths);
154 ns->env_paths = NULL;
155 }
156 if (ns->lib_paths) {
157 __libc_free(ns->lib_paths);
158 ns->lib_paths = NULL;
159 }
160 if (ns->asan_lib_paths) {
161 __libc_free(ns->asan_lib_paths);
162 ns->asan_lib_paths = NULL;
163 }
164 strlist_free(ns->permitted_paths);
165 strlist_free(ns->asan_permitted_paths);
166 strlist_free(ns->allowed_libs);
167 nsinherits_free(ns->ns_inherits);
168 __libc_free(ns);
169 }
170
ns_add_dso(ns_t * ns,struct dso * dso)171 void ns_add_dso(ns_t *ns, struct dso *dso)
172 {
173 if (!ns || !dso) {
174 return;
175 }
176 if (!ns->ns_dsos) {
177 ns->ns_dsos = dsolist_alloc();
178 }
179 if (!ns->ns_dsos) {
180 return;
181 }
182 if (ns->ns_dsos->num == ns->ns_dsos->size) {
183 /* if list is full, realloc size to double*/
184 dsolist_realloc(ns->ns_dsos);
185 }
186 if (ns->ns_dsos->num < ns->ns_dsos->size) {
187 /* realloc succ */
188 ns->ns_dsos->dsos[ns->ns_dsos->num] = dso;
189 ns->ns_dsos->num++;
190 }
191 return;
192 }
193
nslist_init()194 nslist *nslist_init()
195 {
196 g_ns_list.size = NSLIST_DEFAULT_SIZE;
197 g_ns_list.num = 0;
198 g_ns_list.nss = (ns_t **)__libc_calloc(NSLIST_DEFAULT_SIZE, sizeof *g_ns_list.nss);
199 if (!g_ns_list.nss) {
200 LD_LOGE("nslist_init failed!");
201 return NULL;
202 }
203 return &g_ns_list;
204 }
205
nslist_realloc()206 static void nslist_realloc()
207 {
208 size_t size = 2 * g_ns_list.size;
209 if (size) {
210 ns_t **nss;
211 nss = (ns_t **)__libc_realloc(g_ns_list.nss, size * (sizeof *g_ns_list.nss));
212 if (!nss) {
213 LD_LOGE("nslist_realloc failed!");
214 return;
215 }
216 g_ns_list.size = size;
217 g_ns_list.nss = nss;
218 }
219 return;
220 }
221
nslist_add_ns(ns_t * ns)222 void nslist_add_ns(ns_t *ns)
223 {
224 if (!ns) {
225 return;
226 }
227
228 if (g_ns_list.num == g_ns_list.size) {
229 /* if list is full, realloc size to double*/
230 nslist_realloc();
231 }
232 if (g_ns_list.num < g_ns_list.size) {
233 /* realloc succ */
234 g_ns_list.nss[g_ns_list.num] = ns;
235 g_ns_list.num++;
236 }
237 return;
238 }
239
get_default_ns()240 ns_t *get_default_ns()
241 {
242 return &g_ns_default;
243 }
244
245 /* set namespace attributes*/
ns_set_name(ns_t * ns,const char * name)246 void ns_set_name(ns_t *ns, const char *name)
247 {
248 if (!ns || !name) {
249 return;
250 }
251 if (ns->ns_name) __libc_free(ns->ns_name);
252 ns->ns_name = ld_strdup(name);
253 strtrim(ns->ns_name);
254 LD_LOGD("ns_set_name ns_name:%{public}s.", ns->ns_name);
255 }
256
ns_set_env_paths(ns_t * ns,const char * env_paths)257 void ns_set_env_paths(ns_t *ns, const char *env_paths)
258 {
259 if (!ns) {
260 return;
261 }
262 if (ns->env_paths) __libc_free(ns->env_paths);
263 if (env_paths) {
264 ns->env_paths = ld_strdup(env_paths);
265 strtrim(ns->env_paths);
266 } else {
267 ns->env_paths = NULL;
268 }
269 LD_LOGD("ns_set_env_paths ns[%{public}s] env_paths:%{public}s.", ns->ns_name, ns->env_paths);
270 }
271
ns_set_lib_paths(ns_t * ns,const char * lib_paths)272 void ns_set_lib_paths(ns_t *ns, const char *lib_paths)
273 {
274 if (!ns) {
275 return;
276 }
277 if (ns->lib_paths) __libc_free(ns->lib_paths);
278 if (lib_paths) {
279 ns->lib_paths = ld_strdup(lib_paths);
280 strtrim(ns->lib_paths);
281 } else {
282 ns->lib_paths = NULL;
283 }
284 LD_LOGD("ns_set_lib_paths ns[%{public}s] lib_paths:%{public}s.", ns->ns_name, ns->lib_paths);
285 }
286
ns_set_asan_lib_paths(ns_t * ns,const char * asan_lib_paths)287 void ns_set_asan_lib_paths(ns_t *ns, const char *asan_lib_paths)
288 {
289 if (!ns) {
290 return;
291 }
292 if (ns->asan_lib_paths) {
293 __libc_free(ns->asan_lib_paths);
294 }
295 if (asan_lib_paths) {
296 ns->asan_lib_paths = ld_strdup(asan_lib_paths);
297 strtrim(ns->asan_lib_paths);
298 } else {
299 ns->asan_lib_paths = NULL;
300 }
301 LD_LOGD("ns_set_asan_lib_paths ns[%{public}s] asan_lib_paths:%{public}s.", ns->ns_name, ns->asan_lib_paths);
302 }
303
ns_set_permitted_paths(ns_t * ns,const char * permitted_paths)304 void ns_set_permitted_paths(ns_t *ns, const char *permitted_paths)
305 {
306 if (!ns) {
307 return;
308 }
309 if (ns->permitted_paths) strlist_free(ns->permitted_paths);
310 ns->permitted_paths = strsplit(permitted_paths, ":");
311 LD_LOGD("ns_set_permitted_paths ns[%{public}s] permitted_paths:%{public}s.", ns->ns_name, permitted_paths);
312 }
313
ns_set_asan_permitted_paths(ns_t * ns,const char * asan_permitted_paths)314 void ns_set_asan_permitted_paths(ns_t *ns, const char *asan_permitted_paths)
315 {
316 if (!ns) {
317 return;
318 }
319 if (ns->asan_permitted_paths) {
320 strlist_free(ns->asan_permitted_paths);
321 }
322 ns->asan_permitted_paths = strsplit(asan_permitted_paths, ":");
323 LD_LOGD("ns_set_asan_permitted_paths ns[%{public}s] asan_permitted_paths:%{public}s.",
324 ns->ns_name,
325 asan_permitted_paths);
326 }
327
ns_set_separated(ns_t * ns,bool separated)328 void ns_set_separated(ns_t *ns, bool separated)
329 {
330 if (!ns) {
331 return;
332 }
333 ns->separated = separated;
334 LD_LOGD("ns_set_separated ns[%{public}s] separated:%{public}d.", ns->ns_name, ns->separated);
335 }
336
ns_set_allowed_libs(ns_t * ns,const char * allowed_libs)337 void ns_set_allowed_libs(ns_t *ns, const char *allowed_libs)
338 {
339 if (!ns) {
340 return;
341 }
342
343 if (ns->allowed_libs) strlist_free(ns->allowed_libs);
344 ns->allowed_libs = NULL;
345 if (allowed_libs) {
346 /* if setted and not empty, split to list. */
347 char *a_libs = ld_strdup(allowed_libs);
348 if (strtrim(a_libs) > 0) ns->allowed_libs = strsplit(a_libs, ":");
349 __libc_free(a_libs);
350 }
351 LD_LOGD("ns_set_allowed_libs ns[%{public}s] allowed_libs:%{public}s.", ns->ns_name, allowed_libs);
352 }
353
find_ns_by_name(const char * ns_name)354 ns_t *find_ns_by_name(const char *ns_name)
355 {
356 if (!ns_name) {
357 return NULL;
358 }
359 if (strcmp(NS_DEFAULT_NAME, ns_name) == 0) {
360 LD_LOGD("find_ns_by_name return default namespace!");
361 return get_default_ns();
362 }
363 for (size_t i = 0; i < g_ns_list.num; i++) {
364 if (strcmp(g_ns_list.nss[i]->ns_name, ns_name) == 0) {
365 return g_ns_list.nss[i];
366 }
367 }
368 LD_LOGD("find_ns_by_name ns_name[%{public}s] failed,return NULL!", ns_name);
369 return NULL;
370 }
371
find_ns_inherit(ns_t * ns,ns_t * inherited)372 static ns_inherit *find_ns_inherit(ns_t *ns, ns_t *inherited)
373 {
374 if (!ns || !inherited) {
375 return NULL;
376 }
377 if (ns->ns_inherits) {
378 for (size_t i = 0; i < ns->ns_inherits->num; i++) {
379 if (ns->ns_inherits->inherits[i]->inherited_ns == inherited) return ns->ns_inherits->inherits[i];
380 }
381 }
382 LD_LOGD(
383 "find_ns_inherit ns[%{public}s] ns_inherited[%{public}s] failed,return NULL!", ns->ns_name, inherited->ns_name);
384 return NULL;
385 }
386
ns_add_inherit(ns_t * ns,ns_t * ns_inherited,const char * shared_libs)387 void ns_add_inherit(ns_t *ns, ns_t *ns_inherited, const char *shared_libs)
388 {
389 bool need_add = false;
390 if (!ns || !ns_inherited) {
391 return;
392 }
393
394 ns_inherit *inherit = find_ns_inherit(ns, ns_inherited);
395 if (!inherit) {
396 inherit = __libc_calloc(1, sizeof *inherit);
397 if (!inherit) {
398 LD_LOGE("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] calloc failed!",
399 ns->ns_name,
400 ns_inherited->ns_name);
401 return;
402 }
403 inherit->inherited_ns = ns_inherited;
404 need_add = true;
405 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] need_add is true.",
406 ns->ns_name,
407 ns_inherited->ns_name);
408 }
409
410 if (inherit->shared_libs) {
411 strlist_free(inherit->shared_libs);
412 inherit->shared_libs = NULL;
413 }
414
415 /* if setted and not empty, split to list. */
416 if (shared_libs) {
417 char *s_libs = ld_strdup(shared_libs);
418 if (strtrim(s_libs) > 0) inherit->shared_libs = strsplit(shared_libs, ":");
419 __libc_free(s_libs);
420 }
421
422 if (!need_add) {
423 LD_LOGD(
424 "ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] not need_add!", ns->ns_name, ns_inherited->ns_name);
425 return;
426 }
427
428 if (!ns->ns_inherits) {
429 ns->ns_inherits = nsinherits_alloc();
430 }
431
432 if (!ns->ns_inherits) {
433 if (inherit->shared_libs) strlist_free(inherit->shared_libs);
434 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] nsinherits_alloc failed!",
435 ns->ns_name,
436 ns_inherited->ns_name);
437 __libc_free(inherit);
438 return;
439 }
440
441 if (ns->ns_inherits->num == ns->ns_inherits->size) {
442 /* if list is full, realloc size to double*/
443 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] list is full, realloc size to double!",
444 ns->ns_name,
445 ns_inherited->ns_name);
446 nsinherits_realloc(ns->ns_inherits);
447 }
448
449 if (ns->ns_inherits->num < ns->ns_inherits->size) {
450 /* realloc succ */
451 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] realloc success!",
452 ns->ns_name,
453 ns_inherited->ns_name);
454 ns->ns_inherits->inherits[ns->ns_inherits->num] = inherit;
455 ns->ns_inherits->num++;
456 } else {
457 /* realloc failed */
458 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] realloc failed!",
459 ns->ns_name,
460 ns_inherited->ns_name);
461 if (inherit->shared_libs) strlist_free(inherit->shared_libs);
462 __libc_free(inherit);
463 }
464 return;
465 }
466
467 /* check library's pathname if accessible in this namespace */
is_accessible(ns_t * ns,const char * lib_pathname,bool is_asan,bool check_inherited)468 bool is_accessible(ns_t *ns, const char *lib_pathname, bool is_asan, bool check_inherited)
469 {
470 if (check_inherited && !ns->separated) {
471 LD_LOGD("is_accessible ns [%{public}s] is not separated, return true.", ns->ns_name);
472 return true;
473 }
474 if (ns->allowed_libs) {
475 char *shortname = strrchr(lib_pathname, '/');
476 if (shortname) {
477 shortname += 1;
478 size_t i = 0;
479 for (; i < ns->allowed_libs->num; i++) {
480 if (strcmp(shortname, ns->allowed_libs->strs[i]) == 0) {
481 break;
482 }
483 }
484 if (i >= ns->allowed_libs->num) {
485 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] is not in allowed_libs, return false.",
486 ns->ns_name,
487 lib_pathname);
488 return false;
489 }
490 }
491 }
492 strlist *paths;
493 if (ns->env_paths && (paths = strsplit(ns->env_paths, ":"))) {
494 for (size_t i = 0; i < paths->num; i++) {
495 size_t len = strlen(paths->strs[i]);
496 if (strncmp(lib_pathname, paths->strs[i], len) == 0 &&
497 lib_pathname[len] == '/' &&
498 !strchr(lib_pathname + len + 1, '/')) {
499 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] in env_paths, return true.",
500 ns->ns_name,
501 lib_pathname);
502 strlist_free(paths);
503 return true;
504 }
505 }
506 strlist_free(paths);
507 }
508
509 if (is_asan) {
510 if (check_asan_path(ns, lib_pathname)) {
511 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] check_asan_path success, return true.",
512 ns->ns_name,
513 lib_pathname);
514 return true;
515 }
516 }
517
518 if (ns->lib_paths && (paths = strsplit(ns->lib_paths, ":"))) {
519 for (size_t i = 0; i < paths->num; i++) {
520 size_t len = strlen(paths->strs[i]);
521 if (strncmp(lib_pathname, paths->strs[i], len) == 0 &&
522 lib_pathname[len] == '/' &&
523 !strchr(lib_pathname + len + 1, '/')) {
524 strlist_free(paths);
525 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] in lib_paths, return true.",
526 ns->ns_name,
527 lib_pathname);
528 return true;
529 }
530 }
531 strlist_free(paths);
532 }
533
534 if (ns->permitted_paths) {
535 for (size_t i = 0; i < ns->permitted_paths->num; i++) {
536 size_t len = strlen(ns->permitted_paths->strs[i]);
537 if (strncmp(lib_pathname, ns->permitted_paths->strs[i], len) == 0 &&
538 lib_pathname[len] == '/') {
539 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] in permitted_paths, return true.",
540 ns->ns_name,
541 lib_pathname);
542 return true;
543 }
544 }
545 }
546 return false;
547 }
548
check_asan_path(ns_t * ns,const char * lib_pathname)549 bool check_asan_path(ns_t *ns, const char *lib_pathname)
550 {
551 strlist *paths;
552 if (ns->asan_lib_paths && (paths = strsplit(ns->asan_lib_paths, ":"))) {
553 for (size_t i = 0; i < paths->num; i++) {
554 size_t len = strlen(paths->strs[i]);
555 if (strncmp(lib_pathname, paths->strs[i], len) == 0 &&
556 lib_pathname[len] == '/' &&
557 !strchr(lib_pathname + len + 1, '/')) {
558 strlist_free(paths);
559 LD_LOGD("check_asan_path ns [%{public}s] lib_pathname [%{public}s] in asan_lib_paths, return true.",
560 ns->ns_name,
561 lib_pathname);
562 return true;
563 }
564 }
565 strlist_free(paths);
566 }
567 if (ns->asan_permitted_paths) {
568 for (size_t i = 0; i < ns->asan_permitted_paths->num; i++) {
569 size_t len = strlen(ns->asan_permitted_paths->strs[i]);
570 if (strncmp(lib_pathname, ns->asan_permitted_paths->strs[i], len) == 0 &&
571 lib_pathname[len] == '/') {
572 LD_LOGD(
573 "check_asan_path ns [%{public}s] lib_pathname [%{public}s] in asan_permitted_paths, return true.",
574 ns->ns_name,
575 lib_pathname);
576 return true;
577 }
578 }
579 }
580 LD_LOGD(
581 "check_asan_path ns [%{public}s] lib_pathname [%{public}s] failed, return false.", ns->ns_name, lib_pathname);
582 return false;
583 }
584
is_sharable(ns_inherit * inherit,const char * lib_name)585 bool is_sharable(ns_inherit *inherit, const char *lib_name)
586 {
587 if (inherit && lib_name && inherit->shared_libs) {
588 for (size_t i = 0; i < inherit->shared_libs->num; i++) {
589 if (strcmp(inherit->shared_libs->strs[i], lib_name) == 0 ||
590 strcmp(inherit->shared_libs->strs[i], ALLOW_ALL_SHARED_LIBS) == 0) {
591 LD_LOGD("is_sharable inherit [%{public}s] lib_name [%{public}s] found, return true.",
592 inherit->inherited_ns->ns_name,
593 lib_name);
594 return true;
595 }
596 }
597 LD_LOGD("is_sharable inherit [%{public}s] lib_name [%{public}s] not found, return false.",
598 inherit->inherited_ns->ns_name,
599 lib_name);
600 return false;
601 }
602 LD_LOGD("is_sharable shared_libs not config, return true.");
603 return true;
604 }
605
ns_set_flag(ns_t * ns,int flag)606 void ns_set_flag(ns_t *ns, int flag)
607 {
608 if (!ns) {
609 return;
610 }
611 ns->flag = flag;
612 LD_LOGD("ns_set_flag ns[%{public}s] flag:%{public}d.", ns->ns_name, ns->flag);
613 }