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
31 typedef 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
41 static char g_key[MAX_KEY_LEN+1] = {0};
42
config_key_join(const char * join,bool start)43 static 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
default_error_callback(const char * format,...)50 static 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
62 static int (*config_error_callback)(const char *, ...) = default_error_callback;
63
config_set_error_callback(int (* errback)(const char *,...))64 static 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
config_line(char * line,char * section,char * key,char * value)73 static 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
kvlist_alloc(size_t size)113 static 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
kvlist_realloc(kvlist * kvs)135 UT_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
kvlist_free(kvlist * kvs)153 static 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
sections_alloc(size_t size)166 static 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
sections_realloc(section_list * sections)188 UT_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
sections_free(section_list * sections)206 static 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
kvlist_set(kvlist * kvs,const char * key,const char * val)218 static 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
sections_set(section_list * sections,const char * name,const char * key,const char * val)253 static 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
config_load(const char * filepath)287 static 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
357 static 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 */
config_get_kvs(const char * sname)377 static 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 */
config_get_value_by_acquiescence(kvlist * acquiescence_kvs,const char * key)389 static 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 */
config_get_acquiescence_lib_path(kvlist * acquiescence_kvs)404 static 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 */
config_get_acquiescence_asan_lib_path(kvlist * acquiescence_kvs)418 static 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 */
config_get_value(const char * key)434 static 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 */
config_get_lib_paths(const char * ns_name)447 static 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 */
config_get_asan_lib_paths(const char * ns_name)461 static 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 */
config_parse(const char * file_path,const char * exe_path)477 static 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 */
config_get_namespaces()540 static 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 */
config_get_permitted_paths(const char * ns_name)548 static 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 */
config_get_asan_permitted_paths(const char * ns_name)562 static 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 */
config_get_inherits(const char * ns_name)577 static 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 */
config_get_separated(const char * ns_name)591 static 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 */
config_get_allowed_libs(const char * ns_name)608 static 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 */
config_get_inherit_shared_libs(const char * ns_name,const char * inherited_ns_name)621 static 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 */
config_get_sys_paths(void)637 static char *config_get_sys_paths(void)
638 {
639 return g_configor.config_sys_path;
640 }
config_get_asan_sys_paths(void)641 static char *config_get_asan_sys_paths(void)
642 {
643 return g_configor.config_asan_sys_path;
644 }
configor_init()645 ns_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
configor_free()666 void 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 }