summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1997-07-01 21:13:35 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1997-07-01 21:13:35 +0000
commita2de325c1bc9091584675c1c79cfef0bd577dc02 (patch)
tree7b15c47bd73f26cfd15ea3eafa9efc4dfb0b18ac /gnu
parent6555f0b10075bb6cf784f7255ba73d71960ffcf7 (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.c106
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;
}