@@ -94,6 +94,28 @@ _dl_audit_premap_dlmem (struct link_map *l, size_t maplength)
return -1;
}
+void *
+_dl_audit_premap (struct link_map *l, void *pref_addr, size_t maplength)
+{
+ if (__glibc_likely (GLRO(dl_naudit) == 0))
+ return MAP_FAILED;
+
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->premap != NULL)
+ {
+ struct auditstate *state = link_map_audit_state (l, cnt);
+ void *addr = afct->premap (pref_addr, maplength, &state->cookie);
+ if (addr != MAP_FAILED)
+ return addr;
+ }
+
+ afct = afct->next;
+ }
+ return MAP_FAILED;
+}
+
void
_dl_audit_objopen (struct link_map *l, Lmid_t nsid)
{
@@ -90,6 +90,7 @@ _dl_map_segments (struct link_map *l, void *fd,
if (__glibc_likely (type == ET_DYN))
{
+ bool fixed_addr = false;
/* This is a position-independent shared object. We can let the
kernel map it anywhere it likes, but we must have space for all
the segments in their specified positions relative to the first.
@@ -105,10 +106,23 @@ _dl_map_segments (struct link_map *l, void *fd,
= (ELF_PREFERRED_ADDRESS (loader, maplength, c->mapstart)
- MAP_BASE_ADDR (l));
- /* Remember which part of the address space this object uses. */
- l->l_map_start = _dl_map_segment (c, mappref, maplength);
- if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED))
- return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
+#ifdef SHARED
+ /* Call audit to let it change the address if he wants. */
+ void *pref_addr = _dl_audit_premap (l, (void *) mappref, maplength);
+ if (pref_addr != MAP_FAILED)
+ {
+ l->l_map_start = (ElfW(Addr)) pref_addr;
+ fixed_addr = true;
+ }
+#endif
+
+ if (!fixed_addr)
+ {
+ /* Remember which part of the address space this object uses. */
+ l->l_map_start = _dl_map_segment (c, mappref, maplength);
+ if (__glibc_unlikely ((void *) l->l_map_start == MAP_FAILED))
+ return DL_MAP_SEGMENTS_ERROR_MAP_SEGMENT;
+ }
l->l_map_end = l->l_map_start + maplength;
l->l_addr = l->l_map_start - c->mapstart;
@@ -194,6 +194,8 @@ extern void la_activity (uintptr_t *__cookie, unsigned int __flag);
extern char *la_objsearch (const char *__name, uintptr_t *__cookie,
unsigned int __flag);
extern int la_premap_dlmem (size_t maplength, uintptr_t *__cookie);
+extern void *la_premap (void *pref_addr, size_t maplength,
+ uintptr_t *__cookie);
extern unsigned int la_objopen (struct link_map *__map, Lmid_t __lmid,
uintptr_t *__cookie);
extern void la_preinit (uintptr_t *__cookie);
@@ -990,7 +990,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
return;
}
- enum { naudit_ifaces = 9 };
+ enum { naudit_ifaces = 10 };
union
{
struct audit_ifaces ifaces;
@@ -1005,6 +1005,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
"la_activity\0"
"la_objsearch\0"
"la_premap_dlmem\0"
+ "la_premap\0"
"la_objopen\0"
"la_preinit\0"
LA_SYMBIND "\0"
@@ -80,10 +80,24 @@ static int
handle_restart (void)
{
{
+ Dl_info info;
void *h = dlmem_wrapper ("../" LIBC_SO, RTLD_NOW);
pid_t (*s) (void) = xdlsym (h, "getpid");
TEST_COMPARE (s (), getpid ());
+ if (!dladdr (s, &info))
+ {
+ printf ("dladdr failed\n");
+ exit (EXIT_FAILURE);
+ }
+#ifdef MAP_32BIT
+ /* Our test audit module maps everything to lower 32bit. */
+ if ((unsigned long)info.dli_fbase >= 0x100000000)
+ {
+ printf ("premap audit didn't work\n");
+ exit (EXIT_FAILURE);
+ }
+#endif
xdlclose (h);
}
@@ -103,6 +117,14 @@ handle_restart (void)
printf ("dladdr failed\n");
exit (EXIT_FAILURE);
}
+#ifdef MAP_32BIT
+ /* Our test audit module maps everything to lower 32bit. */
+ if ((unsigned long)info.dli_fbase >= 0x100000000)
+ {
+ printf ("premap audit didn't work\n");
+ exit (EXIT_FAILURE);
+ }
+#endif
fprintf (stderr, "offset bar %lx\n", info.dli_saddr - info.dli_fbase);
/* write another value for parent to read */
*bar = TEST_BAR_VAL;
@@ -148,6 +170,7 @@ do_test (int argc, char *argv[])
{ "la_objsearch", false },
{ "la_activity", false },
{ "la_premap_dlmem", false },
+ { "la_premap", false },
{ "la_objopen", false },
{ "la_objclose", false },
{ "la_preinit", false },
@@ -91,6 +91,7 @@ do_test (int argc, char *argv[])
{ "la_version", false },
{ "la_objsearch", false },
{ "la_activity", false },
+ { "la_premap", false },
{ "la_objopen", false },
{ "la_objclose", false },
{ "la_preinit", false },
@@ -68,6 +68,22 @@ la_premap_dlmem (size_t maplength, uintptr_t *cookie)
return fd;
}
+void *
+la_premap (void *addr, size_t maplength, uintptr_t *cookie)
+{
+ void *ret = MAP_FAILED;
+ fprintf (stderr, "%s\n", __func__);
+ /* If addr already set by elf, don't change. */
+ if (addr)
+ return MAP_FAILED;
+#ifdef MAP_32BIT
+ /* This mapping will be overwritten so use PROT_NONE. */
+ ret = mmap(NULL, maplength, PROT_NONE,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
+#endif
+ return ret;
+}
+
unsigned int
la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
{
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <link.h>
+#include <sys/mman.h> // for MAP_FAILED
unsigned int
la_version (unsigned int version)
@@ -39,6 +40,13 @@ la_activity (uintptr_t *cookie, unsigned int flag)
fprintf (stderr, "%s\n", __func__);
}
+void *
+la_premap (void *addr, size_t mapsize, uintptr_t *cookie)
+{
+ fprintf (stderr, "%s\n", __func__);
+ return MAP_FAILED;
+}
+
unsigned int
la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie)
{
@@ -240,6 +240,7 @@ struct audit_ifaces
void (*activity) (uintptr_t *, unsigned int);
char *(*objsearch) (const char *, uintptr_t *, unsigned int);
int (*premap_dlmem) (size_t, uintptr_t *);
+ void *(*premap) (void *, size_t, uintptr_t *);
unsigned int (*objopen) (struct link_map *, Lmid_t, uintptr_t *);
void (*preinit) (uintptr_t *);
union
@@ -1373,6 +1374,11 @@ void _dl_audit_activity_nsid (Lmid_t nsid, int action)
int _dl_audit_premap_dlmem (struct link_map *l, size_t maplength)
attribute_hidden;
+/* Call la_premap from the audit modules from the link map and
+ get back an address to which the solib will be mapped. */
+void *_dl_audit_premap (struct link_map *l, void *pref_addr, size_t maplength)
+ attribute_hidden;
+
/* Call the la_objopen from the audit modules for the link_map L on the
namespace identification NSID. */
void _dl_audit_objopen (struct link_map *l, Lmid_t nsid)
This patch adds _dl_audit_premap() function that calls la_premap audit call-back. That call-back takes the preferred map address and map length, and gives back the address to where the solib should actually be mapped. In tst-auditmod-dlmem.c add such call-back as an example and use MAP_32BIT flag in it to force the mapping into the low 4G of address space. Also add it to tst-auditmod18.c as dummy and make sure it is called. Signed-off-by: Stas Sergeev <stsp2@yandex.ru> --- elf/dl-audit.c | 22 ++++++++++++++++++++++ elf/dl-map-segments.h | 22 ++++++++++++++++++---- elf/link.h | 2 ++ elf/rtld.c | 3 ++- elf/tst-audit-dlmem.c | 23 +++++++++++++++++++++++ elf/tst-audit18.c | 1 + elf/tst-auditmod-dlmem.c | 16 ++++++++++++++++ elf/tst-auditmod18.c | 8 ++++++++ sysdeps/generic/ldsodefs.h | 6 ++++++ 9 files changed, 98 insertions(+), 5 deletions(-)