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 }