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}