If a DSO has not already been loaded and the target is not the main
namespace then we must check to see if it's been DF_1_UNIQUE tagged
and load it into the main namespace instead.
dl_open_worker has alread been modified to notice the discrepancy
between the request and the result in such cases, and will set up
a proxy in the target namespace.
---
elf/dl-load.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 86 insertions(+), 14 deletions(-)
@@ -827,6 +827,63 @@ _dl_init_paths (const char *llp)
env_path_list.dirs = (void *) -1;
}
+static ElfW(Word)
+_get_dt_flags (int fd, const ElfW(Ehdr) *header, const ElfW(Phdr) *phdr)
+{
+ ElfW(Word) flags = 0;
+ const ElfW(Phdr) *ph;
+ ElfW(Dyn) entry = {};
+ off_t reset;
+ off_t pos;
+ off_t end;
+
+ reset = __lseek (fd, 0, SEEK_CUR);
+
+ for (ph = phdr; ph < &phdr[header->e_phnum]; ++ph)
+ {
+ switch (ph->p_type)
+ {
+ case PT_DYNAMIC:
+ // dt_flags_1 = get_dt_flags_1( fd, ph->p_offset, ph->p_filesz );
+ pos = __lseek (fd, ph->p_offset, SEEK_SET);
+ end = pos + ph->p_filesz;
+
+ while (pos < end)
+ {
+ ssize_t rb = 0;
+ do
+ {
+ ssize_t rretl = __read_nocancel (fd, &entry + rb,
+ sizeof (ElfW(Dyn)) - rb);
+ if (rretl <= 0)
+ goto cleanup;
+
+ rb += rretl;
+ }
+ while (__glibc_unlikely (rb < sizeof (ElfW(Dyn))));
+
+ switch (entry.d_tag)
+ {
+ case DT_FLAGS_1:
+ flags = entry.d_un.d_val;
+ case DT_NULL:
+ goto cleanup;
+ break;
+ default:
+ break;
+ }
+ pos += rb;
+ }
+ break;
+ }
+ }
+
+ cleanup:
+ /* Put the file descriptor offset back where it was when we were called. */
+ __lseek (fd, reset, SEEK_SET);
+
+ return flags;
+}
static void
__attribute__ ((noreturn, noinline))
@@ -868,6 +925,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
const ElfW(Ehdr) *header;
const ElfW(Phdr) *phdr;
const ElfW(Phdr) *ph;
+ ElfW(Word) dt_flags_1 = 0;
size_t maplength;
int type;
/* Initialize to keep the compiler happy. */
@@ -1019,6 +1077,34 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
else
assert (r->r_state == RT_ADD);
+ /* Load the ELF header using preallocated struct space if it's big enough. */
+ maplength = header->e_phnum * sizeof (ElfW(Phdr));
+ if (header->e_phoff + maplength <= (size_t) fbp->len)
+ phdr = (void *) (fbp->buf + header->e_phoff);
+ else
+ {
+ phdr = alloca (maplength);
+ if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength,
+ header->e_phoff) != maplength)
+ {
+ errstring = N_("cannot read file data");
+ goto call_lose_errno;
+ }
+ }
+
+ /* We need to check for DT_FLAGS_1 & DF_1_UNIQUE before we start
+ initialising any namespace dependent metatada. */
+ if (nsid != LM_ID_BASE)
+ {
+ dt_flags_1 = _get_dt_flags (fd, header, phdr);
+
+ /* Target DSO is flagged as unique: Make sure it gets loaded into
+ the base namespace. It is up to our caller to generate a proxy in
+ the target nsid. */
+ if (dt_flags_1 & DF_1_UNIQUE)
+ nsid = LM_ID_BASE;
+ }
+
/* Enter the new object in the list of loaded objects. */
l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
if (__glibc_unlikely (l == NULL))
@@ -1036,20 +1122,6 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
type = header->e_type;
l->l_phnum = header->e_phnum;
- maplength = header->e_phnum * sizeof (ElfW(Phdr));
- if (header->e_phoff + maplength <= (size_t) fbp->len)
- phdr = (void *) (fbp->buf + header->e_phoff);
- else
- {
- phdr = alloca (maplength);
- if ((size_t) __pread64_nocancel (fd, (void *) phdr, maplength,
- header->e_phoff) != maplength)
- {
- errstring = N_("cannot read file data");
- goto call_lose_errno;
- }
- }
-
/* On most platforms presume that PT_GNU_STACK is absent and the stack is
* executable. Other platforms default to a nonexecutable stack and don't
* need PT_GNU_STACK to do so. */