xref: /third_party/musl/ldso/linux/namespace.c (revision 570af302)
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
21static ns_t g_ns_default;
22static 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
42static 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
59static 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
72UT_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
91static 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
108static 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
127ns_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
139void 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
171void 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
194nslist *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
206static 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
222void 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
240ns_t *get_default_ns()
241{
242    return &g_ns_default;
243}
244
245/* set namespace attributes*/
246void 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
257void 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
272void 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
287void 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
304void 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
314void 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
328void 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
337void 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
354ns_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
372static 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
387void 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 */
468bool 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
549bool 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
585bool 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
606void 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}