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 2007 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)); 105 if ((*alp->al_objfilter)(&(fracp->ac_cookie), ref, 106 &(feacp->ac_cookie), flags) == 0) 107 return (0); 108 (void) enter(); 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)); 159 nname = (*alp->al_objsearch)(nname, &(acp->ac_cookie), flags); 160 (void) enter(); 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 (alist_append(&(clml->lm_actaudit), &clmp, 226 sizeof (Rt_map *), AL_CNT_ACTAUDIT) == 0) 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)); 239 (*alp->al_activity)(&(acp->ac_cookie), flags); 240 (void) enter(); 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)); 295 flags = (*alp->al_objopen)((Link_map *)nlmp, lmid, 296 &(acp->ac_cookie)); 297 (void) enter(); 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)); 407 (*alp->al_objclose)(&(acp->ac_cookie)); 408 (void) enter(); 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)); 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(); 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(); 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)); 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)); 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(); 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(); 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)); 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)); 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(); 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)); 716 (*alp->al_preinit)(&(acp->ac_cookie)); 717 (void) enter(); 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 Alist *ghalp = 0; 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) alist_append(&ghalp, &(alp->al_ghp), sizeof (Grp_hdl *), 762 AL_CNT_GROUPS); 763 764 if (olnp) 765 free(olnp); 766 olnp = lnp; 767 } 768 if (olnp) 769 free(olnp); 770 771 free(adp); 772 AUDITORS(clmp) = 0; 773 774 if (ghalp) { 775 Grp_hdl ** ghpp; 776 Aliste off; 777 778 for (ALIST_TRAVERSE(ghalp, off, ghpp)) { 779 (void) dlclose_intn(*ghpp, clmp); 780 } 781 free(ghalp); 782 } 783 } 784 785 /* 786 * Clean up (free) an audit information structure. 787 */ 788 void 789 audit_info_cleanup(Rt_map *clmp) 790 { 791 Audit_info *aip = AUDINFO(clmp); 792 793 if (aip == 0) 794 return; 795 796 if (aip->ai_dynplts) 797 free(aip->ai_dynplts); 798 free(aip); 799 } 800 801 /* 802 * Create a data structure of symbol lookup names and associated flags to help 803 * simplify audit_symget() use. 804 */ 805 typedef struct { 806 Msg sname; 807 uint_t alflag; 808 uint_t auflag; 809 } Aud_info; 810 811 static const Aud_info aud_info[] = { 812 { MSG_SYM_LAVERSION, 0 }, /* MSG_ORIG(MSG_SYM_LAVERSION) */ 813 { MSG_SYM_LAPREINIT, /* MSG_ORIG(MSG_SYM_LAPREINIT) */ 814 LML_TFLG_AUD_PREINIT, 0 }, 815 { MSG_SYM_LAOBJSEARCH, /* MSG_ORIG(MSG_SYM_LAOBJSEARCH) */ 816 LML_TFLG_AUD_OBJSEARCH, 0 }, 817 { MSG_SYM_LAOBJOPEN, /* MSG_ORIG(MSG_SYM_LAOBJOPEN) */ 818 LML_TFLG_AUD_OBJOPEN, 0 }, 819 { MSG_SYM_LAOBJFILTER, /* MSG_ORIG(MSG_SYM_LAOBJFILTER */ 820 LML_TFLG_AUD_OBJFILTER, 0 }, 821 { MSG_SYM_LAOBJCLOSE, /* MSG_ORIG(MSG_SYM_LAOBJCLOSE) */ 822 LML_TFLG_AUD_OBJCLOSE, 0 }, 823 { MSG_SYM_LAACTIVITY, /* MSG_ORIG(MSG_SYM_LAACTIVITY) */ 824 LML_TFLG_AUD_ACTIVITY, 0 }, 825 826 #if defined(_ELF64) 827 { MSG_SYM_LASYMBIND_64, /* MSG_ORIG(MSG_SYM_LASYMBIND_64) */ 828 #else 829 { MSG_SYM_LASYMBIND, /* MSG_ORIG(MSG_SYM_LASYMBIND) */ 830 #endif 831 LML_TFLG_AUD_SYMBIND, 0 }, 832 833 #if defined(__sparcv9) 834 { MSG_SYM_LAV9PLTENTER, /* MSG_ORIG(MSG_SYM_LAV9PLTENTER) */ 835 #elif defined(__sparc) 836 { MSG_SYM_LAV8PLTENTER, /* MSG_ORIG(MSG_SYM_LAV8PLTENTER) */ 837 #elif defined(__amd64) 838 { MSG_SYM_LAAMD64PLTENTER, /* MSG_ORIG(MSG_SYM_LAAMD64PLTENTER) */ 839 #elif defined(__i386) 840 { MSG_SYM_LAX86PLTENTER, /* MSG_ORIG(MSG_SYM_LAX86PLTENTER) */ 841 #else 842 #error platform not defined! 843 #endif 844 LML_TFLG_AUD_PLTENTER, AF_PLTENTER }, 845 846 #if defined(_ELF64) 847 { MSG_SYM_LAPLTEXIT_64, /* MSG_ORIG(MSG_SYM_LAPLTEXIT_64) */ 848 #else 849 { MSG_SYM_LAPLTEXIT, /* MSG_ORIG(MSG_SYM_LAPLTEXIT) */ 850 #endif 851 LML_TFLG_AUD_PLTEXIT, AF_PLTEXIT } 852 }; 853 854 #define AI_LAVERSION 0 855 #define AI_LAPREINIT 1 856 #define AI_LAOBJSEARCH 2 857 #define AI_LAOBJOPEN 3 858 #define AI_LAOBJFILTER 4 859 #define AI_LAOBJCLOSE 5 860 #define AI_LAACTIVITY 6 861 #define AI_LASYMBIND 7 862 #define AI_LAPLTENTER 8 863 #define AI_LAPLTEXIT 9 864 865 static Addr 866 audit_symget(Audit_list * alp, int info) 867 { 868 Rt_map *_lmp, *lmp = alp->al_lmp; 869 const char *sname = MSG_ORIG(aud_info[info].sname); 870 uint_t alflag = aud_info[info].alflag; 871 uint_t auflag = aud_info[info].auflag; 872 uint_t binfo; 873 Sym *sym; 874 Slookup sl; 875 876 sl.sl_name = sname; 877 sl.sl_cmap = lml_rtld.lm_head; 878 sl.sl_imap = lmp; 879 sl.sl_hash = 0; 880 sl.sl_rsymndx = 0; 881 sl.sl_flags = LKUP_FIRST; 882 883 if (sym = LM_LOOKUP_SYM(lmp)(&sl, &_lmp, &binfo)) { 884 Addr addr = sym->st_value; 885 886 if (!(FLAGS(lmp) & FLG_RT_FIXED)) 887 addr += ADDR(lmp); 888 889 if (alflag) 890 alp->al_flags |= alflag; 891 if (auflag) 892 audit_flags |= auflag; 893 894 DBG_CALL(Dbg_audit_interface(LIST(alp->al_lmp), 895 alp->al_libname, sname)); 896 return (addr); 897 } else 898 return (0); 899 } 900 901 /* 902 * Centralize cleanup routines. 903 */ 904 static int 905 audit_disable(char *name, Rt_map *clmp, Grp_hdl *ghp, Audit_list *alp) 906 { 907 eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_AUD_DISABLED), name); 908 if (ghp) 909 (void) dlclose_intn(ghp, clmp); 910 if (alp) 911 free(alp); 912 913 return (0); 914 } 915 916 /* 917 * Given a list of one or more audit libraries, open each one and establish a 918 * a descriptor representing the entry points it provides. 919 */ 920 int 921 audit_setup(Rt_map *clmp, Audit_desc *adp, uint_t orig) 922 { 923 char *ptr, *next; 924 Lm_list *clml = LIST(clmp); 925 int error = 1; 926 927 DBG_CALL(Dbg_audit_lib(clml, adp->ad_name)); 928 929 /* 930 * Mark that we have at least one auditing link map 931 */ 932 rtld_flags2 |= RT_FL2_HASAUDIT; 933 934 /* 935 * The audit definitions may be a list (which will already have been 936 * dupped) so split it into individual tokens. 937 */ 938 for (ptr = strtok_r(adp->ad_name, MSG_ORIG(MSG_STR_DELIMIT), &next); 939 ptr; ptr = strtok_r(NULL, MSG_ORIG(MSG_STR_DELIMIT), &next)) { 940 Grp_hdl *ghp; 941 Rt_map *lmp; 942 Rt_map **tobj; 943 Audit_list *alp; 944 945 /* 946 * Open the audit library on its own link-map. 947 */ 948 if ((ghp = dlmopen_intn((Lm_list *)LM_ID_NEWLM, ptr, 949 (RTLD_FIRST | RTLD_GLOBAL | RTLD_WORLD), clmp, 950 FLG_RT_AUDIT, orig, 0)) == 0) { 951 error = audit_disable(ptr, clmp, 0, 0); 952 continue; 953 } 954 lmp = ghp->gh_ownlmp; 955 956 /* 957 * If this auditor has already been loaded, reuse it. 958 */ 959 if ((alp = LIST(lmp)->lm_alp) != 0) { 960 if (list_append(&(adp->ad_list), alp) == 0) 961 return (audit_disable(ptr, clmp, ghp, alp)); 962 963 adp->ad_cnt++; 964 DBG_CALL(Dbg_audit_version(clml, alp->al_libname, 965 alp->al_vernum)); 966 adp->ad_flags |= alp->al_flags; 967 continue; 968 } 969 970 /* 971 * If we are not running in the environment where 972 * libc/libthread are merged, we hold on to rtld lock 973 * upon leave() function. 974 * 975 * There is a possibility that libc is not mapped in yet. 976 * We may later find out that we will be running in 977 * libc/libthread merged enviornment. Refer to: 978 * get_lcinterface() in mutex.c. 979 */ 980 if ((rtld_flags2 & RT_FL2_UNIFPROC) == 0) 981 LIST(lmp)->lm_flags |= LML_FLG_HOLDLOCK; 982 983 /* 984 * Allocate an audit list descriptor for this object and 985 * search for all known entry points. 986 */ 987 if ((alp = calloc(1, sizeof (Audit_list))) == 0) 988 return (audit_disable(ptr, clmp, ghp, 0)); 989 990 alp->al_libname = NAME(lmp); 991 alp->al_lmp = lmp; 992 alp->al_ghp = ghp; 993 994 /* 995 * All audit libraries must handshake through la_version(). 996 * Determine that the symbol exists, finish initializing the 997 * object, and then call the function. 998 */ 999 if ((alp->al_version = 1000 (uint_t(*)())audit_symget(alp, AI_LAVERSION)) == 0) { 1001 eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_GEN_NOSYM), 1002 MSG_ORIG(MSG_SYM_LAVERSION)); 1003 error = audit_disable(ptr, clmp, ghp, alp); 1004 continue; 1005 } 1006 1007 if ((tobj = tsort(lmp, LIST(lmp)->lm_init, RT_SORT_REV)) == 1008 (Rt_map **)S_ERROR) 1009 return (audit_disable(ptr, clmp, ghp, alp)); 1010 1011 rtld_flags |= RT_FL_APPLIC; 1012 if (tobj != (Rt_map **)NULL) 1013 call_init(tobj, DBG_INIT_SORT); 1014 1015 alp->al_vernum = alp->al_version(LAV_CURRENT); 1016 rtld_flags &= ~RT_FL_APPLIC; 1017 1018 if ((alp->al_vernum < LAV_VERSION1) || 1019 (alp->al_vernum > LAV_CURRENT)) { 1020 eprintf(LIST(lmp), ERR_FATAL, MSG_INTL(MSG_AUD_BADVERS), 1021 LAV_CURRENT, alp->al_vernum); 1022 error = audit_disable(ptr, clmp, ghp, alp); 1023 continue; 1024 } 1025 1026 if (list_append(&(adp->ad_list), alp) == 0) 1027 return (audit_disable(ptr, clmp, ghp, alp)); 1028 1029 adp->ad_cnt++; 1030 DBG_CALL(Dbg_audit_version(clml, alp->al_libname, 1031 alp->al_vernum)); 1032 1033 /* 1034 * Collect any remaining entry points. 1035 */ 1036 alp->al_preinit = 1037 (void(*)())audit_symget(alp, AI_LAPREINIT); 1038 alp->al_objsearch = 1039 (char *(*)())audit_symget(alp, AI_LAOBJSEARCH); 1040 alp->al_objopen = 1041 (uint_t(*)())audit_symget(alp, AI_LAOBJOPEN); 1042 alp->al_objfilter = 1043 (int(*)())audit_symget(alp, AI_LAOBJFILTER); 1044 alp->al_objclose = 1045 (uint_t(*)())audit_symget(alp, AI_LAOBJCLOSE); 1046 alp->al_activity = 1047 (void (*)())audit_symget(alp, AI_LAACTIVITY); 1048 alp->al_symbind = 1049 (uintptr_t(*)())audit_symget(alp, AI_LASYMBIND); 1050 alp->al_pltenter = 1051 (uintptr_t(*)())audit_symget(alp, AI_LAPLTENTER); 1052 alp->al_pltexit = 1053 (uintptr_t(*)())audit_symget(alp, AI_LAPLTEXIT); 1054 1055 /* 1056 * Collect the individual object flags, and assign this audit 1057 * list descriptor to its associated link-map list. 1058 */ 1059 adp->ad_flags |= alp->al_flags; 1060 LIST(lmp)->lm_alp = alp; 1061 } 1062 1063 /* 1064 * Free the original audit string, as this descriptor may be used again 1065 * to add additional auditing. 1066 */ 1067 free(adp->ad_name); 1068 adp->ad_name = 0; 1069 1070 return (error); 1071 } 1072