diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1997-07-01 21:13:35 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1997-07-01 21:13:35 +0000 |
commit | a2de325c1bc9091584675c1c79cfef0bd577dc02 (patch) | |
tree | 7b15c47bd73f26cfd15ea3eafa9efc4dfb0b18ac /gnu | |
parent | 6555f0b10075bb6cf784f7255ba73d71960ffcf7 (diff) |
memory leaks, object leaks. some from pk/cgd. rearrange *_DL checks for
further safety.
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/usr.bin/ld/rtld/rtld.c | 106 |
1 files changed, 91 insertions, 15 deletions
diff --git a/gnu/usr.bin/ld/rtld/rtld.c b/gnu/usr.bin/ld/rtld/rtld.c index e7a6395cbba..d2d44e597a8 100644 --- a/gnu/usr.bin/ld/rtld/rtld.c +++ b/gnu/usr.bin/ld/rtld/rtld.c @@ -84,6 +84,7 @@ struct somap_private { #define RTLD_MAIN 1 #define RTLD_RTLD 2 #define RTLD_DL 4 + size_t spd_size; #ifdef SUN_COMPAT long spd_offset; /* Correction for Sun main programs */ @@ -178,9 +179,11 @@ static struct ld_entry ld_entry = { long binder __P((jmpslot_t *)); static int load_subs __P((struct so_map *)); static struct so_map *map_object __P((struct sod *, struct so_map *)); +static void unmap_object __P((struct so_map *)); static struct so_map *alloc_link_map __P(( char *, struct sod *, struct so_map *, caddr_t, - struct _dynamic *)); + size_t, struct _dynamic *)); +static void free_link_map __P((struct so_map *)); static inline void check_text_reloc __P(( struct relocation_info *, struct so_map *, caddr_t)); @@ -290,12 +293,12 @@ rtld(version, crtp, dp) * for `main' and `rtld'. */ smp = alloc_link_map(main_progname, (struct sod *)0, (struct so_map *)0, - (caddr_t)0, crtp->crt_dp); + (caddr_t)0, 0, crtp->crt_dp); LM_PRIVATE(smp)->spd_refcount++; LM_PRIVATE(smp)->spd_flags |= RTLD_MAIN; smp = alloc_link_map(us, (struct sod *)0, (struct so_map *)0, - (caddr_t)crtp->crt_ba, dp); + (caddr_t)crtp->crt_ba, 0, dp); LM_PRIVATE(smp)->spd_refcount++; LM_PRIVATE(smp)->spd_flags |= RTLD_RTLD; @@ -383,7 +386,8 @@ load_subs(smp) sodp->sod_major, sodp->sod_minor); } - newmap = alloc_link_map(NULL, sodp, smp, 0, 0); + newmap = alloc_link_map(NULL, sodp, smp, + 0, 0, 0); } LM_PRIVATE(newmap)->spd_refcount++; next = sodp->sod_next; @@ -482,11 +486,12 @@ ld_trace(smp) * result of the presence of link object LOP in the link map PARENT. */ static struct so_map * -alloc_link_map(path, sodp, parent, addr, dp) +alloc_link_map(path, sodp, parent, addr, size, dp) char *path; struct sod *sodp; struct so_map *parent; caddr_t addr; + size_t size; struct _dynamic *dp; { struct so_map *smp; @@ -511,6 +516,7 @@ alloc_link_map(path, sodp, parent, addr, dp) smpp->spd_refcount = 0; smpp->spd_flags = 0; smpp->spd_parent = parent; + smpp->spd_size = size; #ifdef SUN_COMPAT smpp->spd_offset = @@ -520,6 +526,29 @@ alloc_link_map(path, sodp, parent, addr, dp) } /* + * Free the link map for an object being unmapped. The link map + * has already been removed from the link map list, so it can't be used + * after it's been unmapped. + */ +static void +free_link_map(smp) + struct so_map *smp; +{ + + if ((LM_PRIVATE(smp)->spd_flags & RTLD_DL) != 0) { + /* free synthetic sod structure allocated in __dlopen() */ + free((char *)smp->som_sod->sod_name); + free(smp->som_sod); + } + + /* free the link map structure. */ + free(smp->som_spd); + if (smp->som_path != NULL) + free(smp->som_path); + free(smp); +} + +/* * Map object identified by link object SODP which was found * in link map SMP. */ @@ -604,6 +633,10 @@ again: return NULL; } +#if DEBUG + xprintf("map1: 0x%x for 0x%x\n", addr, hdr.a_text + hdr.a_data + hdr.a_bss); +#endif + if (mprotect(addr + hdr.a_text, hdr.a_data, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) { (void)close(fd); @@ -626,7 +659,38 @@ again: /* Fixup __DYNAMIC structure */ (long)dp->d_un.d_sdt += (long)addr; - return alloc_link_map(path, sodp, smp, addr, dp); + return alloc_link_map(path, sodp, smp, addr, + hdr.a_text + hdr.a_data + hdr.a_bss, dp); +} + +/* + * Unmap a mapped object. + */ +static void +unmap_object(smp) + struct so_map *smp; +{ + struct so_map *p, **pp; + + /* remove from link map list */ + pp = &link_map_head; + while ((p = *pp) != NULL) { + if (p == smp) + break; + pp = &p->som_next; + } + if (p == NULL) { + warnx("warning: link map entry for %s not on link map list!", + smp->som_path); + return; + } + + *pp = smp->som_next; /* make list skip it */ + if (link_map_tail == &smp->som_next) /* and readjust tail pointer */ + link_map_tail = pp; + + /* unmap from address space */ + (void)munmap(smp->som_addr, LM_PRIVATE(smp)->spd_size); } void @@ -1342,7 +1406,7 @@ static struct so_map dlmap = { static int dlerrno; /* - * Populate sod struct for dlopen's call to map_obj + * Populate sod struct for dlopen's call to map_object */ void build_sod(name, sodp) @@ -1442,16 +1506,27 @@ __dlopen(name, mode) xprintf("%s: %s\n", name, strerror(errno)); #endif dlerrno = errno; + free((char *)sodp->sod_name); + free(sodp); return NULL; } - if (LM_PRIVATE(smp)->spd_refcount++ > 0) + if (LM_PRIVATE(smp)->spd_refcount++ > 0) { + free((char *)sodp->sod_name); + free(sodp); return smp; + } + + LM_PRIVATE(smp)->spd_flags |= RTLD_DL; - if (load_subs(smp) != 0) + if (load_subs(smp) != 0) { + if (--LM_PRIVATE(smp)->spd_refcount == 0) { + unmap_object(smp); + free_link_map(smp); + } return NULL; + } - LM_PRIVATE(smp)->spd_flags |= RTLD_DL; init_maps(smp); return smp; } @@ -1468,15 +1543,16 @@ xprintf("dlclose(%s): refcount = %d\n", smp->som_path, LM_PRIVATE(smp)->spd_refc if (--LM_PRIVATE(smp)->spd_refcount != 0) return 0; + if ((LM_PRIVATE(smp)->spd_flags & RTLD_DL) == 0) + return 0; + /* Dismantle shared object map and descriptor */ call_map(smp, "__fini"); #if 0 - unmap_object(smp); - free(smp->som_sod->sod_name); - free(smp->som_sod); - free(smp); + unload_subs(smp); /* XXX should unload implied objects */ #endif - + unmap_object(smp); + free_link_map(smp); return 0; } |