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 "namespace.h" 17 18#include "ld_log.h" 19#include "strops.h" 20 21static ns_t g_ns_default; 22static nslist g_ns_list; 23 24#ifndef NSLIST_DEFAULT_SIZE 25#define NSLIST_DEFAULT_SIZE 16 26#endif 27#ifndef DSOLIST_DEFAULT_SIZE 28#define DSOLIST_DEFAULT_SIZE 16 29#endif 30#ifndef INHERIT_DEFAULT_SIZE 31#define INHERIT_DEFAULT_SIZE 16 32#endif 33 34#ifdef UNIT_TEST_STATIC 35 #define UT_STATIC 36#else 37 #define UT_STATIC static 38#endif 39 40#define ALLOW_ALL_SHARED_LIBS "allow_all_shared_libs" 41 42static ns_inherit_list *nsinherits_alloc() 43{ 44 ns_inherit_list *nsinl; 45 nsinl = (ns_inherit_list *)__libc_calloc(1, sizeof *nsinl); 46 47 if (nsinl) { 48 nsinl->size = INHERIT_DEFAULT_SIZE; 49 nsinl->inherits = (ns_inherit **)__libc_calloc(INHERIT_DEFAULT_SIZE, sizeof *nsinl->inherits); 50 if (!nsinl->inherits) { 51 LD_LOGE("nsinherits_alloc failed,return NULL!"); 52 __libc_free(nsinl); 53 nsinl = NULL; 54 } 55 } 56 return nsinl; 57} 58 59static void nsinherits_free(ns_inherit_list *nsinl) 60{ 61 if (!nsinl) { 62 return; 63 } 64 for (size_t i = 0; i < nsinl->num; i++) { 65 strlist_free(nsinl->inherits[i]->shared_libs); 66 __libc_free(nsinl->inherits[i]); 67 } 68 __libc_free(nsinl->inherits); 69 __libc_free(nsinl); 70} 71 72UT_STATIC void nsinherits_realloc(ns_inherit_list *nsinl) 73{ 74 if (!nsinl) { 75 return; 76 } 77 size_t size = 2 * nsinl->size; 78 if (size) { 79 ns_inherit **inherits; 80 inherits = (ns_inherit **)__libc_realloc(nsinl->inherits, size * (sizeof *nsinl->inherits)); 81 if (!inherits) { 82 LD_LOGE("nsinherits_realloc failed!"); 83 return; 84 } 85 nsinl->size = size; 86 nsinl->inherits = inherits; 87 } 88 return; 89} 90 91static dsolist *dsolist_alloc() 92{ 93 dsolist *dsol; 94 dsol = (dsolist *)__libc_calloc(1, sizeof *dsol); 95 96 if (dsol) { 97 dsol->size = DSOLIST_DEFAULT_SIZE; 98 dsol->dsos = (struct dso **)__libc_calloc(DSOLIST_DEFAULT_SIZE, sizeof *dsol->dsos); 99 if (!dsol->dsos) { 100 LD_LOGE("dsolist_alloc failed,return NULL!"); 101 __libc_free(dsol); 102 dsol = NULL; 103 } 104 } 105 return dsol; 106} 107 108static void dsolist_realloc(dsolist *dsol) 109{ 110 if (!dsol) { 111 return; 112 } 113 size_t size = 2 * dsol->size; 114 if (size) { 115 struct dso **ds; 116 ds = (struct dso **)__libc_realloc(dsol->dsos, size * (sizeof *dsol->dsos)); 117 if (!ds) { 118 LD_LOGE("dsolist_realloc failed!"); 119 return; 120 } 121 dsol->size = size; 122 dsol->dsos = ds; 123 } 124 return; 125} 126 127ns_t *ns_alloc() 128{ 129 ns_t *nst = (ns_t *)__libc_calloc(1, sizeof *nst); 130 nst->ns_dsos = dsolist_alloc(); 131 if (!nst->ns_dsos) { 132 LD_LOGE("ns_alloc failed,return NULL!"); 133 __libc_free(nst); 134 nst = NULL; 135 } 136 return nst; 137} 138 139void ns_free(ns_t *ns) 140{ 141 if (!ns) { 142 return; 143 } 144 if (ns->ns_dsos) { 145 __libc_free(ns->ns_dsos); 146 ns->ns_dsos = NULL; 147 } 148 if (ns->ns_name) { 149 __libc_free(ns->ns_name); 150 ns->ns_name = NULL; 151 } 152 if (ns->env_paths) { 153 __libc_free(ns->env_paths); 154 ns->env_paths = NULL; 155 } 156 if (ns->lib_paths) { 157 __libc_free(ns->lib_paths); 158 ns->lib_paths = NULL; 159 } 160 if (ns->asan_lib_paths) { 161 __libc_free(ns->asan_lib_paths); 162 ns->asan_lib_paths = NULL; 163 } 164 strlist_free(ns->permitted_paths); 165 strlist_free(ns->asan_permitted_paths); 166 strlist_free(ns->allowed_libs); 167 nsinherits_free(ns->ns_inherits); 168 __libc_free(ns); 169} 170 171void ns_add_dso(ns_t *ns, struct dso *dso) 172{ 173 if (!ns || !dso) { 174 return; 175 } 176 if (!ns->ns_dsos) { 177 ns->ns_dsos = dsolist_alloc(); 178 } 179 if (!ns->ns_dsos) { 180 return; 181 } 182 if (ns->ns_dsos->num == ns->ns_dsos->size) { 183 /* if list is full, realloc size to double*/ 184 dsolist_realloc(ns->ns_dsos); 185 } 186 if (ns->ns_dsos->num < ns->ns_dsos->size) { 187 /* realloc succ */ 188 ns->ns_dsos->dsos[ns->ns_dsos->num] = dso; 189 ns->ns_dsos->num++; 190 } 191 return; 192} 193 194nslist *nslist_init() 195{ 196 g_ns_list.size = NSLIST_DEFAULT_SIZE; 197 g_ns_list.num = 0; 198 g_ns_list.nss = (ns_t **)__libc_calloc(NSLIST_DEFAULT_SIZE, sizeof *g_ns_list.nss); 199 if (!g_ns_list.nss) { 200 LD_LOGE("nslist_init failed!"); 201 return NULL; 202 } 203 return &g_ns_list; 204} 205 206static void nslist_realloc() 207{ 208 size_t size = 2 * g_ns_list.size; 209 if (size) { 210 ns_t **nss; 211 nss = (ns_t **)__libc_realloc(g_ns_list.nss, size * (sizeof *g_ns_list.nss)); 212 if (!nss) { 213 LD_LOGE("nslist_realloc failed!"); 214 return; 215 } 216 g_ns_list.size = size; 217 g_ns_list.nss = nss; 218 } 219 return; 220} 221 222void nslist_add_ns(ns_t *ns) 223{ 224 if (!ns) { 225 return; 226 } 227 228 if (g_ns_list.num == g_ns_list.size) { 229 /* if list is full, realloc size to double*/ 230 nslist_realloc(); 231 } 232 if (g_ns_list.num < g_ns_list.size) { 233 /* realloc succ */ 234 g_ns_list.nss[g_ns_list.num] = ns; 235 g_ns_list.num++; 236 } 237 return; 238} 239 240ns_t *get_default_ns() 241{ 242 return &g_ns_default; 243} 244 245/* set namespace attributes*/ 246void ns_set_name(ns_t *ns, const char *name) 247{ 248 if (!ns || !name) { 249 return; 250 } 251 if (ns->ns_name) __libc_free(ns->ns_name); 252 ns->ns_name = ld_strdup(name); 253 strtrim(ns->ns_name); 254 LD_LOGD("ns_set_name ns_name:%{public}s.", ns->ns_name); 255} 256 257void ns_set_env_paths(ns_t *ns, const char *env_paths) 258{ 259 if (!ns) { 260 return; 261 } 262 if (ns->env_paths) __libc_free(ns->env_paths); 263 if (env_paths) { 264 ns->env_paths = ld_strdup(env_paths); 265 strtrim(ns->env_paths); 266 } else { 267 ns->env_paths = NULL; 268 } 269 LD_LOGD("ns_set_env_paths ns[%{public}s] env_paths:%{public}s.", ns->ns_name, ns->env_paths); 270} 271 272void ns_set_lib_paths(ns_t *ns, const char *lib_paths) 273{ 274 if (!ns) { 275 return; 276 } 277 if (ns->lib_paths) __libc_free(ns->lib_paths); 278 if (lib_paths) { 279 ns->lib_paths = ld_strdup(lib_paths); 280 strtrim(ns->lib_paths); 281 } else { 282 ns->lib_paths = NULL; 283 } 284 LD_LOGD("ns_set_lib_paths ns[%{public}s] lib_paths:%{public}s.", ns->ns_name, ns->lib_paths); 285} 286 287void ns_set_asan_lib_paths(ns_t *ns, const char *asan_lib_paths) 288{ 289 if (!ns) { 290 return; 291 } 292 if (ns->asan_lib_paths) { 293 __libc_free(ns->asan_lib_paths); 294 } 295 if (asan_lib_paths) { 296 ns->asan_lib_paths = ld_strdup(asan_lib_paths); 297 strtrim(ns->asan_lib_paths); 298 } else { 299 ns->asan_lib_paths = NULL; 300 } 301 LD_LOGD("ns_set_asan_lib_paths ns[%{public}s] asan_lib_paths:%{public}s.", ns->ns_name, ns->asan_lib_paths); 302} 303 304void ns_set_permitted_paths(ns_t *ns, const char *permitted_paths) 305{ 306 if (!ns) { 307 return; 308 } 309 if (ns->permitted_paths) strlist_free(ns->permitted_paths); 310 ns->permitted_paths = strsplit(permitted_paths, ":"); 311 LD_LOGD("ns_set_permitted_paths ns[%{public}s] permitted_paths:%{public}s.", ns->ns_name, permitted_paths); 312} 313 314void ns_set_asan_permitted_paths(ns_t *ns, const char *asan_permitted_paths) 315{ 316 if (!ns) { 317 return; 318 } 319 if (ns->asan_permitted_paths) { 320 strlist_free(ns->asan_permitted_paths); 321 } 322 ns->asan_permitted_paths = strsplit(asan_permitted_paths, ":"); 323 LD_LOGD("ns_set_asan_permitted_paths ns[%{public}s] asan_permitted_paths:%{public}s.", 324 ns->ns_name, 325 asan_permitted_paths); 326} 327 328void ns_set_separated(ns_t *ns, bool separated) 329{ 330 if (!ns) { 331 return; 332 } 333 ns->separated = separated; 334 LD_LOGD("ns_set_separated ns[%{public}s] separated:%{public}d.", ns->ns_name, ns->separated); 335} 336 337void ns_set_allowed_libs(ns_t *ns, const char *allowed_libs) 338{ 339 if (!ns) { 340 return; 341 } 342 343 if (ns->allowed_libs) strlist_free(ns->allowed_libs); 344 ns->allowed_libs = NULL; 345 if (allowed_libs) { 346 /* if setted and not empty, split to list. */ 347 char *a_libs = ld_strdup(allowed_libs); 348 if (strtrim(a_libs) > 0) ns->allowed_libs = strsplit(a_libs, ":"); 349 __libc_free(a_libs); 350 } 351 LD_LOGD("ns_set_allowed_libs ns[%{public}s] allowed_libs:%{public}s.", ns->ns_name, allowed_libs); 352} 353 354ns_t *find_ns_by_name(const char *ns_name) 355{ 356 if (!ns_name) { 357 return NULL; 358 } 359 if (strcmp(NS_DEFAULT_NAME, ns_name) == 0) { 360 LD_LOGD("find_ns_by_name return default namespace!"); 361 return get_default_ns(); 362 } 363 for (size_t i = 0; i < g_ns_list.num; i++) { 364 if (strcmp(g_ns_list.nss[i]->ns_name, ns_name) == 0) { 365 return g_ns_list.nss[i]; 366 } 367 } 368 LD_LOGD("find_ns_by_name ns_name[%{public}s] failed,return NULL!", ns_name); 369 return NULL; 370} 371 372static ns_inherit *find_ns_inherit(ns_t *ns, ns_t *inherited) 373{ 374 if (!ns || !inherited) { 375 return NULL; 376 } 377 if (ns->ns_inherits) { 378 for (size_t i = 0; i < ns->ns_inherits->num; i++) { 379 if (ns->ns_inherits->inherits[i]->inherited_ns == inherited) return ns->ns_inherits->inherits[i]; 380 } 381 } 382 LD_LOGD( 383 "find_ns_inherit ns[%{public}s] ns_inherited[%{public}s] failed,return NULL!", ns->ns_name, inherited->ns_name); 384 return NULL; 385} 386 387void ns_add_inherit(ns_t *ns, ns_t *ns_inherited, const char *shared_libs) 388{ 389 bool need_add = false; 390 if (!ns || !ns_inherited) { 391 return; 392 } 393 394 ns_inherit *inherit = find_ns_inherit(ns, ns_inherited); 395 if (!inherit) { 396 inherit = __libc_calloc(1, sizeof *inherit); 397 if (!inherit) { 398 LD_LOGE("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] calloc failed!", 399 ns->ns_name, 400 ns_inherited->ns_name); 401 return; 402 } 403 inherit->inherited_ns = ns_inherited; 404 need_add = true; 405 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] need_add is true.", 406 ns->ns_name, 407 ns_inherited->ns_name); 408 } 409 410 if (inherit->shared_libs) { 411 strlist_free(inherit->shared_libs); 412 inherit->shared_libs = NULL; 413 } 414 415 /* if setted and not empty, split to list. */ 416 if (shared_libs) { 417 char *s_libs = ld_strdup(shared_libs); 418 if (strtrim(s_libs) > 0) inherit->shared_libs = strsplit(shared_libs, ":"); 419 __libc_free(s_libs); 420 } 421 422 if (!need_add) { 423 LD_LOGD( 424 "ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] not need_add!", ns->ns_name, ns_inherited->ns_name); 425 return; 426 } 427 428 if (!ns->ns_inherits) { 429 ns->ns_inherits = nsinherits_alloc(); 430 } 431 432 if (!ns->ns_inherits) { 433 if (inherit->shared_libs) strlist_free(inherit->shared_libs); 434 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] nsinherits_alloc failed!", 435 ns->ns_name, 436 ns_inherited->ns_name); 437 __libc_free(inherit); 438 return; 439 } 440 441 if (ns->ns_inherits->num == ns->ns_inherits->size) { 442 /* if list is full, realloc size to double*/ 443 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] list is full, realloc size to double!", 444 ns->ns_name, 445 ns_inherited->ns_name); 446 nsinherits_realloc(ns->ns_inherits); 447 } 448 449 if (ns->ns_inherits->num < ns->ns_inherits->size) { 450 /* realloc succ */ 451 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] realloc success!", 452 ns->ns_name, 453 ns_inherited->ns_name); 454 ns->ns_inherits->inherits[ns->ns_inherits->num] = inherit; 455 ns->ns_inherits->num++; 456 } else { 457 /* realloc failed */ 458 LD_LOGD("ns_add_inherit ns[%{public}s] ns_inherited[%{public}s] realloc failed!", 459 ns->ns_name, 460 ns_inherited->ns_name); 461 if (inherit->shared_libs) strlist_free(inherit->shared_libs); 462 __libc_free(inherit); 463 } 464 return; 465} 466 467/* check library's pathname if accessible in this namespace */ 468bool is_accessible(ns_t *ns, const char *lib_pathname, bool is_asan, bool check_inherited) 469{ 470 if (check_inherited && !ns->separated) { 471 LD_LOGD("is_accessible ns [%{public}s] is not separated, return true.", ns->ns_name); 472 return true; 473 } 474 if (ns->allowed_libs) { 475 char *shortname = strrchr(lib_pathname, '/'); 476 if (shortname) { 477 shortname += 1; 478 size_t i = 0; 479 for (; i < ns->allowed_libs->num; i++) { 480 if (strcmp(shortname, ns->allowed_libs->strs[i]) == 0) { 481 break; 482 } 483 } 484 if (i >= ns->allowed_libs->num) { 485 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] is not in allowed_libs, return false.", 486 ns->ns_name, 487 lib_pathname); 488 return false; 489 } 490 } 491 } 492 strlist *paths; 493 if (ns->env_paths && (paths = strsplit(ns->env_paths, ":"))) { 494 for (size_t i = 0; i < paths->num; i++) { 495 size_t len = strlen(paths->strs[i]); 496 if (strncmp(lib_pathname, paths->strs[i], len) == 0 && 497 lib_pathname[len] == '/' && 498 !strchr(lib_pathname + len + 1, '/')) { 499 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] in env_paths, return true.", 500 ns->ns_name, 501 lib_pathname); 502 strlist_free(paths); 503 return true; 504 } 505 } 506 strlist_free(paths); 507 } 508 509 if (is_asan) { 510 if (check_asan_path(ns, lib_pathname)) { 511 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] check_asan_path success, return true.", 512 ns->ns_name, 513 lib_pathname); 514 return true; 515 } 516 } 517 518 if (ns->lib_paths && (paths = strsplit(ns->lib_paths, ":"))) { 519 for (size_t i = 0; i < paths->num; i++) { 520 size_t len = strlen(paths->strs[i]); 521 if (strncmp(lib_pathname, paths->strs[i], len) == 0 && 522 lib_pathname[len] == '/' && 523 !strchr(lib_pathname + len + 1, '/')) { 524 strlist_free(paths); 525 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] in lib_paths, return true.", 526 ns->ns_name, 527 lib_pathname); 528 return true; 529 } 530 } 531 strlist_free(paths); 532 } 533 534 if (ns->permitted_paths) { 535 for (size_t i = 0; i < ns->permitted_paths->num; i++) { 536 size_t len = strlen(ns->permitted_paths->strs[i]); 537 if (strncmp(lib_pathname, ns->permitted_paths->strs[i], len) == 0 && 538 lib_pathname[len] == '/') { 539 LD_LOGD("is_accessible ns [%{public}s] lib_pathname [%{public}s] in permitted_paths, return true.", 540 ns->ns_name, 541 lib_pathname); 542 return true; 543 } 544 } 545 } 546 return false; 547} 548 549bool check_asan_path(ns_t *ns, const char *lib_pathname) 550{ 551 strlist *paths; 552 if (ns->asan_lib_paths && (paths = strsplit(ns->asan_lib_paths, ":"))) { 553 for (size_t i = 0; i < paths->num; i++) { 554 size_t len = strlen(paths->strs[i]); 555 if (strncmp(lib_pathname, paths->strs[i], len) == 0 && 556 lib_pathname[len] == '/' && 557 !strchr(lib_pathname + len + 1, '/')) { 558 strlist_free(paths); 559 LD_LOGD("check_asan_path ns [%{public}s] lib_pathname [%{public}s] in asan_lib_paths, return true.", 560 ns->ns_name, 561 lib_pathname); 562 return true; 563 } 564 } 565 strlist_free(paths); 566 } 567 if (ns->asan_permitted_paths) { 568 for (size_t i = 0; i < ns->asan_permitted_paths->num; i++) { 569 size_t len = strlen(ns->asan_permitted_paths->strs[i]); 570 if (strncmp(lib_pathname, ns->asan_permitted_paths->strs[i], len) == 0 && 571 lib_pathname[len] == '/') { 572 LD_LOGD( 573 "check_asan_path ns [%{public}s] lib_pathname [%{public}s] in asan_permitted_paths, return true.", 574 ns->ns_name, 575 lib_pathname); 576 return true; 577 } 578 } 579 } 580 LD_LOGD( 581 "check_asan_path ns [%{public}s] lib_pathname [%{public}s] failed, return false.", ns->ns_name, lib_pathname); 582 return false; 583} 584 585bool is_sharable(ns_inherit *inherit, const char *lib_name) 586{ 587 if (inherit && lib_name && inherit->shared_libs) { 588 for (size_t i = 0; i < inherit->shared_libs->num; i++) { 589 if (strcmp(inherit->shared_libs->strs[i], lib_name) == 0 || 590 strcmp(inherit->shared_libs->strs[i], ALLOW_ALL_SHARED_LIBS) == 0) { 591 LD_LOGD("is_sharable inherit [%{public}s] lib_name [%{public}s] found, return true.", 592 inherit->inherited_ns->ns_name, 593 lib_name); 594 return true; 595 } 596 } 597 LD_LOGD("is_sharable inherit [%{public}s] lib_name [%{public}s] not found, return false.", 598 inherit->inherited_ns->ns_name, 599 lib_name); 600 return false; 601 } 602 LD_LOGD("is_sharable shared_libs not config, return true."); 603 return true; 604} 605 606void ns_set_flag(ns_t *ns, int flag) 607{ 608 if (!ns) { 609 return; 610 } 611 ns->flag = flag; 612 LD_LOGD("ns_set_flag ns[%{public}s] flag:%{public}d.", ns->ns_name, ns->flag); 613}