• 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 "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 }