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