xref: /third_party/musl/ldso/linux/ns_config.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 "ns_config.h"
17
18#include <ctype.h>
19#include <stdarg.h>
20
21#include "ld_log.h"
22/*---------------------------- Defines -------------------------------------*/
23#define MAX_LINE_SIZE         (1024)
24#define INI_INVALID_KEY     ((char*)-1)
25
26#ifdef UNIT_TEST_STATIC
27    #define UT_STATIC
28#else
29    #define UT_STATIC static
30#endif
31typedef enum _line_status_ {
32    LINE_UNPROCESSED,
33    LINE_ERROR,
34    LINE_EMPTY,
35    LINE_COMMENT,
36    LINE_SECTION,
37    LINE_VALUE
38} line_status;
39
40#define MAX_KEY_LEN 256
41static char g_key[MAX_KEY_LEN + 1] = {0};
42
43static char *config_key_join(const char *join, bool start)
44{
45    if (start) g_key[0] = 0;
46    size_t cnt = MAX_KEY_LEN - strlen(g_key);
47    return strncat(g_key, join, cnt);
48}
49
50static int default_error_callback(const char *format, ...)
51{
52    int ret = 0;
53    va_list argptr;
54    va_start(argptr, format);
55    /* do not print
56    ret = vfprintf(stderr, format, argptr);
57    */
58    va_end(argptr);
59    return ret;
60}
61
62static int (*config_error_callback)(const char *, ...) = default_error_callback;
63
64static void config_set_error_callback(int (*errback)(const char *, ...))
65{
66    if (errback) {
67        config_error_callback = errback;
68    } else {
69        config_error_callback = default_error_callback;
70    }
71}
72
73static line_status config_line(char *line, char *section, char *key, char *value)
74{
75    size_t len;
76    char *split;
77
78    if ((len = strcspn(line, "#;")) == 0) {
79        /* comment line */
80        return LINE_COMMENT;
81    }
82    line[len] = 0;
83    if ((len = strtrim(line)) == 0) {
84        /* empty line */
85        return LINE_EMPTY;
86    }
87    if (line[0] == '[' && line[len - 1] == ']') {
88        /* section name */
89        memcpy(section, line + 1, len - 2);
90        section[len - 2] = 0;
91        strtrim(section);
92        return LINE_SECTION;
93    }
94    if (split = strchr(line, '=')) {
95        /* key and value */
96        size_t klen, vlen;
97        klen = split - line;
98        vlen = len - klen - 1;
99        if (klen > 0) memcpy(key, line, klen);
100        if (vlen > 0) memcpy(value, split + 1, vlen);
101        key[klen] = 0;
102        value[vlen] = 0;
103        strtrim(key);
104        strtrim(value);
105        return LINE_VALUE;
106    }
107    return LINE_ERROR;
108}
109
110#define SECTION_DEFAULT_SIZE   16
111#define KV_DEFAULT_SIZE   64
112
113static kvlist * kvlist_alloc(size_t size)
114{
115    kvlist *kvs;
116
117    if (size < KV_DEFAULT_SIZE) size = KV_DEFAULT_SIZE;
118
119    kvs = (kvlist *)__libc_calloc(1, sizeof *kvs);
120    if (kvs) {
121        kvs->key = (char **)__libc_calloc(size, sizeof *kvs->key);
122        kvs->val = (char **)__libc_calloc(size, sizeof *kvs->val);
123        if (kvs->key && kvs->val) {
124            kvs->size = size;
125        } else {
126            __libc_free(kvs->key);
127            __libc_free(kvs->val);
128            __libc_free(kvs);
129            kvs = NULL;
130        }
131    }
132    return kvs;
133}
134
135UT_STATIC void kvlist_realloc(kvlist *kvs)
136{
137    if (!kvs) return;
138    size_t size = 2 * kvs->size;
139    if (size) {
140        char **keys, **vals;
141        keys = (char **)__libc_realloc(kvs->key, size * (sizeof *kvs->key));
142        if (!keys) return;
143        kvs->key = keys;
144        vals = (char **)__libc_realloc(kvs->val, size * (sizeof *kvs->val));
145        if (!vals) return;
146        kvs->val = vals;
147        kvs->size = size;
148    }
149
150    return;
151}
152
153static void kvlist_free(kvlist *kvs)
154{
155    size_t i;
156    if (!kvs) return;
157    for (i = 0; i < kvs->num; i++) {
158        __libc_free(kvs->key[i]);
159        __libc_free(kvs->val[i]);
160    }
161    __libc_free(kvs->key);
162    __libc_free(kvs->val);
163    __libc_free(kvs);
164}
165
166static section_list *sections_alloc(size_t size)
167{
168    section_list *sections;
169    if (size < SECTION_DEFAULT_SIZE) size = SECTION_DEFAULT_SIZE;
170
171    sections = (section_list *)__libc_calloc(1, sizeof *sections);
172
173    if (sections) {
174        sections->names = (char**)__libc_calloc(size, sizeof *sections->names);
175        sections->kvs = (kvlist**)__libc_calloc(size, sizeof *sections->kvs);
176        if (sections->names && sections->kvs) {
177            sections->size = size;
178        } else {
179            __libc_free(sections->names);
180            __libc_free(sections->kvs);
181            __libc_free(sections);
182            sections = NULL;
183        }
184    }
185    return sections;
186}
187
188UT_STATIC void sections_realloc(section_list *sections)
189{
190    if (!sections) return;
191    size_t size = 2 * sections->size;
192    if (size) {
193        char **names;
194        kvlist **kvs;
195        names = (char **)__libc_realloc(sections->names, size * (sizeof *sections->names));
196        if (!names) return;
197        sections->names = names;
198        kvs = (kvlist **)__libc_realloc(sections->kvs, size * (sizeof *sections->kvs));
199        if (!kvs) return;
200        sections->kvs = kvs;
201        sections->size = size;
202    }
203    return;
204}
205
206static void sections_free(section_list *sections)
207{
208    if (!sections) return;
209    for (size_t i = 0; i < sections->num; i++) {
210        __libc_free(sections->names[i]);
211        kvlist_free(sections->kvs[i]);
212    }
213    __libc_free(sections->names);
214    __libc_free(sections->kvs);
215    __libc_free(sections);
216}
217
218static void kvlist_set(kvlist *kvs, const char *key, const char *val)
219{
220    size_t i;
221    if (!kvs || !key || !val) return;
222
223    for (i = 0; i < kvs->num; i++) {
224        if (!strcmp(kvs->key[i], key)) {
225            break;
226        }
227    }
228
229    if (i < kvs->num) {
230        char * v = ld_strdup(val);
231        if (v) {
232            __libc_free(kvs->val[i]);
233            kvs->val[i] = v;
234        }
235        return;
236    }
237    if (kvs->num == kvs->size) {
238        kvlist_realloc(kvs);
239    }
240    if (kvs->num < kvs->size) {
241        kvs->key[kvs->num] = ld_strdup(key);
242        kvs->val[kvs->num] = ld_strdup(val);
243        if (kvs->key[kvs->num] && kvs->val[kvs->num]) {
244            kvs->num++;
245        } else {
246            __libc_free(kvs->key[kvs->num]);
247            __libc_free(kvs->val[kvs->num]);
248        }
249    }
250    return;
251}
252
253static void sections_set(section_list *sections, const char *name, const char *key, const char *val)
254{
255    kvlist* kvs = NULL;
256    if (!sections || !name || !key || !val) return;
257
258    for(size_t i = 0; i < sections->num; i++) {
259        if (!strcmp(sections->names[i], name)) {
260            kvs = sections->kvs[i];
261            break;
262        }
263    }
264    if (kvs) {
265        kvlist_set(kvs, key, val);
266        return;
267    }
268
269    if (sections->num == sections->size) {
270       sections_realloc(sections);
271    }
272
273    if (sections->num < sections->size) {
274        kvs = kvlist_alloc(0);
275        sections->names[sections->num] = ld_strdup(name);
276        sections->kvs[sections->num] = kvs;
277        if (sections->names[sections->num] && kvs) {
278            sections->num++;
279            kvlist_set(kvs, key, val);
280        } else {
281            __libc_free(sections->names[sections->num]);
282            kvlist_free(kvs);
283        }
284    }
285}
286
287static section_list *config_load(const char *filepath)
288{
289    FILE *file;
290    char line[MAX_LINE_SIZE + 1];
291    char section[MAX_LINE_SIZE + 1];
292    char key[MAX_LINE_SIZE + 1];
293    char val[MAX_LINE_SIZE + 1];
294
295    size_t  len;
296    int  lineno = 0;
297
298    section_list *sections;
299
300    if ((file = fopen(filepath, "r")) == NULL) {
301        config_error_callback("config: cannot open %s\n", filepath);
302        return NULL;
303    }
304
305    sections = sections_alloc(0);
306    if (!sections) {
307        fclose(file);
308        return NULL;
309    }
310
311    memset(line, 0, sizeof line);
312    memset(section, 0, sizeof section);
313    memset(key, 0, sizeof key);
314    memset(val, 0, sizeof val);
315
316    while (fgets(line, sizeof line, file)) {
317        lineno++;
318        len = strlen(line);
319        if (len == 0) continue;
320
321        if (line[len - 1] != '\n' && !feof(file)) {
322            config_error_callback(
323              "config: input line too long in %s (%d)\n", filepath, lineno);
324            sections_free(sections);
325            fclose(file);
326            return NULL;
327        }
328
329        if (line[len - 1] == '\n') {
330            line[len - 1] = 0;
331            len--;
332        }
333
334        switch (config_line(line, section, key, val)) {
335            case LINE_EMPTY:
336            case LINE_COMMENT:
337            case LINE_SECTION:
338                break;
339            case LINE_VALUE:
340                sections_set(sections, section, key, val);
341                break;
342            case LINE_ERROR:
343                config_error_callback(
344                    "config: syntax error in %s (%d):\n-> %s\n",
345                    filepath,
346                    lineno,
347                    line);
348                break;
349            default:
350                break;
351        }
352    }
353    fclose(file);
354    return sections;
355}
356
357static ns_configor g_configor;
358
359/* const define */
360#define CONFIG_DEFAULT_FILE "/etc/ld-musl-namespace-arm.ini"        /* default config file pathname */
361#define SECTION_DIR_MAP "section.dir.map"   /* map of section and directory of app */
362#define ATTR_NS_PREFIX "namespace"         /* prefix of namespace attribute */
363#define ATTR_NS_ASAN "asan"                /* asan */
364#define ATTR_NS_LIB_PATHS "lib.paths"         /* library search paths */
365#define ATTR_NS_PERMITTED_PATHS "permitted.paths"         /* when separated, permitted dir paths of libs, including sub dirs */
366#define ATTR_NS_INHERITS "inherits"          /* inherited namespace */
367#define ATTR_NS_SEPARATED "separated"         /* if separated */
368#define ATTR_ADDED_NSLIST "added.nslist"      /* all namespace names except default */
369#define ATTR_NS_DEFAULT "default"           /* default namespace name */
370#define ATTR_NS_ACQUIESCENCE "acquiescence"           /* acquiescence section name */
371#define ATTR_NS_ALLOWED_LIBS "allowed.libs"      /* when separated, allowed library names */
372#define ATTR_NS_INHERIT_SHARED_LIBS "shared.libs"      /* when inherited, shared library names */
373#define SECTION_DIR_MAP_SYSTEM "system"      /* system path */
374#define SECTION_DIR_MAP_ASAN_SYSTEM "asan_system"      /* asan system path */
375
376/* get key-value list of section */
377static kvlist *config_get_kvs(const char *sname)
378{
379    size_t  i;
380    for (i = 0; i < g_configor.sections->num; i++) {
381        if (!strcmp(g_configor.sections->names[i], sname)) {
382            return g_configor.sections->kvs[i];
383        }
384    }
385    return NULL;
386}
387
388/* get value by acquiescence */
389static char *config_get_value_by_acquiescence(kvlist *acquiescence_kvs, const char *key)
390{
391    if (!acquiescence_kvs) {
392        return NULL;
393    }
394    size_t i;
395    for (i = 0; i < acquiescence_kvs->num; i++) {
396        if (!strcmp(acquiescence_kvs->key[i], key)) {
397            return acquiescence_kvs->val[i];
398        }
399    }
400    return NULL;
401}
402
403/* get value by acquiescence lib path */
404static char *config_get_acquiescence_lib_path(kvlist *acquiescence_kvs)
405{
406    if (!acquiescence_kvs) {
407        return NULL;
408    }
409    config_key_join(ATTR_NS_PREFIX, true);
410    config_key_join(".", false);
411    config_key_join(ATTR_NS_DEFAULT, false);
412    config_key_join(".", false);
413    char *key = config_key_join(ATTR_NS_LIB_PATHS, false);
414    return config_get_value_by_acquiescence(acquiescence_kvs, key);
415}
416
417/* get value by acquiescence asan lib path */
418static char *config_get_acquiescence_asan_lib_path(kvlist *acquiescence_kvs)
419{
420    if (!acquiescence_kvs) {
421        return NULL;
422    }
423    config_key_join(ATTR_NS_PREFIX, true);
424    config_key_join(".", false);
425    config_key_join(ATTR_NS_DEFAULT, false);
426    config_key_join(".", false);
427    config_key_join(ATTR_NS_ASAN, false);
428    config_key_join(".", false);
429    char *key = config_key_join(ATTR_NS_LIB_PATHS, false);
430    return config_get_value_by_acquiescence(acquiescence_kvs, key);
431}
432
433/* get value by key */
434static char *config_get_value(const char *key)
435{
436    if (!g_configor.kvs) {
437        return NULL;
438    }
439    size_t i;
440    for (i = 0; i < g_configor.kvs->num; i++) {
441        if (!strcmp(g_configor.kvs->key[i], key)) return g_configor.kvs->val[i];
442    }
443    return NULL;
444}
445
446/* get library search paths */
447static char *config_get_lib_paths(const char *ns_name)
448{
449    if (ns_name == NULL) {
450        return NULL;
451    }
452    config_key_join(ATTR_NS_PREFIX, true);
453    config_key_join(".", false);
454    config_key_join(ns_name, false);
455    config_key_join(".", false);
456    char *key = config_key_join(ATTR_NS_LIB_PATHS, false);
457    return config_get_value(key);
458}
459
460/* get asan library search paths */
461static char *config_get_asan_lib_paths(const char *ns_name)
462{
463    if (ns_name == NULL) {
464        return NULL;
465    }
466    config_key_join(ATTR_NS_PREFIX, true);
467    config_key_join(".", false);
468    config_key_join(ns_name, false);
469    config_key_join(".", false);
470    config_key_join(ATTR_NS_ASAN, false);
471    config_key_join(".", false);
472    char *key = config_key_join(ATTR_NS_LIB_PATHS, false);
473    return config_get_value(key);
474}
475
476/* parse config, success 0, failure <0 */
477static int config_parse(const char *file_path, const char *exe_path)
478{
479    kvlist* dirkvs;
480    kvlist* acquiescence_kvs;
481    if (!exe_path) return -1;
482    g_configor.exe_path = ld_strdup(exe_path);
483    const char * fpath = CONFIG_DEFAULT_FILE;
484    if (file_path) fpath = file_path;
485    g_configor.file_path = ld_strdup(fpath);
486    g_configor.sections = config_load(fpath);
487
488    if (!g_configor.sections) {
489        LD_LOGD("config_parse load ini config fail!");
490        return -2;
491    }
492    dirkvs = config_get_kvs(SECTION_DIR_MAP);
493    acquiescence_kvs = config_get_kvs(ATTR_NS_ACQUIESCENCE);
494    if (!dirkvs || !acquiescence_kvs) {
495        LD_LOGD("config_parse get dirkvs or acquiescence_kvs fail!");
496        return -3; /* no section directory map or acquiescence section found */
497    }
498    g_configor.config_sys_path = config_get_acquiescence_lib_path(acquiescence_kvs);
499    g_configor.config_asan_sys_path = config_get_acquiescence_asan_lib_path(acquiescence_kvs);
500    size_t i;
501    char * sname = NULL;
502    for (i = 0; i < dirkvs->num; i++) {
503       strlist * paths = strsplit(dirkvs->val[i], ":");
504       if (paths) {
505           size_t j;
506           for (j = 0; j < paths->num; j++) {
507               if (!strcmp(paths->strs[j], exe_path)) break;
508           }
509           if (j < paths->num) sname = dirkvs->key[i];
510        }
511        strlist_free(paths);
512        if (sname) break;
513    }
514    if (!sname) {
515        /* No matched section found, use the default section. */
516        sname = ATTR_NS_ACQUIESCENCE;
517        LD_LOGD("config_parse no section found!");
518    }
519    if (!(g_configor.kvs = config_get_kvs(sname))) {
520        LD_LOGD("config_parse no section key-value list found!");
521        return -5;/* no section key-value list found */
522    }
523
524    char *default_lib_paths = config_get_lib_paths(ATTR_NS_DEFAULT);
525    if (default_lib_paths) {
526        g_configor.config_sys_path = default_lib_paths;
527    } else {
528        LD_LOGW("config_parse get default lib paths fail! Config namespace default lib paths,please!");
529    }
530    char *default_asan_lib_paths = config_get_asan_lib_paths(ATTR_NS_DEFAULT);
531    if (default_asan_lib_paths) {
532        g_configor.config_asan_sys_path = default_asan_lib_paths;
533    } else {
534        LD_LOGW("config_parse get default asan lib paths fail! Config namespace default asan lib paths,please!");
535    }
536    return 0;
537}
538
539/* get namespace names except default */
540static strlist *config_get_namespaces()
541{
542    char *key = config_key_join(ATTR_ADDED_NSLIST, true);
543    char *val = config_get_value(key);
544    return strsplit(val, ",");
545}
546
547/* get permitted paths */
548static char *config_get_permitted_paths(const char *ns_name)
549{
550    if (ns_name == NULL) {
551        return NULL;
552    }
553    config_key_join(ATTR_NS_PREFIX, true);
554    config_key_join(".", false);
555    config_key_join(ns_name, false);
556    config_key_join(".", false);
557    char *key = config_key_join(ATTR_NS_PERMITTED_PATHS, false);
558    return config_get_value(key);
559}
560
561/* get asan permitted paths */
562static char *config_get_asan_permitted_paths(const char *ns_name)
563{
564    if (ns_name == NULL) {
565        return NULL;
566    }
567    config_key_join(ATTR_NS_PREFIX, true);
568    config_key_join(".", false);
569    config_key_join(ns_name, false);
570    config_key_join(".", false);
571    config_key_join(ATTR_NS_ASAN, false);
572    config_key_join(".", false);
573    char *key = config_key_join(ATTR_NS_PERMITTED_PATHS, false);
574    return config_get_value(key);
575}
576/* get inherited namespace names */
577static strlist *config_get_inherits(const char *ns_name)
578{
579    if (ns_name == NULL) {
580        return NULL;
581    }
582    config_key_join(ATTR_NS_PREFIX, true);
583    config_key_join(".", false);
584    config_key_join(ns_name, false);
585    config_key_join(".", false);
586    char *key = config_key_join(ATTR_NS_INHERITS, false);
587    char *val = config_get_value(key);
588    return strsplit(val, ",");
589}
590/* get separated */
591static bool config_get_separated(const char *ns_name)
592{
593    if (ns_name == NULL) {
594        return false;
595    }
596    config_key_join(ATTR_NS_PREFIX, true);
597    config_key_join(".", false);
598    config_key_join(ns_name, false);
599    config_key_join(".", false);
600    char *key = config_key_join(ATTR_NS_SEPARATED, false);
601    char *val = config_get_value(key);
602    strlwc(val);
603    if (val && !strcmp("true", val)) return true;
604    return false;  /* default false */
605}
606
607/* get allowed libs */
608static char *config_get_allowed_libs(const char *ns_name)
609{
610    if (ns_name == NULL) {
611        return NULL;
612    }
613    config_key_join(ATTR_NS_PREFIX, true);
614    config_key_join(".", false);
615    config_key_join(ns_name, false);
616    config_key_join(".", false);
617    char *key = config_key_join(ATTR_NS_ALLOWED_LIBS, false);
618    return config_get_value(key);
619}
620/* get shared libs by inherited namespace */
621static char *config_get_inherit_shared_libs(const char *ns_name, const char *inherited_ns_name)
622{
623    if (ns_name == NULL || inherited_ns_name == NULL) {
624        return NULL;
625    }
626    config_key_join(ATTR_NS_PREFIX, true);
627    config_key_join(".", false);
628    config_key_join(ns_name, false);
629    config_key_join(".inherit.", false);
630    config_key_join(inherited_ns_name, false);
631    config_key_join(".", false);
632    char *key = config_key_join(ATTR_NS_INHERIT_SHARED_LIBS, false);
633    return config_get_value(key);
634}
635
636/* The call time is after parse */
637static char *config_get_sys_paths(void)
638{
639    return g_configor.config_sys_path;
640}
641static char *config_get_asan_sys_paths(void)
642{
643    return g_configor.config_asan_sys_path;
644}
645ns_configor *configor_init()
646{
647    memset(&g_configor, 0, sizeof g_configor);
648    g_configor.set_error_callback = config_set_error_callback;
649    g_configor.parse = config_parse;
650    g_configor.get_namespaces = config_get_namespaces;
651    g_configor.get_lib_paths = config_get_lib_paths;
652    g_configor.get_asan_lib_paths = config_get_asan_lib_paths;
653    g_configor.get_permitted_paths = config_get_permitted_paths;
654    g_configor.get_asan_permitted_paths = config_get_asan_permitted_paths;
655    g_configor.get_separated = config_get_separated;
656    g_configor.get_inherits = config_get_inherits;
657    g_configor.get_allowed_libs = config_get_allowed_libs;
658    g_configor.get_inherit_shared_libs = config_get_inherit_shared_libs;
659    g_configor.get_sys_paths = config_get_sys_paths;
660    g_configor.get_asan_sys_paths = config_get_asan_sys_paths;
661    g_configor.config_sys_path = NULL; // init it in config_parse.
662    g_configor.config_asan_sys_path = NULL; // init it in config_parse.
663    return &g_configor;
664}
665
666void configor_free()
667{
668    if (g_configor.sections) {
669        sections_free(g_configor.sections);
670        g_configor.sections = NULL;
671    }
672    if (g_configor.file_path) {
673        __libc_free(g_configor.file_path);
674        g_configor.file_path = NULL;
675    }
676    if (g_configor.exe_path) {
677        __libc_free(g_configor.exe_path);
678        g_configor.exe_path = NULL;
679    }
680}