1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 * Audit interfaces. Auditing can be enabled in two ways: 27 * 28 * o Using the LD_AUDIT environment variable 29 * 30 * o From individual objects containing a DT_DEPAUDIT entry 31 * (see ld(1) -P/-p options). 32 * 33 * The former establishes a global set of audit libraries which can inspect all 34 * objects from a given process. The latter establishes a local set of audit 35 * libraries which can inspect the immediate dependencies of the caller. 36 * 37 * Audit library capabilities are indicated by flags within the link-map list 38 * header (for global auditing), see LML_TFLG_AUD_* flags, or by the same flags 39 * within the individual link-map (for local auditing). Although both sets of 40 * flags can occur in different data items they are defined as one to simplify 41 * audit interface requirements. The basic test for all audit interfaces is: 42 * 43 * if (((lml->lm_tflags | FLAGS1(lmp)) & LML_TFLG_AUD_MASK) && 44 * (lml == LIST(lmp))) 45 * 46 * The latter link-map list equivalence test insures that auditors themselves 47 * (invoked through DT_DEPAUDIT) are not audited. 48 */ 49 #pragma ident "%Z%%M% %I% %E% SMI" 50 51 #include <stdio.h> 52 #include <sys/types.h> 53 #include <sys/lwp.h> 54 #include <stdio.h> 55 #include <stdarg.h> 56 #include <dlfcn.h> 57 #include <string.h> 58 #include <debug.h> 59 #include "_rtld.h" 60 #include "_audit.h" 61 #include "_elf.h" 62 #include "msg.h" 63 64 uint_t audit_flags = 0; /* Copy of specific audit flags to */ 65 /* simplify boot_elf.s access. */ 66 67 static Audit_client * 68 _audit_client(Audit_info *aip, Rt_map *almp) 69 { 70 int ndx; 71 72 if (aip == 0) 73 return (0); 74 75 for (ndx = 0; ndx < aip->ai_cnt; ndx++) { 76 if (aip->ai_clients[ndx].ac_lmp == almp) 77 return (&(aip->ai_clients[ndx])); 78 } 79 return (0); 80 } 81 82 /* 83 * la_filter() caller. Traverse through all audit libraries and call any 84 * la_filter() entry points found. A zero return from an auditor indicates 85 * that the filtee should be ignored. 86 */ 87 static int 88 _audit_objfilter(List *list, Rt_map *frlmp, const char *ref, Rt_map *felmp, 89 uint_t flags) 90 { 91 Audit_list *alp; 92 Listnode *lnp; 93 94 for (LIST_TRAVERSE(list, lnp, alp)) { 95 Audit_client *fracp, *feacp; 96 97 if (alp->al_objfilter == 0) 98 continue; 99 if ((fracp = _audit_client(AUDINFO(frlmp), alp->al_lmp)) == 0) 100 continue; 101 if ((feacp = _audit_client(AUDINFO(felmp), alp->al_lmp)) == 0) 102 continue; 103 104 leave(LIST(alp->al_lmp), thr_flg_reenter); 105 if ((*alp->al_objfilter)(&(fracp->ac_cookie), ref, 106 &(feacp->ac_cookie), flags) == 0) 107 return (0); 108 (void) enter(thr_flg_reenter); 109 } 110 return (1); 111 } 112 113 int 114 audit_objfilter(Rt_map *frlmp, const char *ref, Rt_map *felmp, uint_t flags) 115 { 116 int appl = 0, respond = 1; 117 118 if ((rtld_flags & RT_FL_APPLIC) == 0) 119 appl = rtld_flags |= RT_FL_APPLIC; 120 121 if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJFILTER)) 122 respond = _audit_objfilter(&(auditors->ad_list), frlmp, 123 ref, felmp, flags); 124 if (respond && AUDITORS(frlmp) && 125 (AUDITORS(frlmp)->ad_flags & LML_TFLG_AUD_OBJFILTER)) 126 respond = _audit_objfilter(&(AUDITORS(frlmp)->ad_list), frlmp, 127 ref, felmp, flags); 128 129 if (appl) 130 rtld_flags &= ~RT_FL_APPLIC; 131 132 return (respond); 133 } 134 135 /* 136 * la_objsearch() caller. Traverse through all audit libraries and call any 137 * la_objsearch() entry points found. 138 * 139 * Effectively any audit library can change the name we're working with, so we 140 * continue to propagate the new name to each audit library. Any 0 return 141 * terminates the search. 142 */ 143 static char * 144 _audit_objsearch(List *list, char *name, Rt_map *clmp, uint_t flags) 145 { 146 Audit_list *alp; 147 Listnode *lnp; 148 char *nname = (char *)name; 149 150 for (LIST_TRAVERSE(list, lnp, alp)) { 151 Audit_client *acp; 152 153 if (alp->al_objsearch == 0) 154 continue; 155 if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == 0) 156 continue; 157 158 leave(LIST(alp->al_lmp), thr_flg_reenter); 159 nname = (*alp->al_objsearch)(nname, &(acp->ac_cookie), flags); 160 (void) enter(thr_flg_reenter); 161 if (nname == 0) 162 break; 163 } 164 return (nname); 165 } 166 167 char * 168 audit_objsearch(Rt_map *clmp, const char *name, uint_t flags) 169 { 170 char *nname = (char *)name; 171 int appl = 0; 172 173 if ((rtld_flags & RT_FL_APPLIC) == 0) 174 appl = rtld_flags |= RT_FL_APPLIC; 175 176 if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJSEARCH)) 177 nname = _audit_objsearch(&(auditors->ad_list), nname, 178 clmp, flags); 179 if (nname && AUDITORS(clmp) && 180 (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_OBJSEARCH)) 181 nname = _audit_objsearch(&(AUDITORS(clmp)->ad_list), nname, 182 clmp, flags); 183 184 if (appl) 185 rtld_flags &= ~RT_FL_APPLIC; 186 187 DBG_CALL(Dbg_libs_audit(LIST(clmp), name, nname)); 188 return (nname); 189 } 190 191 /* 192 * la_activity() caller. Traverse through all audit libraries and call any 193 * la_activity() entry points found. 194 */ 195 static void 196 _audit_activity(List *list, Rt_map *clmp, uint_t flags) 197 { 198 Audit_list *alp; 199 Listnode *lnp; 200 Lm_list *clml = LIST(clmp); 201 202 for (LIST_TRAVERSE(list, lnp, alp)) { 203 Audit_client *acp; 204 Rt_map *almp = alp->al_lmp; 205 Lm_list *alml = LIST(almp); 206 207 if (alp->al_activity == 0) 208 continue; 209 if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == 0) 210 continue; 211 212 /* 213 * Make sure the audit library only sees one addition/deletion 214 * at a time. This ensures the library doesn't see numerous 215 * events from lazy loading a series of libraries. Keep track 216 * of this caller having called an auditor, so that the 217 * appropriate "consistent" event can be supplied on leaving 218 * ld.so.1. 219 */ 220 if ((flags == LA_ACT_ADD) || (flags == LA_ACT_DELETE)) { 221 222 if (alml->lm_flags & LML_FLG_AUDITNOTIFY) 223 continue; 224 225 if (aplist_append(&clml->lm_actaudit, clmp, 226 AL_CNT_ACTAUDIT) == NULL) 227 return; 228 229 alml->lm_flags |= LML_FLG_AUDITNOTIFY; 230 231 } else { 232 if ((alml->lm_flags & LML_FLG_AUDITNOTIFY) == 0) 233 continue; 234 235 alml->lm_flags &= ~LML_FLG_AUDITNOTIFY; 236 } 237 238 leave(LIST(alp->al_lmp), thr_flg_reenter); 239 (*alp->al_activity)(&(acp->ac_cookie), flags); 240 (void) enter(thr_flg_reenter); 241 } 242 } 243 244 void 245 audit_activity(Rt_map *clmp, uint_t flags) 246 { 247 int appl = 0; 248 249 if ((rtld_flags & RT_FL_APPLIC) == 0) 250 appl = rtld_flags |= RT_FL_APPLIC; 251 252 if (auditors && (auditors->ad_flags & LML_TFLG_AUD_ACTIVITY)) 253 _audit_activity(&(auditors->ad_list), clmp, flags); 254 if (AUDITORS(clmp) && 255 (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_ACTIVITY)) 256 _audit_activity(&(AUDITORS(clmp)->ad_list), clmp, flags); 257 258 if (appl) 259 rtld_flags &= ~RT_FL_APPLIC; 260 } 261 262 /* 263 * la_objopen() caller. Create an audit information structure for the indicated 264 * link-map, regardless of an la_objopen() entry point. This structure is used 265 * to supply information to various audit interfaces (see LML_MSK_AUDINFO). 266 * Traverse through all audit library and call any la_objopen() entry points 267 * found. 268 */ 269 static int 270 _audit_objopen(List *list, Rt_map *nlmp, Lmid_t lmid, Audit_info *aip, 271 int *ndx) 272 { 273 Audit_list *alp; 274 Listnode *lnp; 275 276 for (LIST_TRAVERSE(list, lnp, alp)) { 277 uint_t flags; 278 Audit_client *acp; 279 280 /* 281 * Associate a cookie with the audit library, and assign the 282 * initial cookie as the present link-map. 283 */ 284 acp = &aip->ai_clients[(*ndx)++]; 285 acp->ac_lmp = alp->al_lmp; 286 acp->ac_cookie = (uintptr_t)nlmp; 287 288 if (alp->al_objopen == 0) 289 continue; 290 291 DBG_CALL(Dbg_audit_object(LIST(alp->al_lmp), alp->al_libname, 292 NAME(nlmp))); 293 294 leave(LIST(alp->al_lmp), thr_flg_reenter); 295 flags = (*alp->al_objopen)((Link_map *)nlmp, lmid, 296 &(acp->ac_cookie)); 297 (void) enter(thr_flg_reenter); 298 299 if (flags & LA_FLG_BINDTO) 300 acp->ac_flags |= FLG_AC_BINDTO; 301 302 if (flags & LA_FLG_BINDFROM) { 303 ulong_t pltcnt; 304 305 acp->ac_flags |= FLG_AC_BINDFROM; 306 /* 307 * We only need dynamic plt's if a pltenter and/or a 308 * pltexit() entry point exist in one of our auditing 309 * libraries. 310 */ 311 if (aip->ai_dynplts || (JMPREL(nlmp) == 0) || 312 ((audit_flags & (AF_PLTENTER | AF_PLTEXIT)) == 0)) 313 continue; 314 315 /* 316 * Create one dynplt for every 'PLT' that exists in the 317 * object. 318 */ 319 pltcnt = PLTRELSZ(nlmp) / RELENT(nlmp); 320 if ((aip->ai_dynplts = calloc(pltcnt, 321 dyn_plt_ent_size)) == 0) 322 return (0); 323 } 324 } 325 return (1); 326 } 327 328 int 329 audit_objopen(Rt_map *clmp, Rt_map *nlmp) 330 { 331 Lmid_t lmid = get_linkmap_id(LIST(nlmp)); 332 int appl = 0, respond = 1, ndx = 0; 333 uint_t clients = 0; 334 Audit_info *aip; 335 336 /* 337 * Determine the total number of audit libraries in use. This provides 338 * the number of client structures required for this object. 339 */ 340 if (auditors) 341 clients = auditors->ad_cnt; 342 if (AUDITORS(clmp)) 343 clients += AUDITORS(clmp)->ad_cnt; 344 if ((nlmp != clmp) && AUDITORS(nlmp)) 345 clients += AUDITORS(nlmp)->ad_cnt; 346 347 /* 348 * The initial allocation of the audit information structure includes 349 * an array of audit clients, 1 per audit library presently available. 350 * 351 * --------------- 352 * | ai_cnt | 353 * Audit_info | ai_clients |------- 354 * | ai_dynplts | | 355 * |---------------| | 356 * Audit_client | 1 |<------ 357 * |---------------| 358 * | 2 | 359 * ......... 360 */ 361 if ((AUDINFO(nlmp) = aip = calloc(1, sizeof (Audit_info) + 362 (sizeof (Audit_client) * clients))) == 0) 363 return (0); 364 365 aip->ai_cnt = clients; 366 aip->ai_clients = (Audit_client *)((uintptr_t)aip + 367 sizeof (Audit_info)); 368 369 if ((rtld_flags & RT_FL_APPLIC) == 0) 370 appl = rtld_flags |= RT_FL_APPLIC; 371 372 if (auditors) 373 respond = _audit_objopen(&(auditors->ad_list), nlmp, 374 lmid, aip, &ndx); 375 if (respond && AUDITORS(clmp)) 376 respond = _audit_objopen(&(AUDITORS(clmp)->ad_list), nlmp, 377 lmid, aip, &ndx); 378 if (respond && (nlmp != clmp) && AUDITORS(nlmp)) 379 respond = _audit_objopen(&(AUDITORS(nlmp)->ad_list), nlmp, 380 lmid, aip, &ndx); 381 382 if (appl) 383 rtld_flags &= ~RT_FL_APPLIC; 384 385 return (respond); 386 } 387 388 /* 389 * la_objclose() caller. Traverse through all audit library and call any 390 * la_objclose() entry points found. 391 */ 392 void 393 _audit_objclose(List *list, Rt_map *lmp) 394 { 395 Audit_list *alp; 396 Listnode *lnp; 397 398 for (LIST_TRAVERSE(list, lnp, alp)) { 399 Audit_client *acp; 400 401 if (alp->al_objclose == 0) 402 continue; 403 if ((acp = _audit_client(AUDINFO(lmp), alp->al_lmp)) == 0) 404 continue; 405 406 leave(LIST(alp->al_lmp), thr_flg_reenter); 407 (*alp->al_objclose)(&(acp->ac_cookie)); 408 (void) enter(thr_flg_reenter); 409 } 410 } 411 412 void 413 audit_objclose(Rt_map *clmp, Rt_map *lmp) 414 { 415 int appl = 0; 416 417 if ((rtld_flags & RT_FL_APPLIC) == 0) 418 appl = rtld_flags |= RT_FL_APPLIC; 419 420 if (auditors && (auditors->ad_flags & LML_TFLG_AUD_OBJCLOSE)) 421 _audit_objclose(&(auditors->ad_list), lmp); 422 if (AUDITORS(clmp) && 423 (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_OBJCLOSE)) 424 _audit_objclose(&(AUDITORS(clmp)->ad_list), lmp); 425 426 if (appl) 427 rtld_flags &= ~RT_FL_APPLIC; 428 } 429 430 /* 431 * la_pltenter() caller. Traverse through all audit library and call any 432 * la_pltenter() entry points found. NOTE: this routine is called via the 433 * glue code established in elf_plt_trace_write(), the symbol descriptor is 434 * created as part of the glue and for 32bit environments the st_name is a 435 * pointer to the real symbol name (ie. it's already been adjusted with the 436 * objects base offset). For 64bit environments the st_name remains the 437 * original symbol offset and in this case it is used to compute the real name 438 * pointer and pass as a separate argument to the auditor. 439 */ 440 static void 441 _audit_pltenter(List *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, 442 uint_t ndx, void *regs, uint_t *flags) 443 { 444 Audit_list *alp; 445 Listnode *lnp; 446 #if defined(_ELF64) 447 const char *name = (const char *)(sym->st_name + STRTAB(dlmp)); 448 #else 449 const char *name = (const char *)(sym->st_name); 450 #endif 451 452 for (LIST_TRAVERSE(list, lnp, alp)) { 453 Audit_client *racp, *dacp; 454 Addr prev = sym->st_value; 455 456 if (alp->al_pltenter == 0) 457 continue; 458 if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == 0) 459 continue; 460 if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == 0) 461 continue; 462 if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) || 463 ((dacp->ac_flags & FLG_AC_BINDTO) == 0)) 464 continue; 465 466 leave(LIST(alp->al_lmp), thr_flg_reenter); 467 sym->st_value = (Addr)(*alp->al_pltenter)(sym, ndx, 468 &(racp->ac_cookie), &(dacp->ac_cookie), regs, 469 /* BEGIN CSTYLED */ 470 #if defined(_ELF64) 471 flags, name); 472 #else 473 flags); 474 #endif 475 /* END CSTYLED */ 476 (void) enter(thr_flg_reenter); 477 478 DBG_CALL(Dbg_audit_symval(LIST(alp->al_lmp), alp->al_libname, 479 MSG_ORIG(MSG_AUD_PLTENTER), name, prev, sym->st_name)); 480 } 481 } 482 483 Addr 484 audit_pltenter(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx, 485 void *regs, uint_t *flags) 486 { 487 Sym _sym = *sym; 488 int _appl = 0; 489 490 /* 491 * We're effectively entering ld.so.1 from user (glue) code. 492 */ 493 (void) enter(0); 494 if ((rtld_flags & RT_FL_APPLIC) == 0) 495 _appl = rtld_flags |= RT_FL_APPLIC; 496 497 if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTENTER)) 498 _audit_pltenter(&(auditors->ad_list), rlmp, dlmp, &_sym, 499 ndx, regs, flags); 500 if (AUDITORS(rlmp) && 501 (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_PLTENTER)) 502 _audit_pltenter(&(AUDITORS(rlmp)->ad_list), rlmp, dlmp, &_sym, 503 ndx, regs, flags); 504 505 if (_appl) 506 rtld_flags &= ~RT_FL_APPLIC; 507 leave(LIST(rlmp), 0); 508 509 return (_sym.st_value); 510 } 511 512 513 /* 514 * la_pltexit() caller. Traverse through all audit library and call any 515 * la_pltexit() entry points found. See notes above (_audit_pltenter) for 516 * discussion on st_name. 517 */ 518 static Addr 519 _audit_pltexit(List *list, uintptr_t retval, Rt_map *rlmp, Rt_map *dlmp, 520 Sym *sym, uint_t ndx) 521 { 522 Audit_list *alp; 523 Listnode *lnp; 524 #if defined(_ELF64) 525 const char *name = (const char *)(sym->st_name + STRTAB(dlmp)); 526 #endif 527 528 for (LIST_TRAVERSE(list, lnp, alp)) { 529 Audit_client *racp, *dacp; 530 531 if (alp->al_pltexit == 0) 532 continue; 533 if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == 0) 534 continue; 535 if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == 0) 536 continue; 537 if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) || 538 ((dacp->ac_flags & FLG_AC_BINDTO) == 0)) 539 continue; 540 541 leave(LIST(alp->al_lmp), thr_flg_reenter); 542 retval = (*alp->al_pltexit)(sym, ndx, 543 &(racp->ac_cookie), &(dacp->ac_cookie), 544 /* BEGIN CSTYLED */ 545 #if defined(_ELF64) 546 retval, name); 547 #else 548 retval); 549 #endif 550 /* END CSTYLED */ 551 (void) enter(thr_flg_reenter); 552 } 553 return (retval); 554 } 555 556 Addr 557 audit_pltexit(uintptr_t retval, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, 558 uint_t ndx) 559 { 560 uintptr_t _retval = retval; 561 int _appl = 0; 562 563 /* 564 * We're effectively entering ld.so.1 from user (glue) code. 565 */ 566 (void) enter(0); 567 if ((rtld_flags & RT_FL_APPLIC) == 0) 568 _appl = rtld_flags |= RT_FL_APPLIC; 569 570 if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PLTEXIT)) 571 _retval = _audit_pltexit(&(auditors->ad_list), _retval, 572 rlmp, dlmp, sym, ndx); 573 if (AUDITORS(rlmp) && (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_PLTEXIT)) 574 _retval = _audit_pltexit(&(AUDITORS(rlmp)->ad_list), _retval, 575 rlmp, dlmp, sym, ndx); 576 577 if (_appl) 578 rtld_flags &= ~RT_FL_APPLIC; 579 leave(LIST(rlmp), 0); 580 581 return (_retval); 582 } 583 584 585 /* 586 * la_symbind() caller. Traverse through all audit library and call any 587 * la_symbind() entry points found. 588 */ 589 static Addr 590 _audit_symbind(List *list, Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx, 591 uint_t *flags, int *called) 592 { 593 Audit_list *alp; 594 Listnode *lnp; 595 #if defined(_ELF64) 596 const char *name = (const char *)(sym->st_name + STRTAB(dlmp)); 597 #else 598 const char *name = (const char *)(sym->st_name); 599 #endif 600 601 for (LIST_TRAVERSE(list, lnp, alp)) { 602 Audit_client *racp, *dacp; 603 Addr prev = sym->st_value; 604 uint_t lflags; 605 606 if (alp->al_symbind == 0) 607 continue; 608 if ((racp = _audit_client(AUDINFO(rlmp), alp->al_lmp)) == 0) 609 continue; 610 if ((dacp = _audit_client(AUDINFO(dlmp), alp->al_lmp)) == 0) 611 continue; 612 if (((racp->ac_flags & FLG_AC_BINDFROM) == 0) || 613 ((dacp->ac_flags & FLG_AC_BINDTO) == 0)) 614 continue; 615 616 /* 617 * The la_symbind interface is only called when the calling 618 * object has been identified as BINDFROM, and the destination 619 * object has been identified as BINDTO. Use a local version of 620 * the flags, so that any user update can be collected. 621 */ 622 called++; 623 lflags = (*flags & ~(LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)); 624 625 leave(LIST(alp->al_lmp), thr_flg_reenter); 626 sym->st_value = (*alp->al_symbind)(sym, ndx, 627 &(racp->ac_cookie), &(dacp->ac_cookie), 628 /* BEGIN CSTYLED */ 629 #if defined(_ELF64) 630 &lflags, name); 631 #else 632 &lflags); 633 #endif 634 /* END CSTYLED */ 635 (void) enter(thr_flg_reenter); 636 637 /* 638 * If the auditor indicated that they did not want to process 639 * pltenter, or pltexit audits for this symbol, retain this 640 * information. Also retain whether an alternative symbol value 641 * has been supplied. 642 */ 643 *flags |= (lflags & (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT)); 644 if ((prev != sym->st_value) && (alp->al_vernum >= LAV_VERSION2)) 645 *flags |= LA_SYMB_ALTVALUE; 646 647 DBG_CALL(Dbg_audit_symval(LIST(alp->al_lmp), alp->al_libname, 648 MSG_ORIG(MSG_AUD_SYMBIND), name, prev, sym->st_value)); 649 } 650 return (sym->st_value); 651 } 652 653 Addr 654 audit_symbind(Rt_map *rlmp, Rt_map *dlmp, Sym *sym, uint_t ndx, Addr value, 655 uint_t *flags) 656 { 657 Sym _sym; 658 int _appl = 0, called = 0; 659 660 /* 661 * Construct a new symbol from that supplied but with the real address. 662 * In the 64-bit world the st_name field is only 32-bits which isn't 663 * big enough to hold a character pointer. We pass this pointer as a 664 * separate parameter for 64-bit audit libraries. 665 */ 666 _sym = *sym; 667 _sym.st_value = value; 668 669 #if !defined(_ELF64) 670 _sym.st_name += (Word)STRTAB(dlmp); 671 #endif 672 if ((rtld_flags & RT_FL_APPLIC) == 0) 673 _appl = rtld_flags |= RT_FL_APPLIC; 674 675 if (auditors && (auditors->ad_flags & LML_TFLG_AUD_SYMBIND)) 676 _sym.st_value = _audit_symbind(&(auditors->ad_list), 677 rlmp, dlmp, &_sym, ndx, flags, &called); 678 if (AUDITORS(rlmp) && (AUDITORS(rlmp)->ad_flags & LML_TFLG_AUD_SYMBIND)) 679 _sym.st_value = _audit_symbind(&(AUDITORS(rlmp)->ad_list), 680 rlmp, dlmp, &_sym, ndx, flags, &called); 681 682 /* 683 * If no la_symbind() was called for this interface, fabricate that no 684 * la_pltenter, or la_pltexit is required. This helps reduce the glue 685 * code created for further auditing. 686 */ 687 if (caller == 0) 688 *flags |= (LA_SYMB_NOPLTENTER | LA_SYMB_NOPLTEXIT); 689 690 if (_appl) 691 rtld_flags &= ~RT_FL_APPLIC; 692 693 return (_sym.st_value); 694 } 695 696 697 /* 698 * la_preinit() caller. Traverse through all audit libraries and call any 699 * la_preinit() entry points found. 700 */ 701 static void 702 _audit_preinit(List *list, Rt_map *clmp) 703 { 704 Audit_list *alp; 705 Listnode *lnp; 706 707 for (LIST_TRAVERSE(list, lnp, alp)) { 708 Audit_client *acp; 709 710 if (alp->al_preinit == 0) 711 continue; 712 if ((acp = _audit_client(AUDINFO(clmp), alp->al_lmp)) == 0) 713 continue; 714 715 leave(LIST(alp->al_lmp), thr_flg_reenter); 716 (*alp->al_preinit)(&(acp->ac_cookie)); 717 (void) enter(thr_flg_reenter); 718 } 719 } 720 721 void 722 audit_preinit(Rt_map *clmp) 723 { 724 int appl = 0; 725 726 if ((rtld_flags & RT_FL_APPLIC) == 0) 727 appl = rtld_flags |= RT_FL_APPLIC; 728 729 if (auditors && (auditors->ad_flags & LML_TFLG_AUD_PREINIT)) 730 _audit_preinit(&(auditors->ad_list), clmp); 731 if (AUDITORS(clmp) && (AUDITORS(clmp)->ad_flags & LML_TFLG_AUD_PREINIT)) 732 _audit_preinit(&(AUDITORS(clmp)->ad_list), clmp); 733 734 if (appl) 735 rtld_flags &= ~RT_FL_APPLIC; 736 } 737 738 739 /* 740 * Clean up (free) an audit descriptor. First, gather a list of all handles, 741 * and then close each one down. This is done rather than using the handles 742 * directly from the auditors, as the audit list can be torn down as a result 743 * of the dlclose. In other words, what you're pointing at can be removed 744 * while your still pointing at it. 745 */ 746 void 747 audit_desc_cleanup(Rt_map *clmp) 748 { 749 Audit_desc *adp = AUDITORS(clmp); 750 Audit_list *alp; 751 Listnode *lnp, *olnp; 752 APlist *ghalp = NULL; 753 754 if (adp == 0) 755 return; 756 if (adp->ad_name) 757 free(adp->ad_name); 758 759 olnp = 0; 760 for (LIST_TRAVERSE(&(adp->ad_list), lnp, alp)) { 761 (void) aplist_append(&ghalp, alp->al_ghp, AL_CNT_GROUPS); 762 763 if (olnp) 764 free(olnp); 765 olnp = lnp; 766 } 767 if (olnp) 768 free(olnp); 769 770 free(adp); 771 AUDITORS(clmp) = 0; 772 773 if (ghalp) { 774 Grp_hdl *ghp; 775 Aliste idx; 776 777 for (APLIST_TRAVERSE(ghalp, idx, ghp)) { 778 (void) dlclose_intn(ghp, clmp); 779 } 780 free(ghalp); 781 } 782 } 783 784 /* 785 * Clean up (free) an audit information structure. 786 */ 787 void 788 audit_info_cleanup(Rt_map *clmp) 789 { 790 Audit_info *aip = AUDINFO(clmp); 791 792 if (aip == 0) 793 return; 794 795 if (aip->ai_dynplts) 796 free(aip->ai_dynplts); 797 free(aip); 798 } 799 800 /* 801 * Create a data structure of symbol lookup names and associated flags to help 802 * simplify audit_symget() use. 803 */ 804 typedef struct { 805 Msg sname; 806 uint_t alflag; 807 uint_t auflag; 808 } Aud_info; 809 810 static const Aud_info aud_info[] = { 811 { MSG_SYM_LAVERSION, 0 }, /* MSG_ORIG(MSG_SYM_LAVERSION) */ 812 { MSG_SYM_LAPREINIT, /* MSG_ORIG(MSG_SYM_LAPREINIT) */ 813 LML_TFLG_AUD_PREINIT, 0 }, 814 { MSG_SYM_LAOBJSEARCH, /* MSG_ORIG(MSG_SYM_LAOBJSEARCH) */ 815 LML_TFLG_AUD_OBJSEARCH, 0 }, 816 { MSG_SYM_LAOBJOPEN, /* MSG_ORIG(MSG_SYM_LAOBJOPEN) */ 817 LML_TFLG_AUD_OBJOPEN, 0 }, 818 { MSG_SYM_LAOBJFILTER, /* MSG_ORIG(MSG_SYM_LAOBJFILTER */ 819 LML_TFLG_AUD_OBJFILTER, 0 }, 820 { MSG_SYM_LAOBJCLOSE, /* MSG_ORIG(MSG_SYM_LAOBJCLOSE) */ 821 LML_TFLG_AUD_OBJCLOSE, 0 }, 822 { MSG_SYM_LAACTIVITY, /* MSG_ORIG(MSG_SYM_LAACTIVITY) */ 823 LML_TFLG_AUD_ACTIVITY, 0 }, 824 825 #if defined(_ELF64) 826 { MSG_SYM_LASYMBIND_64, /* MSG_ORIG(MSG_SYM_LASYMBIND_64) */ 827 #else 828 { MSG_SYM_LASYMBIND, /* MSG_ORIG(MSG_SYM_LASYMBIND) */ 829 #endif 830 LML_TFLG_AUD_SYMBIND, 0 }, 831 832 #if defined(__sparcv9) 833 { MSG_SYM_LAV9PLTENTER, /* MSG_ORIG(MSG_SYM_LAV9PLTENTER) */ 834 #elif defined(__sparc) 835 { MSG_SYM_LAV8PLTENTER, /* MSG_ORIG(MSG_SYM_LAV8PLTENTER) */ 836 #elif defined(__amd64) 837 { MSG_SYM_LAAMD64PLTENTER, /* MSG_ORIG(MSG_SYM_LAAMD64PLTENTER) */ 838 #elif defined(__i386) 839 { MSG_SYM_LAX86PLTENTER, /* MSG_ORIG(MSG_SYM_LAX86PLTENTER) */ 840 #else 841 #error platform not defined! 842 #endif 843 LML_TFLG_AUD_PLTENTER, AF_PLTENTER }, 844 845 #if defined(_ELF64) 846 { MSG_SYM_LAPLTEXIT_64, /* MSG_ORIG(MSG_SYM_LAPLTEXIT_64) */ 847 #else 848 { MSG_SYM_LAPLTEXIT, /* MSG_ORIG(MSG_SYM_LAPLTEXIT) */ 849 #endif 850 LML_TFLG_AUD_PLTEXIT, AF_PLTEXIT } 851 }; 852 853 #define AI_LAVERSION 0 854 #define AI_LAPREINIT 1 855 #define AI_LAOBJSEARCH 2 856 #define AI_LAOBJOPEN 3 857 #define AI_LAOBJFILTER 4 858 #define AI_LAOBJCLOSE 5 859 #define AI_LAACTIVITY 6 860 #define AI_LASYMBIND 7 861 #define AI_LAPLTENTER 8 862 #define AI_LAPLTEXIT 9 863 864 static Addr 865 audit_symget(Audit_list *alp, int info, int *in_nfavl) 866 { 867 Rt_map *_lmp, *lmp = alp->al_lmp; 868 const char *sname = MSG_ORIG(aud_info[info].sname); 869 uint_t alflag = aud_info[info].alflag; 870 uint_t auflag = aud_info[info].auflag; 871 uint_t binfo; 872 Sym *sym; 873 Slookup sl; 874 875 /* 876 * Initialize the symbol lookup data structure. 877 */ 878 SLOOKUP_INIT(sl, sname, lml_rtld.lm_head, lmp, ld_entry_cnt, 879 0, 0, 0, 0, LKUP_FIRST); 880 881 if (sym = LM_LOOKUP_SYM(lmp)(&sl, &_lmp, &binfo, in_nfavl)) { 882 Addr addr = sym->st_value; 883 884 if (!(FLAGS(lmp) & FLG_RT_FIXED)) 885 addr += ADDR(lmp); 886 887 if (alflag) 888 alp->al_flags |= alflag; 889 if (auflag) 890 audit_flags |= auflag; 891 892 DBG_CALL(Dbg_audit_interface(LIST(alp->al_lmp), 893 alp->al_libname, sname)); 894 return (addr); 895 } else 896 return (0); 897 } 898 899 /* 900 * Centralize cleanup routines. 901 */ 902 static int 903 audit_disable(char *name, Rt_map *clmp, Grp_hdl *ghp, Audit_list *alp) 904 { 905 eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_AUD_DISABLED), name); 906 if (ghp) 907 (void) dlclose_intn(ghp, clmp); 908 if (alp) 909 free(alp); 910 911 return (0); 912 } 913 914 /* 915 * Given a list of one or more audit libraries, open each one and establish a 916 * a descriptor representing the entry points it provides. 917 */ 918 int 919 audit_setup(Rt_map *clmp, Audit_desc *adp, uint_t orig, int *in_nfavl) 920 { 921 char *ptr, *next; 922 Lm_list *clml = LIST(clmp); 923 int error = 1; 924 925 DBG_CALL(Dbg_audit_lib(clml, adp->ad_name)); 926 927 /* 928 * Mark that we have at least one auditing link map 929 */ 930 rtld_flags2 |= RT_FL2_HASAUDIT; 931 932 /* 933 * The audit definitions may be a list (which will already have been 934 * dupped) so split it into individual tokens. 935 */ 936 for (ptr = strtok_r(adp->ad_name, MSG_ORIG(MSG_STR_DELIMIT), &next); 937 ptr; ptr = strtok_r(NULL, MSG_ORIG(MSG_STR_DELIMIT), &next)) { 938 Grp_hdl *ghp; 939 Rt_map *lmp; 940 Rt_map **tobj; 941 Audit_list *alp; 942 943 /* 944 * Open the audit library on its own link-map. 945 */ 946 if ((ghp = dlmopen_intn((Lm_list *)LM_ID_NEWLM, ptr, 947 (RTLD_FIRST | RTLD_GLOBAL | RTLD_WORLD), clmp, 948 FLG_RT_AUDIT, orig)) == 0) { 949 error = audit_disable(ptr, clmp, 0, 0); 950 continue; 951 } 952 lmp = ghp->gh_ownlmp; 953 954 /* 955 * If this auditor has already been loaded, reuse it. 956 */ 957 if ((alp = LIST(lmp)->lm_alp) != 0) { 958 if (list_append(&(adp->ad_list), alp) == 0) 959 return (audit_disable(ptr, clmp, ghp, alp)); 960 961 adp->ad_cnt++; 962 DBG_CALL(Dbg_audit_version(clml, alp->al_libname, 963 alp->al_vernum)); 964 adp->ad_flags |= alp->al_flags; 965 continue; 966 } 967 968 /* 969 * If we are not running in the environment where 970 * libc/libthread are merged, we hold on to rtld lock 971 * upon leave() function. 972 * 973 * There is a possibility that libc is not mapped in yet. 974 * We may later find out that we will be running in 975 * libc/libthread merged enviornment. Refer to: 976 * get_lcinterface() in mutex.c. 977 */ 978 if ((rtld_flags2 & RT_FL2_UNIFPROC) == 0) 979 LIST(lmp)->lm_flags |= LML_FLG_HOLDLOCK; 980 981 /* 982 * Allocate an audit list descriptor for this object and 983 * search for all known entry points. 984 */ 985 if ((alp = calloc(1, sizeof (Audit_list))) == 0) 986 return (audit_disable(ptr, clmp, ghp, 0)); 987 988 alp->al_libname = NAME(lmp); 989 alp->al_lmp = lmp; 990 alp->al_ghp = ghp; 991 992 /* 993 * All audit libraries must handshake through la_version(). 994 * Determine that the symbol exists, finish initializing the 995 * object, and then call the function. 996 */ 997 if ((alp->al_version = (uint_t(*)())audit_symget(alp, 998 AI_LAVERSION, in_nfavl)) == 0) { 999 eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_GEN_NOSYM), 1000 MSG_ORIG(MSG_SYM_LAVERSION)); 1001 error = audit_disable(ptr, clmp, ghp, alp); 1002 continue; 1003 } 1004 1005 if ((tobj = tsort(lmp, LIST(lmp)->lm_init, RT_SORT_REV)) == 1006 (Rt_map **)S_ERROR) 1007 return (audit_disable(ptr, clmp, ghp, alp)); 1008 1009 rtld_flags |= RT_FL_APPLIC; 1010 if (tobj != (Rt_map **)NULL) 1011 call_init(tobj, DBG_INIT_SORT); 1012 1013 alp->al_vernum = alp->al_version(LAV_CURRENT); 1014 rtld_flags &= ~RT_FL_APPLIC; 1015 1016 if ((alp->al_vernum < LAV_VERSION1) || 1017 (alp->al_vernum > LAV_CURRENT)) { 1018 eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_AUD_BADVERS), 1019 LAV_CURRENT, alp->al_vernum); 1020 error = audit_disable(ptr, clmp, ghp, alp); 1021 continue; 1022 } 1023 1024 if (list_append(&(adp->ad_list), alp) == 0) 1025 return (audit_disable(ptr, clmp, ghp, alp)); 1026 1027 adp->ad_cnt++; 1028 DBG_CALL(Dbg_audit_version(clml, alp->al_libname, 1029 alp->al_vernum)); 1030 1031 /* 1032 * Collect any remaining entry points. 1033 */ 1034 alp->al_preinit = (void(*)())audit_symget(alp, 1035 AI_LAPREINIT, in_nfavl); 1036 alp->al_objsearch = (char *(*)())audit_symget(alp, 1037 AI_LAOBJSEARCH, in_nfavl); 1038 alp->al_objopen = (uint_t(*)())audit_symget(alp, 1039 AI_LAOBJOPEN, in_nfavl); 1040 alp->al_objfilter = (int(*)())audit_symget(alp, 1041 AI_LAOBJFILTER, in_nfavl); 1042 alp->al_objclose = (uint_t(*)())audit_symget(alp, 1043 AI_LAOBJCLOSE, in_nfavl); 1044 alp->al_activity = (void (*)())audit_symget(alp, 1045 AI_LAACTIVITY, in_nfavl); 1046 alp->al_symbind = (uintptr_t(*)())audit_symget(alp, 1047 AI_LASYMBIND, in_nfavl); 1048 alp->al_pltenter = (uintptr_t(*)())audit_symget(alp, 1049 AI_LAPLTENTER, in_nfavl); 1050 alp->al_pltexit = (uintptr_t(*)())audit_symget(alp, 1051 AI_LAPLTEXIT, in_nfavl); 1052 1053 /* 1054 * Collect the individual object flags, and assign this audit 1055 * list descriptor to its associated link-map list. 1056 */ 1057 adp->ad_flags |= alp->al_flags; 1058 LIST(lmp)->lm_alp = alp; 1059 } 1060 1061 /* 1062 * Free the original audit string, as this descriptor may be used again 1063 * to add additional auditing. 1064 */ 1065 free(adp->ad_name); 1066 adp->ad_name = 0; 1067 1068 return (error); 1069 } 1070