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 (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Remove objects. Objects need removal from a process as part of:
28 *
29 * - a dlclose() request
30 *
31 * - tearing down a dlopen(), lazy-load, or filter hierarchy that failed to
32 * completely load
33 *
34 * Any other failure condition will result in process exit (in which case all
35 * we have to do is execute the fini's - tear down is unnecessary).
36 *
37 * Any removal of objects is therefore associated with a dlopen() handle. There
38 * is a small window between creation of the first dlopen() object and creating
39 * its handle (in which case remove_so() can get rid of the new link-map if
40 * necessary), but other than this all object removal is driven by inspecting
41 * the components of a handle.
42 *
43 * Things to note. The creation of a link-map, and its addition to the link-map
44 * list occurs in {elf|aout}_new_lm(), if this returns success the link-map is
45 * valid and added, otherwise any steps (allocations) in the process of creating
46 * the link-map would have been undone. If a failure occurs between creating
47 * the link-map and adding it to a handle, remove_so() is called to remove the
48 * link-map. If a failures occurs after a handle have been created,
49 * remove_hdl() is called to remove the handle and the link-map.
50 */
51
52 #include <string.h>
53 #include <stdio.h>
54 #include <unistd.h>
55 #include <dlfcn.h>
56 #include <sys/debug.h>
57 #include <sys/avl.h>
58 #include <libc_int.h>
59 #include <debug.h>
60 #include "_rtld.h"
61 #include "_audit.h"
62 #include "_elf.h"
63 #include "msg.h"
64
65 /*
66 * Atexit callback provided by libc. As part of dlclose() determine the address
67 * ranges of all objects that are to be deleted. Pass this information to
68 * libc's pre-atexit routine. Libc will purge any registered atexit() calls
69 * related to those objects about to be deleted.
70 */
71 static int
purge_exit_handlers(Lm_list * lml,Rt_map ** tobj)72 purge_exit_handlers(Lm_list *lml, Rt_map **tobj)
73 {
74 uint_t num;
75 Rt_map **_tobj;
76 Lc_addr_range_t *addr, *_addr;
77 int error;
78 int (*fptr)(Lc_addr_range_t *, uint_t);
79
80 /*
81 * Has a callback been established?
82 */
83 if ((fptr = lml->lm_lcs[CI_ATEXIT].lc_un.lc_func) == NULL)
84 return (0);
85
86 /*
87 * Determine the total number of mapped segments that will be unloaded.
88 */
89 for (num = 0, _tobj = tobj; *_tobj != NULL; _tobj++) {
90 Rt_map *lmp = *_tobj;
91
92 num += MMAPCNT(lmp);
93 }
94
95 /*
96 * Account for a null entry at the end of the address range array.
97 */
98 if (num++ == 0)
99 return (0);
100
101 /*
102 * Allocate an array for the address range.
103 */
104 if ((addr = malloc(num * sizeof (Lc_addr_range_t))) == NULL)
105 return (1);
106
107 /*
108 * Fill the address range with each loadable segments size and address.
109 */
110 for (_tobj = tobj, _addr = addr; *_tobj != NULL; _tobj++) {
111 Rt_map *lmp = *_tobj;
112 mmapobj_result_t *mpp = MMAPS(lmp);
113 uint_t ndx;
114
115 for (ndx = 0; ndx < MMAPCNT(lmp); ndx++, mpp++) {
116 _addr->lb = (void *)(uintptr_t)(mpp->mr_addr +
117 mpp->mr_offset);
118 _addr->ub = (void *)(uintptr_t)(mpp->mr_addr +
119 mpp->mr_msize);
120 _addr++;
121 }
122 }
123 _addr->lb = _addr->ub = 0;
124
125 leave(LIST(*tobj), 0);
126 error = (*fptr)(addr, (num - 1));
127 (void) enter(0);
128
129 /*
130 * If we fail to converse with libc, generate an error message to
131 * satisfy any dlerror() usage.
132 */
133 if (error)
134 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ATEXIT), error);
135
136 free(addr);
137 return (error);
138 }
139
140 /*
141 * Break down an Alist containing pathname descriptors. In most instances, the
142 * Alist is removed completely. However, in some instances the alist is cleaned
143 * of all entries, but retained for later use.
144 */
145 void
remove_alist(Alist ** alpp,int complete)146 remove_alist(Alist **alpp, int complete)
147 {
148 Alist *alp = *alpp;
149
150 if (alp) {
151 if (complete) {
152 free((void *)alp);
153 *alpp = NULL;
154 } else {
155 alist_reset(alp);
156 }
157 }
158 }
159
160 /*
161 * Remove a link-map list descriptor. This is called to finalize the removal
162 * of an entire link-map list, after all link-maps have been removed, or none
163 * got added. As load_one() can process a list of potential candidate objects,
164 * the link-map descriptor must be maintained as each object is processed. Only
165 * after all objects have been processed can a failure condition finally tear
166 * down the link-map list descriptor.
167 */
168 void
remove_lml(Lm_list * lml)169 remove_lml(Lm_list *lml)
170 {
171 if (lml && (lml->lm_head == NULL)) {
172 if (lml->lm_lmidstr)
173 free(lml->lm_lmidstr);
174 if (lml->lm_alp)
175 free(lml->lm_alp);
176 if (lml->lm_lists)
177 free(lml->lm_lists);
178 if (lml->lm_aud_cookies)
179 free(lml->lm_aud_cookies);
180
181 /*
182 * Cleanup any pending RTLDINFO in the case where it was
183 * allocated but not called (see _relocate_lmc()).
184 */
185 if (lml->lm_rti)
186 free(lml->lm_rti);
187 if (lml->lm_fpavl) {
188 /*
189 * As we are freeing the link-map list, all nodes must
190 * have previously been removed.
191 */
192 ASSERT(avl_numnodes(lml->lm_fpavl) == 0);
193 free(lml->lm_fpavl);
194 }
195 (void) aplist_delete_value(dynlm_list, lml);
196 free(lml);
197 }
198 }
199
200 /*
201 * Remove a link-map. This removes a link-map from its associated list and
202 * free's up the link-map itself. Note, all components that are freed are local
203 * to the link-map, no inter-link-map lists are operated on as these are all
204 * broken down by dlclose() while all objects are still mapped.
205 *
206 * This routine is called from dlclose() to zap individual link-maps after their
207 * interdependencies (DEPENDS(), CALLER(), handles, etc.) have been removed.
208 * This routine is also called from the bowels of load_one() in the case of a
209 * link-map creation failure.
210 */
211 void
remove_so(Lm_list * lml,Rt_map * lmp,Rt_map * clmp)212 remove_so(Lm_list *lml, Rt_map *lmp, Rt_map *clmp)
213 {
214 Dyninfo *dip;
215
216 if (lmp == NULL)
217 return;
218
219 /*
220 * Unlink the link map from the link-map list.
221 */
222 if (lml && lmp)
223 lm_delete(lml, lmp, clmp);
224
225 /*
226 * If this object contributed any local external vectors for the current
227 * link-map list, remove the vectors. If this object contributed any
228 * global external vectors we should find some new candidates, or leave
229 * this object lying around.
230 */
231 if (lml) {
232 int tag;
233
234 for (tag = 0; tag < CI_MAX; tag++) {
235 if (lml->lm_lcs[tag].lc_lmp == lmp) {
236 lml->lm_lcs[tag].lc_lmp = NULL;
237 lml->lm_lcs[tag].lc_un.lc_val = 0;
238 }
239 if (glcs[tag].lc_lmp == lmp) {
240 ASSERT(glcs[tag].lc_lmp != NULL);
241 glcs[tag].lc_lmp = NULL;
242 glcs[tag].lc_un.lc_val = 0;
243 }
244 }
245 }
246
247 DBG_CALL(Dbg_file_delete(lmp));
248
249 /*
250 * If this object is an auditor, determine whether any link-map lists
251 * are maintaining cookies to represent this auditor. These cookies
252 * are established for local auditing preinit and activity events.
253 */
254 if (FLAGS(lmp) & FLG_RT_AUDIT) {
255 Lm_list *nlml;
256 Aliste idx1;
257
258 for (APLIST_TRAVERSE(dynlm_list, idx1, nlml)) {
259 Rt_map *hlmp = nlml->lm_head;
260 Audit_client *acp;
261 Aliste idx2;
262
263 if ((hlmp == NULL) || (FLAGS(hlmp) & FLG_RT_AUDIT))
264 continue;
265
266 for (ALIST_TRAVERSE(nlml->lm_aud_cookies, idx2, acp)) {
267 if (acp->ac_lmp != lmp) {
268 alist_delete(nlml->lm_aud_cookies,
269 &idx2);
270 break;
271 }
272 }
273 }
274 }
275
276 /*
277 * If this is a temporary link-map, put in place to facilitate the
278 * link-edit or a relocatable object, then the link-map contains no
279 * information that needs to be cleaned up.
280 */
281 if (FLAGS(lmp) & FLG_RT_OBJECT)
282 return;
283
284 /*
285 * Remove any FullpathNode AVL names if they still exist.
286 */
287 if (FPNODE(lmp))
288 fpavl_remove(lmp);
289
290 /*
291 * Remove any alias names.
292 */
293 if (ALIAS(lmp))
294 free(ALIAS(lmp));
295
296 /*
297 * Remove any of this objects filtee infrastructure. The filtees them-
298 * selves have already been removed.
299 */
300 if (((dip = DYNINFO(lmp)) != NULL) && (FLAGS1(lmp) & MSK_RT_FILTER)) {
301 uint_t cnt, max = DYNINFOCNT(lmp);
302
303 for (cnt = 0; cnt < max; cnt++, dip++) {
304 if ((dip->di_info == NULL) ||
305 ((dip->di_flags & MSK_DI_FILTER) == 0))
306 continue;
307
308 remove_alist((Alist **)&(dip->di_info), 1);
309 }
310 }
311
312 /*
313 * Deallocate any remaining cruft and free the link-map.
314 */
315 if (RLIST(lmp))
316 remove_alist(&RLIST(lmp), 1);
317
318 if (AUDITORS(lmp))
319 audit_desc_cleanup(lmp);
320 if (AUDINFO(lmp))
321 audit_info_cleanup(lmp);
322
323 /*
324 * Note that COPY_R() and COPY_S() reference the same memory
325 * location, and that we want to release the memory referenced
326 * without regard to which list it logically belongs to. We can
327 * use either pointer to do this.
328 */
329 if (COPY_R(lmp))
330 free(COPY_R(lmp));
331
332 /*
333 * During a dlclose() any groups this object was a part of will have
334 * been torn down. However, we can get here to remove an object that
335 * has failed to load, perhaps because its addition to a handle failed.
336 * Therefore if this object indicates that its part of a group tear
337 * these associations down.
338 */
339 if (GROUPS(lmp) != NULL) {
340 Aliste idx1;
341 Grp_hdl *ghp;
342
343 for (APLIST_TRAVERSE(GROUPS(lmp), idx1, ghp)) {
344 Grp_desc *gdp;
345 Aliste idx2;
346
347 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
348 if (gdp->gd_depend != lmp)
349 continue;
350
351 alist_delete(ghp->gh_depends, &idx2);
352 break;
353 }
354 }
355 free(GROUPS(lmp));
356 }
357 if (HANDLES(lmp))
358 free(HANDLES(lmp));
359
360 /*
361 * Clean up reglist if needed
362 */
363 if (reglist) {
364 Reglist *cur, *prv, *del;
365
366 cur = prv = reglist;
367 while (cur) {
368 if (cur->rl_lmp == lmp) {
369 del = cur;
370 if (cur == reglist) {
371 reglist = cur->rl_next;
372 cur = prv = reglist;
373 } else {
374 prv->rl_next = cur->rl_next;
375 cur = cur->rl_next;
376 }
377 free(del);
378 } else {
379 prv = cur;
380 cur = cur->rl_next;
381 }
382 }
383 }
384
385 /*
386 * If this link map represents a relocatable object concatenation, then
387 * the image was simply generated in allocated memory. Free the memory.
388 * Note: memory maps were fabricated for the relocatable object, and
389 * the mapping infrastructure must be free'd, but there are no address
390 * mappings that must be unmapped.
391 *
392 * Otherwise, unmap the object.
393 */
394 if (FLAGS(lmp) & FLG_RT_IMGALLOC)
395 free((void *)ADDR(lmp));
396
397 if (CAPCHAIN(lmp))
398 free((void *)CAPCHAIN(lmp));
399
400 if (MMAPS(lmp)) {
401 if ((FLAGS(lmp) & FLG_RT_IMGALLOC) == 0)
402 unmap_obj(MMAPS(lmp), MMAPCNT(lmp));
403 free(MMAPS(lmp));
404 }
405
406 free(lmp);
407 }
408
409 /*
410 * Traverse an objects dependency list removing callers and dependencies.
411 * There's a chicken and egg problem with tearing down link-maps. Any
412 * relationship between link-maps is maintained on a DEPENDS list, and an
413 * associated CALLERS list. These lists can't be broken down at the time a
414 * single link-map is removed, as any related link-map may have already been
415 * removed. Thus, lists between link-maps must be broken down before the
416 * individual link-maps themselves.
417 */
418 static void
remove_lists(Rt_map * lmp,int lazy)419 remove_lists(Rt_map *lmp, int lazy)
420 {
421 Aliste idx1;
422 Bnd_desc *bdp;
423
424 /*
425 * First, traverse this objects dependencies.
426 */
427 for (APLIST_TRAVERSE(DEPENDS(lmp), idx1, bdp)) {
428 Rt_map *dlmp = bdp->b_depend;
429
430 /*
431 * Remove this object from the dependencies callers.
432 */
433 (void) aplist_delete_value(CALLERS(dlmp), bdp);
434 free(bdp);
435 }
436 if (DEPENDS(lmp)) {
437 free(DEPENDS(lmp));
438 DEPENDS(lmp) = NULL;
439 }
440
441 /*
442 * Second, traverse this objects callers.
443 */
444 for (APLIST_TRAVERSE(CALLERS(lmp), idx1, bdp)) {
445 Rt_map *clmp = bdp->b_caller;
446 Dyninfo *dip;
447
448 /*
449 * If we're removing an object that was triggered by a lazyload,
450 * remove the callers DYNINFO() entry and bump the lazy counts.
451 * This reinitialization of the lazy information allows a lazy
452 * object to be reloaded again later. Although we may be
453 * breaking down a group of lazyloaded objects because one has
454 * failed to relocate, it's possible that one or more of the
455 * individual objects can be reloaded without a problem.
456 */
457 if (lazy && ((dip = DYNINFO(clmp)) != NULL)) {
458 uint_t cnt, max = DYNINFOCNT(clmp);
459
460 for (cnt = 0; cnt < max; cnt++, dip++) {
461 if ((dip->di_flags & FLG_DI_LAZY) == 0)
462 continue;
463
464 if (dip->di_info == (void *)lmp) {
465 dip->di_info = NULL;
466
467 if (LAZY(clmp)++ == 0)
468 LIST(clmp)->lm_lazy++;
469 }
470 }
471 }
472
473 (void) aplist_delete_value(DEPENDS(clmp), bdp);
474 free(bdp);
475 }
476 if (CALLERS(lmp)) {
477 free(CALLERS(lmp));
478 CALLERS(lmp) = NULL;
479 }
480 }
481
482 /*
483 * Delete any temporary link-map control list.
484 */
485 void
remove_cntl(Lm_list * lml,Aliste lmco)486 remove_cntl(Lm_list *lml, Aliste lmco)
487 {
488 Aliste _lmco = lmco;
489 #if DEBUG
490 Lm_cntl *lmc;
491
492 lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco);
493
494 /*
495 * This element should be empty.
496 */
497 ASSERT(lmc->lc_head == NULL);
498 #endif
499 alist_delete_by_offset(lml->lm_lists, &_lmco);
500 }
501
502 /*
503 * If a lazy loaded object, or filtee fails to load, possibly because it, or
504 * one of its dependencies can't be relocated, then tear down any objects
505 * that are apart of this link-map control list.
506 */
507 static void
remove_incomplete(Lm_list * lml,Aliste lmco,Rt_map * clmp)508 remove_incomplete(Lm_list *lml, Aliste lmco, Rt_map *clmp)
509 {
510 Rt_map *lmp;
511 Lm_cntl *lmc;
512
513 /* LINTED */
514 lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco);
515
516 /*
517 * If auditing is in effect, the loading of these objects might have
518 * resulted in la_objopen() events being posted. Normally, an
519 * la_objclose() event is posted after an object's .fini is executed,
520 * just before the objects are unloaded. These failed objects do not
521 * have their .fini's executed, but an la_objclose() event should still
522 * be posted to any auditors.
523 */
524 if ((lml->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_OBJCLOSE) {
525 for (lmp = lmc->lc_head; lmp; lmp = NEXT_RT_MAP(lmp))
526 audit_objclose(lmp, clmp);
527 }
528
529 /*
530 * Remove any lists that may point between objects.
531 */
532 for (lmp = lmc->lc_head; lmp; lmp = NEXT_RT_MAP(lmp))
533 remove_lists(lmp, 1);
534
535 /*
536 * Finally, remove each object. remove_so() calls lm_delete(), thus
537 * effectively the link-map control head gets updated to point to the
538 * next link-map.
539 */
540 while ((lmp = lmc->lc_head) != NULL)
541 remove_so(lml, lmp, clmp);
542
543 lmc->lc_head = lmc->lc_tail = NULL;
544 }
545
546 /*
547 * Determine whether an object is deletable.
548 */
549 static int
is_deletable(APlist ** lmalp,APlist ** ghalp,Rt_map * lmp)550 is_deletable(APlist **lmalp, APlist **ghalp, Rt_map *lmp)
551 {
552 Aliste idx;
553 Bnd_desc *bdp;
554 Grp_hdl *ghp;
555
556 /*
557 * If the object hasn't yet been relocated take this as a sign that
558 * it's loading failed, thus we're here to cleanup. If the object is
559 * relocated it will only be retained if it was marked non-deletable,
560 * and exists on the main link-map control list.
561 */
562 if ((FLAGS(lmp) & FLG_RT_RELOCED) &&
563 (MODE(lmp) & RTLD_NODELETE) && (CNTL(lmp) == ALIST_OFF_DATA))
564 return (0);
565
566 /*
567 * If this object is the head of a handle that has not been captured as
568 * a candidate for deletion, then this object is in use from a dlopen()
569 * outside of the scope of this dlclose() family. Dlopen'ed objects,
570 * and filtees, have group descriptors for their callers. Typically
571 * this parent will have callers that are not apart of this dlclose()
572 * family, and thus would be caught by the CALLERS test below. However,
573 * if the caller had itself been dlopen'ed, it may not have any explicit
574 * callers registered for itself. Thus, by looking for objects with
575 * handles we can ferret out these outsiders.
576 */
577 for (APLIST_TRAVERSE(HANDLES(lmp), idx, ghp)) {
578 /*
579 * If this is a private handle, then the handle isn't referenced
580 * from outside of the group of objects being deleted, and can
581 * be ignored when evaluating objects for deletion.
582 */
583 if (ghp->gh_flags & GPH_PRIVATE)
584 continue;
585 if (aplist_test(ghalp, ghp, 0) != ALE_EXISTS)
586 return (0);
587 }
588
589 /*
590 * If this object is called by any object outside of the family of
591 * objects selected for deletion, it can't be deleted.
592 */
593 for (APLIST_TRAVERSE(CALLERS(lmp), idx, bdp)) {
594 if (aplist_test(lmalp, bdp->b_caller, 0) != ALE_EXISTS)
595 return (0);
596 }
597
598 /*
599 * This object is a candidate for deletion.
600 */
601 return (1);
602 }
603
604 /*
605 * Collect the groups (handles) and associated objects that are candidates for
606 * deletion. The criteria for deleting an object is whether it is only refer-
607 * enced from the objects within the groups that are candidates for deletion.
608 */
609 static int
gdp_collect(APlist ** ghalpp,APlist ** lmalpp,Grp_hdl * ghp1)610 gdp_collect(APlist **ghalpp, APlist **lmalpp, Grp_hdl *ghp1)
611 {
612 Aliste idx1;
613 Grp_desc *gdp;
614 int action;
615
616 /*
617 * Add this group to our group collection. If it isn't added either an
618 * allocation has failed, or it already exists.
619 */
620 if ((action = aplist_test(ghalpp, ghp1, AL_CNT_GRPCLCT)) !=
621 ALE_CREATE)
622 return (action);
623
624 /*
625 * Traverse the dependencies of the group and collect the associated
626 * objects.
627 */
628 for (ALIST_TRAVERSE(ghp1->gh_depends, idx1, gdp)) {
629 Rt_map *lmp = gdp->gd_depend;
630
631 /*
632 * We only want to process dependencies for deletion. Although
633 * we want to purge group descriptors for parents, we don't want
634 * to analyze the parent itself for additional filters or
635 * deletion.
636 */
637 if ((gdp->gd_flags & GPD_PARENT) ||
638 ((gdp->gd_flags & GPD_ADDEPS) == 0))
639 continue;
640
641 if ((action = aplist_test(lmalpp, lmp, AL_CNT_GRPCLCT)) ==
642 ALE_ALLOCFAIL)
643 return (0);
644 if (action == ALE_EXISTS)
645 continue;
646
647 /*
648 * If this object is a candidate for deletion, determine if the
649 * object provides any filtees. If so, the filter groups are
650 * added to the group collection.
651 *
652 * An object is a candidate for deletion if:
653 *
654 * - the object hasn't yet been relocated, in which case
655 * we're here to clean up a failed load, or
656 * - the object doesn't reside on the base link-map control
657 * list, in which case a group of objects, typically
658 * lazily loaded, or filtees, need cleaning up, or
659 * - the object isn't tagged as non-deletable.
660 */
661 if ((((FLAGS(lmp) & FLG_RT_RELOCED) == 0) ||
662 (CNTL(lmp) != ALIST_OFF_DATA) ||
663 ((MODE(lmp) & RTLD_NODELETE) == 0)) &&
664 (FLAGS1(lmp) & MSK_RT_FILTER)) {
665 Dyninfo *dip = DYNINFO(lmp);
666 uint_t cnt, max = DYNINFOCNT(lmp);
667
668 for (cnt = 0; cnt < max; cnt++, dip++) {
669 Alist *falp;
670 Aliste idx2;
671 Pdesc *pdp;
672
673 if (((falp = (Alist *)dip->di_info) == NULL) ||
674 ((dip->di_flags & MSK_DI_FILTER) == 0))
675 continue;
676
677 for (ALIST_TRAVERSE(falp, idx2, pdp)) {
678 Grp_hdl *ghp2;
679
680 if ((pdp->pd_plen == 0) || ((ghp2 =
681 (Grp_hdl *)pdp->pd_info) == NULL))
682 continue;
683
684 if (gdp_collect(ghalpp, lmalpp,
685 ghp2) == 0)
686 return (0);
687 }
688 }
689 }
690 }
691 return (1);
692 }
693
694 /*
695 * Traverse the list of deletable candidates. If an object can't be deleted
696 * then neither can its dependencies or filtees. Any object that is cleared
697 * from being deleted drops the deletion count, plus, if there are no longer
698 * any deletions pending we can discontinue any further processing.
699 */
700 static int
remove_rescan(APlist * lmalp,APlist * ghalp,int * delcnt)701 remove_rescan(APlist *lmalp, APlist *ghalp, int *delcnt)
702 {
703 Aliste idx1;
704 Rt_map *lmp;
705 int rescan = 0;
706
707 for (APLIST_TRAVERSE(lmalp, idx1, lmp)) {
708 Aliste idx2;
709 Bnd_desc *bdp;
710 Dyninfo *dip;
711 uint_t cnt, max;
712
713 if (FLAGS(lmp) & FLG_RT_DELETE)
714 continue;
715
716 /*
717 * As this object can't be deleted, make sure its dependencies
718 * aren't deleted either.
719 */
720 for (APLIST_TRAVERSE(DEPENDS(lmp), idx2, bdp)) {
721 Rt_map *dlmp = bdp->b_depend;
722
723 if (FLAGS(dlmp) & FLG_RT_DELETE) {
724 FLAGS(dlmp) &= ~FLG_RT_DELETE;
725 if (--(*delcnt) == 0)
726 return (0);
727 rescan = 1;
728 }
729 }
730
731 /*
732 * If this object is a filtee and one of its filters is outside
733 * of this dlclose family, then it can't be deleted either.
734 */
735 if ((FLAGS1(lmp) & MSK_RT_FILTER) == 0)
736 continue;
737
738 dip = DYNINFO(lmp);
739 max = DYNINFOCNT(lmp);
740
741 for (cnt = 0; cnt < max; cnt++, dip++) {
742 Alist *falp;
743 Pdesc *pdp;
744
745 if (((falp = (Alist *)dip->di_info) == NULL) ||
746 ((dip->di_flags & MSK_DI_FILTER) == 0))
747 continue;
748
749 for (ALIST_TRAVERSE(falp, idx2, pdp)) {
750 Aliste idx3;
751 Grp_hdl *ghp;
752 Grp_desc *gdp;
753
754 if ((pdp->pd_plen == 0) ||
755 ((ghp = (Grp_hdl *)pdp->pd_info) == NULL))
756 continue;
757
758 if (aplist_test(&ghalp, ghp, 0) ==
759 ALE_EXISTS)
760 continue;
761
762 for (ALIST_TRAVERSE(ghp->gh_depends, idx3,
763 gdp)) {
764 Rt_map *dlmp = gdp->gd_depend;
765
766 if (FLAGS(dlmp) & FLG_RT_DELETE) {
767 FLAGS(dlmp) &= ~FLG_RT_DELETE;
768 if (--(*delcnt) == 0)
769 return (0);
770 rescan = 1;
771 }
772 }
773
774 /*
775 * Remove this group handle from our dynamic
776 * deletion list.
777 */
778 (void) aplist_delete_value(ghalp, ghp);
779 }
780 }
781 }
782 return (rescan);
783 }
784
785 /*
786 * Cleanup any collection alists we've created.
787 */
788 static void
remove_collect(APlist * ghalp,APlist * lmalp)789 remove_collect(APlist *ghalp, APlist *lmalp)
790 {
791 if (ghalp)
792 free(ghalp);
793 if (lmalp)
794 free(lmalp);
795 }
796
797 /*
798 * Remove a handle, leaving the associated objects intact.
799 */
800 void
free_hdl(Grp_hdl * ghp)801 free_hdl(Grp_hdl *ghp)
802 {
803 if (--(ghp->gh_refcnt) == 0) {
804 Grp_desc *gdp;
805 Aliste idx;
806 uintptr_t ndx;
807
808 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) {
809 Rt_map *lmp = gdp->gd_depend;
810
811 if (ghp->gh_ownlmp == lmp)
812 (void) aplist_delete_value(HANDLES(lmp), ghp);
813 (void) aplist_delete_value(GROUPS(lmp), ghp);
814 }
815 (void) free(ghp->gh_depends);
816
817 /* LINTED */
818 ndx = (uintptr_t)ghp % HDLIST_SZ;
819 (void) aplist_delete_value(hdl_alp[ndx], ghp);
820
821 (void) free(ghp);
822 }
823 }
824
825 /*
826 * If a load operation, using a new link-map control list, has failed, then
827 * forcibly remove the failed objects. This failure can occur as a result
828 * of a lazy load, a dlopen(), or a filtee load, once the application is
829 * running. If the link-map control list has not yet started relocation, then
830 * cleanup is simply a process of removing all the objects from the control
831 * list. If relocation has begun, then other loads may have been triggered to
832 * satisfy the relocations, and thus we need to break down the control list
833 * using handles.
834 *
835 * The objects associated with this load must be part of a unique handle. In
836 * the case of a dlopen() or filtee request, a handle will have been created.
837 * For a lazyload request, a handle must be generated so that the remove
838 * process can use the handle.
839 *
840 * During the course of processing these objects, other objects (handles) may
841 * have been loaded to satisfy relocation requirements. After these families
842 * have successfully loaded, they will have been propagated to the same link-map
843 * control list. The failed objects need to be removed from this list, while
844 * any successfully loaded families can be left alone, and propagated to the
845 * previous link-map control list. By associating each load request with a
846 * handle, we can isolate the failed objects while not interfering with any
847 * successfully loaded families.
848 */
849 void
remove_lmc(Lm_list * lml,Rt_map * clmp,Aliste lmco,const char * name)850 remove_lmc(Lm_list *lml, Rt_map *clmp, Aliste lmco, const char *name)
851 {
852 Grp_hdl *ghp;
853 Grp_desc *gdp;
854 Aliste idx;
855 Lm_cntl *lmc;
856 Rt_map *lmp;
857
858 /*
859 * Determine the link-map control list, and whether any object has been
860 * added to this list.
861 */
862 /* LINTED */
863 lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco);
864 if (lmc->lc_head == NULL)
865 return;
866
867 DBG_CALL(Dbg_file_cleanup(lml, name, lmco));
868
869 /*
870 * Obtain a handle for the first object on the link-map control list.
871 * If none exists (which would occur from a lazy load request), and
872 * the link-map control list is being relocated, create a handle.
873 */
874 lmp = lmc->lc_head;
875 if (HANDLES(lmp)) {
876 ghp = (Grp_hdl *)HANDLES(lmp)->apl_data[0];
877
878 /*
879 * If this is a private handle, remove this state, so as to
880 * prevent any attempt to remove the handle more than once.
881 */
882 ghp->gh_flags &= ~GPH_PRIVATE;
883
884 } else if (lmc->lc_flags & LMC_FLG_RELOCATING) {
885 /*
886 * Establish a handle, and should anything fail, fall through
887 * to remove the link-map control list.
888 */
889 if (((ghp = hdl_create(lml, lmc->lc_head, NULL, GPH_PUBLIC,
890 GPD_ADDEPS, 0)) == NULL) ||
891 (hdl_initialize(ghp, lmc->lc_head, 0, 0) == 0))
892 lmc->lc_flags &= ~LMC_FLG_RELOCATING;
893 } else {
894 ghp = NULL;
895 }
896
897 /*
898 * If relocation hasn't begun, simply remove all the objects from this
899 * list, and any handle that may have been created.
900 */
901 if ((lmc->lc_flags & LMC_FLG_RELOCATING) == 0) {
902 remove_incomplete(lml, lmco, clmp);
903
904 if (ghp) {
905 ghp->gh_refcnt = 1;
906 free_hdl(ghp);
907 }
908 return;
909 }
910
911 ASSERT(ghp != NULL);
912
913 /*
914 * As the objects of this handle are being forcibly removed, first
915 * remove any associations to objects on parent link-map control
916 * lists. This breaks the bond between a caller and a hierarchy of
917 * dependencies represented by the handle, thus the caller doesn't lock
918 * the hierarchy and prevent their deletion from the generic handle
919 * processing or remove_hdl().
920 *
921 * This scenario can be produced when the relocation of a object
922 * results in vectoring through a filter that is already loaded. The
923 * filtee may be on the link-map list that is presently being processed,
924 * however an association between the filter and filtee would have been
925 * established during filtee processing. It is this association that
926 * must be broken to allow the objects on this link-map list to be
927 * removed.
928 */
929 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) {
930 Rt_map *lmp = gdp->gd_depend;
931
932 /*
933 * If this object has not been relocated, break down any
934 * dependency relationships the object might have established.
935 */
936 if ((FLAGS(lmp) & FLG_RT_RELOCED) == 0)
937 remove_lists(lmp, 1);
938
939 if (CNTL(lmp) == lmco)
940 continue;
941
942 if (gdp->gd_flags & GPD_FILTER) {
943 Dyninfo *dip = DYNINFO(lmp);
944 uint_t cnt, max = DYNINFOCNT(lmp);
945
946 for (cnt = 0; cnt < max; cnt++, dip++) {
947 Alist *falp;
948 Aliste idx2;
949 Pdesc *pdp;
950
951 if (((falp = (Alist *)dip->di_info) == NULL) ||
952 ((dip->di_flags & MSK_DI_FILTER) == 0))
953 continue;
954
955 for (ALIST_TRAVERSE(falp, idx2, pdp)) {
956 if ((Grp_hdl *)pdp->pd_info == ghp) {
957 pdp->pd_info = NULL;
958 break;
959 }
960 }
961 }
962 }
963 (void) aplist_delete_value(GROUPS(lmp), ghp);
964 alist_delete(ghp->gh_depends, &idx);
965 }
966
967 /*
968 * Having removed any callers, set the group handle reference count to
969 * one, and let the generic handle remover delete the associated
970 * objects.
971 */
972 ghp->gh_refcnt = 1;
973 (void) remove_hdl(ghp, clmp, NULL);
974
975 /*
976 * If this link-map control list still contains objects, determine the
977 * previous control list and move the objects.
978 */
979 if (lmc->lc_head) {
980 Lm_cntl *plmc;
981 Aliste plmco;
982
983 plmco = lmco - lml->lm_lists->al_size;
984 /* LINTED */
985 plmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, plmco);
986
987 lm_move(lml, lmco, plmco, lmc, plmc);
988 }
989 }
990
991 /*
992 * Remove the objects associated with a handle. There are two goals here, to
993 * delete the objects associated with the handle, and to remove the handle
994 * itself. Things get a little more complex if the objects selected for
995 * deletion are filters, in this case we also need to collect their filtees,
996 * and process the combined groups as a whole. But, care still must be exer-
997 * cised to make sure any filtees found aren't being used by filters outside of
998 * the groups we've collect. The series of events is basically:
999 *
1000 * - Determine the groups (handles) that might be deletable.
1001 *
1002 * - Determine the objects of these handles that can be deleted.
1003 *
1004 * - Fire the fini's of those objects selected for deletion.
1005 *
1006 * - Remove all inter-dependency linked lists while the objects link-maps
1007 * are still available.
1008 *
1009 * - Remove all deletable objects link-maps and unmap the objects themselves.
1010 *
1011 * - Remove the handle descriptors for each deleted object, and hopefully
1012 * the whole handle.
1013 *
1014 * A handle that can't be deleted is added to an orphans list. This list is
1015 * revisited any time another dlclose() request results in handle descriptors
1016 * being deleted. These deleted descriptors can be sufficient to allow the
1017 * final deletion of the orphaned handles.
1018 */
1019 int
remove_hdl(Grp_hdl * ghp,Rt_map * clmp,int * removed)1020 remove_hdl(Grp_hdl *ghp, Rt_map *clmp, int *removed)
1021 {
1022 Rt_map *lmp;
1023 int rescan = 0;
1024 int delcnt = 0, rmcnt = 0, error = 0, orphans;
1025 APlist *lmalp = NULL, *ghalp = NULL;
1026 Aliste idx1, idx2;
1027 Grp_hdl *ghp2;
1028 Grp_desc *gdp;
1029 Lm_list *lml = NULL;
1030
1031 /*
1032 * Generate the family of groups and objects that are candidates for
1033 * deletion. This consists of the objects that are explicitly defined
1034 * as dependencies of this handle, plus any filtee handles and their
1035 * associated objects.
1036 */
1037 if (gdp_collect(&ghalp, &lmalp, ghp) == 0) {
1038 remove_collect(ghalp, lmalp);
1039 return (0);
1040 }
1041
1042 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_DELETE));
1043
1044 /*
1045 * Traverse the groups we've collected to determine if any filtees are
1046 * included. If so, and the filtee handle is in use by a filter outside
1047 * of the family of objects collected for this deletion, it can not be
1048 * removed.
1049 */
1050 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1051 Grp_hdl *ghp = ghp2;
1052
1053 DBG_CALL(Dbg_file_hdl_collect(ghp, 0));
1054
1055 if ((ghp->gh_flags & GPH_FILTEE) == 0)
1056 continue;
1057
1058 /*
1059 * Special case for ld.so.1. There can be multiple instances of
1060 * libdl.so.1 using this handle, so although we want the handles
1061 * reference count to be decremented, we don't want the handle
1062 * removed.
1063 */
1064 if (ghp->gh_flags & GPH_LDSO) {
1065 DBG_CALL(Dbg_file_hdl_collect(ghp,
1066 NAME(lml_rtld.lm_head)));
1067 aplist_delete(ghalp, &idx1);
1068 continue;
1069 }
1070
1071 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1072 Grp_hdl *ghp3;
1073 Aliste idx3;
1074
1075 /*
1076 * Determine whether this dependency is the filtee's
1077 * parent filter, and that it isn't also an explicit
1078 * dependency (in which case it would have added its own
1079 * dependencies to the handle).
1080 */
1081 if ((gdp->gd_flags &
1082 (GPD_FILTER | GPD_ADDEPS)) != GPD_FILTER)
1083 continue;
1084
1085 lmp = gdp->gd_depend;
1086
1087 if (FLAGS(lmp) & FLG_RT_DELETE)
1088 continue;
1089
1090 if (aplist_test(&lmalp, lmp, 0) == ALE_EXISTS)
1091 continue;
1092
1093 /*
1094 * Remove this group handle from our dynamic deletion
1095 * list. In addition, recompute the list of objects
1096 * that are candidates for deletion to continue this
1097 * group verification.
1098 */
1099 DBG_CALL(Dbg_file_hdl_collect(ghp, NAME(lmp)));
1100 aplist_delete(ghalp, &idx1);
1101
1102 free(lmalp);
1103 lmalp = NULL;
1104 for (APLIST_TRAVERSE(ghalp, idx3, ghp3)) {
1105 Aliste idx4;
1106 Grp_desc *gdp4;
1107
1108 for (ALIST_TRAVERSE(ghp3->gh_depends,
1109 idx4, gdp4)) {
1110 if ((gdp4->gd_flags & GPD_ADDEPS) == 0)
1111 continue;
1112 if (aplist_test(&lmalp, gdp4->gd_depend,
1113 AL_CNT_GRPCLCT) == ALE_ALLOCFAIL) {
1114 remove_collect(ghalp, lmalp);
1115 return (0);
1116 }
1117 }
1118 }
1119 break;
1120 }
1121 }
1122
1123 /*
1124 * Now that we've collected all the handles dependencies, traverse the
1125 * collection determining whether they are a candidate for deletion.
1126 */
1127 for (APLIST_TRAVERSE(lmalp, idx1, lmp)) {
1128 /*
1129 * Establish which link-map list we're dealing with for later
1130 * .fini processing.
1131 */
1132 if (lml == NULL)
1133 lml = LIST(lmp);
1134
1135 /*
1136 * If an object isn't a candidate for deletion we'll have to
1137 * rescan the handle insuring that this objects dependencies
1138 * aren't deleted either.
1139 */
1140 if (is_deletable(&lmalp, &ghalp, lmp)) {
1141 FLAGS(lmp) |= FLG_RT_DELETE;
1142 delcnt++;
1143 } else
1144 rescan = 1;
1145 }
1146
1147 /*
1148 * Rescan the handle if any objects where found non-deletable.
1149 */
1150 while (rescan)
1151 rescan = remove_rescan(lmalp, ghalp, &delcnt);
1152
1153 /*
1154 * Now that we have determined the number of groups that are candidates
1155 * for removal, mark each group descriptor as a candidate for removal
1156 * from the group.
1157 */
1158 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1159 for (ALIST_TRAVERSE(ghp2->gh_depends, idx2, gdp))
1160 gdp->gd_flags |= GPD_REMOVE;
1161 }
1162
1163 /*
1164 * Now that we know which objects on this handle can't be deleted
1165 * determine whether they still need to remain identified as belonging
1166 * to this group to be able to continue binding to one another.
1167 */
1168 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1169 Grp_hdl *ghp = ghp2;
1170
1171 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1172 Aliste idx3;
1173 Bnd_desc *bdp;
1174
1175 lmp = gdp->gd_depend;
1176
1177 if (FLAGS(lmp) & FLG_RT_DELETE)
1178 continue;
1179
1180 for (APLIST_TRAVERSE(DEPENDS(lmp), idx3, bdp)) {
1181 Aliste idx4;
1182 Grp_desc *gdp4;
1183 Rt_map *dlmp = bdp->b_depend;
1184
1185 /*
1186 * If this dependency (dlmp) can be referenced
1187 * by the caller (clmp) without being part of
1188 * this group (ghp) then belonging to this group
1189 * is no longer necessary. This can occur when
1190 * objects are part of multiple handles, or if a
1191 * previously deleted handle was moved to the
1192 * orphan list and has been reopened. Note,
1193 * first make sure the caller can reference the
1194 * dependency with this group, if it can't we
1195 * must be bound to a filtee, so there's no need
1196 * to remain a part of this group either.
1197 */
1198 if ((callable(lmp, dlmp, 0, 0) == 0) ||
1199 callable(lmp, dlmp, ghp, 0))
1200 continue;
1201
1202 if (gdp->gd_flags & GPD_REMOVE)
1203 gdp->gd_flags &= ~GPD_REMOVE;
1204
1205 for (ALIST_TRAVERSE(ghp->gh_depends,
1206 idx4, gdp4)) {
1207 if (gdp4->gd_depend != dlmp)
1208 continue;
1209
1210 if (gdp4->gd_flags & GPD_REMOVE)
1211 gdp4->gd_flags &= ~GPD_REMOVE;
1212 }
1213 }
1214 }
1215 }
1216
1217 /*
1218 * If the owner of a handle can't be deleted and it's handle descriptor
1219 * must remain also, don't delete the handle at all. Leave it for
1220 * possible later use. Although it's left intact, it will still be
1221 * moved to the orphans list, as we might be able to revisit it on later
1222 * dlclose() operations and finally remove the underlying objects. Note
1223 * that the handle still remains attached to the owner via the HANDLES
1224 * list, so that it can be re-associated to the owner if a dlopen()
1225 * of this object reoccurs.
1226 */
1227 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1228 Grp_hdl *ghp = ghp2;
1229
1230 /*
1231 * If this handle is already an orphan, or if it's owner is
1232 * deletable there's no need to inspect its dependencies.
1233 */
1234 if ((ghp->gh_ownlmp == NULL) ||
1235 (FLAGS(ghp->gh_ownlmp) & FLG_RT_DELETE))
1236 continue;
1237
1238 /*
1239 * Make sure all handle dependencies aren't removed or the
1240 * dependencies themselves aren't deleted.
1241 */
1242 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1243 lmp = gdp->gd_depend;
1244
1245 /*
1246 * The first dependency of a non-orphaned handle is the
1247 * owner. If the handle descriptor for this isn't
1248 * required there's no need to look at any other of the
1249 * handles dependencies.
1250 */
1251 if ((lmp == ghp->gh_ownlmp) &&
1252 (gdp->gd_flags & GPD_REMOVE))
1253 break;
1254
1255 if (gdp->gd_flags & GPD_REMOVE)
1256 gdp->gd_flags &= ~GPD_REMOVE;
1257 if (FLAGS(lmp) & FLG_RT_DELETE) {
1258 FLAGS(lmp) &= ~FLG_RT_DELETE;
1259 delcnt--;
1260 }
1261 }
1262 }
1263
1264 /*
1265 * Final scan of objects to see if any objects are to to be deleted.
1266 * Also - display diagnostic information on what operations are to be
1267 * performed on the collected handles before firing .fini's (which
1268 * produces additional diagnostics).
1269 */
1270 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1271 Grp_hdl *ghp = ghp2;
1272
1273 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_DELETE));
1274
1275 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1276 Grp_hdl *ghp3;
1277 Aliste idx3;
1278 int flag;
1279
1280 lmp = gdp->gd_depend;
1281
1282 /*
1283 * Note, we must never delete a parent. The parent
1284 * may already be tagged for deletion from a previous
1285 * dlclose(). That dlclose has triggered this dlclose(),
1286 * but the parents deletion is the responsibility of the
1287 * previous dlclose(), not this one.
1288 */
1289 if ((FLAGS(lmp) & FLG_RT_DELETE) &&
1290 ((gdp->gd_flags & GPD_PARENT) == 0)) {
1291 flag = DBG_DEP_DELETE;
1292
1293 /*
1294 * Remove any pathnames from the FullpathNode
1295 * AVL tree. As we're about to fire .fini's,
1296 * it's possible this object will be required
1297 * again, in which case we want to make sure a
1298 * new version of the object gets loaded.
1299 */
1300 if (FPNODE(lmp))
1301 fpavl_remove(lmp);
1302 } else if (gdp->gd_flags & GPD_REMOVE)
1303 flag = DBG_DEP_REMOVE;
1304 else
1305 flag = DBG_DEP_REMAIN;
1306
1307 DBG_CALL(Dbg_file_hdl_action(ghp, lmp, flag, 0));
1308
1309 /*
1310 * If this object contains any private handles, remove
1311 * them now.
1312 */
1313 for (APLIST_TRAVERSE(HANDLES(lmp), idx3, ghp3)) {
1314 if (ghp3->gh_flags & GPH_PRIVATE)
1315 free_hdl(ghp3);
1316 }
1317 }
1318 }
1319
1320 /*
1321 * If there are objects to be deleted process their .fini's.
1322 */
1323 if (delcnt) {
1324 Rt_map **tobj;
1325
1326 /*
1327 * Sort and fire all fini's of the objects selected for
1328 * deletion. Note that we have to start our search from the
1329 * link-map head - there's no telling whether this object has
1330 * dependencies on objects that were loaded before it and which
1331 * can now be deleted. If the tsort() fails because of an
1332 * allocation error then that might just be a symptom of why
1333 * we're here in the first place - forgo the fini's but
1334 * continue to try cleaning up.
1335 */
1336 lml->lm_flags |= LML_FLG_OBJDELETED;
1337
1338 if (((tobj = tsort(lml->lm_head, delcnt,
1339 (RT_SORT_DELETE | RT_SORT_FWD))) != NULL) &&
1340 (tobj != (Rt_map **)S_ERROR)) {
1341 error = purge_exit_handlers(lml, tobj);
1342 call_fini(lml, tobj, clmp);
1343 }
1344 }
1345
1346 /*
1347 * Now that .fini processing (which may have involved new bindings)
1348 * is complete, remove all inter-dependency lists from those objects
1349 * selected for deletion.
1350 */
1351 for (APLIST_TRAVERSE(lmalp, idx1, lmp)) {
1352 Dyninfo *dip;
1353 uint_t cnt, max;
1354
1355 if (FLAGS(lmp) & FLG_RT_DELETE)
1356 remove_lists(lmp, 0);
1357
1358 /*
1359 * Determine whether we're dealing with a filter, and if so
1360 * process any inter-dependencies with its filtee's.
1361 */
1362 if ((FLAGS1(lmp) & MSK_RT_FILTER) == 0)
1363 continue;
1364
1365 dip = DYNINFO(lmp);
1366 max = DYNINFOCNT(lmp);
1367
1368 for (cnt = 0; cnt < max; cnt++, dip++) {
1369 Alist *falp;
1370 Aliste idx2;
1371 Pdesc *pdp;
1372
1373 if (((falp = (Alist *)dip->di_info) == NULL) ||
1374 ((dip->di_flags & MSK_DI_FILTER) == 0))
1375 continue;
1376
1377 for (ALIST_TRAVERSE(falp, idx2, pdp)) {
1378 Grp_hdl *ghp;
1379
1380 if ((pdp->pd_plen == 0) ||
1381 ((ghp = (Grp_hdl *)pdp->pd_info) == NULL))
1382 continue;
1383
1384 /*
1385 * Determine whether this filtee's handle is a
1386 * part of the list of handles being deleted.
1387 */
1388 if (aplist_test(&ghalp, ghp, 0) == ALE_EXISTS) {
1389 /*
1390 * If this handle exists on the deletion
1391 * list, then it has been removed. If
1392 * this filter isn't going to be
1393 * deleted, sever its reference to the
1394 * handle.
1395 */
1396 pdp->pd_info = NULL;
1397 } else {
1398 /*
1399 * If this handle isn't on the deletion
1400 * list, then it must still exist. If
1401 * this filter is being deleted, make
1402 * sure the filtees reference count
1403 * gets decremented.
1404 */
1405 if (FLAGS(lmp) & FLG_RT_DELETE) {
1406 (void) dlclose_core(ghp,
1407 lmp, lml);
1408 }
1409 }
1410 }
1411 }
1412 }
1413
1414 /*
1415 * If called from dlclose(), determine if there are already handles on
1416 * the orphans list that we can reinvestigate.
1417 */
1418 if ((removed == 0) && aplist_nitems(hdl_alp[HDLIST_ORP]))
1419 orphans = 1;
1420 else
1421 orphans = 0;
1422
1423 /*
1424 * Finally remove any handle infrastructure and remove any objects
1425 * marked for deletion.
1426 */
1427 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1428 Grp_hdl *ghp = ghp2;
1429
1430 /*
1431 * If we're not dealing with orphaned handles remove this handle
1432 * from its present handle list.
1433 */
1434 if (removed == 0) {
1435 uintptr_t ndx;
1436
1437 /* LINTED */
1438 ndx = (uintptr_t)ghp % HDLIST_SZ;
1439 (void) aplist_delete_value(hdl_alp[ndx], ghp);
1440 }
1441
1442 /*
1443 * Traverse each handle dependency. Retain the dependencies
1444 * flags to insure we don't delete any parents (the flags
1445 * information is deleted as part of the alist removal that
1446 * occurs before we inspect the object for deletion).
1447 */
1448 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1449 uint_t flags = gdp->gd_flags;
1450
1451 if ((flags & GPD_REMOVE) == 0)
1452 continue;
1453
1454 lmp = gdp->gd_depend;
1455 rmcnt++;
1456
1457 /*
1458 * If this object is the owner of the handle break that
1459 * association in case the handle is retained.
1460 */
1461 if (ghp->gh_ownlmp == lmp) {
1462 (void) aplist_delete_value(HANDLES(lmp), ghp);
1463 ghp->gh_ownlmp = NULL;
1464 }
1465
1466 (void) aplist_delete_value(GROUPS(lmp), ghp);
1467 alist_delete(ghp->gh_depends, &idx2);
1468
1469 /*
1470 * Complete the link-map deletion if appropriate.
1471 */
1472 if ((FLAGS(lmp) & FLG_RT_DELETE) &&
1473 ((flags & GPD_PARENT) == 0)) {
1474 tls_modaddrem(lmp, TM_FLG_MODREM);
1475 remove_so(LIST(lmp), lmp, clmp);
1476 }
1477 }
1478
1479 /*
1480 * If we've deleted all the dependencies of the handle, finalize
1481 * the cleanup by removing the handle itself.
1482 *
1483 * Otherwise we're left with a handle containing one or more
1484 * objects that can not be deleted (they're in use by other
1485 * handles, non-deletable, etc.), but require to remain a part
1486 * of this group to allow them to continue binding to one
1487 * another.
1488 *
1489 * If the handles reference count is zero, or represents a
1490 * link-map list (dlopen(0)), then move that handle to the
1491 * orphans list. Should another dlclose() operation occur that
1492 * results in the removal of handle descriptors, these orphan
1493 * handles are re-examined to determine if their deletion can
1494 * be completed.
1495 */
1496 if (ghp->gh_depends->al_nitems == 0) {
1497 free(ghp->gh_depends);
1498 free(ghp);
1499
1500 } else if ((ghp->gh_refcnt == 0) &&
1501 ((ghp->gh_flags & GPH_ZERO) == 0)) {
1502 /*
1503 * Move this handle to the orphans list.
1504 */
1505 (void) aplist_append(&hdl_alp[HDLIST_ORP], ghp,
1506 AL_CNT_HANDLES);
1507
1508 if (DBG_ENABLED) {
1509 DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ORPHAN));
1510 for (ALIST_TRAVERSE(ghp->gh_depends, idx1, gdp))
1511 DBG_CALL(Dbg_file_hdl_action(ghp,
1512 gdp->gd_depend, DBG_DEP_ORPHAN, 0));
1513 }
1514 }
1515 }
1516
1517 /*
1518 * If no handle descriptors got removed there's no point in looking for
1519 * orphans to process.
1520 */
1521 if (rmcnt == 0)
1522 orphans = 0;
1523
1524 /*
1525 * Cleanup any alists we've created.
1526 */
1527 remove_collect(ghalp, lmalp);
1528
1529 /*
1530 * If orphan processing isn't required we're done. If our processing
1531 * originated from investigating orphans, return the number of handle
1532 * descriptors removed as an indication whether orphan processing
1533 * should continue.
1534 */
1535 if (orphans == 0) {
1536 if (removed)
1537 *removed = rmcnt;
1538 return (error);
1539 }
1540
1541 /*
1542 * Traverse the orphans list as many times as necessary until no
1543 * handle removals occur.
1544 */
1545 do {
1546 APlist *alp;
1547 Aliste idx;
1548 Grp_hdl *ghp, *oghp = NULL;
1549 int title = 0;
1550
1551 /*
1552 * Effectively clean the HDLIST_ORP list. Any object that can't
1553 * be removed will be re-added to the list.
1554 */
1555 alp = hdl_alp[HDLIST_ORP];
1556 hdl_alp[HDLIST_ORP] = NULL;
1557
1558 rescan = 0;
1559 for (APLIST_TRAVERSE(alp, idx, ghp)) {
1560 int _error, _remove;
1561
1562 if (title++ == 0)
1563 DBG_CALL(Dbg_file_del_rescan(ghp->gh_ownlml));
1564
1565 if (oghp) {
1566 (void) aplist_delete_value(alp, oghp);
1567 oghp = NULL;
1568 }
1569
1570 if (((_error = remove_hdl(ghp, clmp, &_remove)) != 0) &&
1571 (error == 0))
1572 error = _error;
1573
1574 if (_remove)
1575 rescan++;
1576
1577 oghp = ghp;
1578 }
1579 if (oghp) {
1580 (void) aplist_delete_value(alp, oghp);
1581 oghp = NULL;
1582 }
1583 if (alp)
1584 free((void *)alp);
1585
1586 } while (rescan && aplist_nitems(hdl_alp[HDLIST_ORP]));
1587
1588 return (error);
1589 }
1590