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