/* Map in a shared object's segments from the file.
- Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
#include "dynamic-link.h"
#include <abi-tag.h>
#include <stackinfo.h>
-#include <caller.h>
#include <sysdep.h>
#include <stap-probe.h>
+#include <libc-pointer-arith.h>
+#include <array_length.h>
#include <dl-dst.h>
#include <dl-load.h>
#include <dl-map-segments.h>
#include <dl-unmap-segments.h>
#include <dl-machine-reject-phdr.h>
+#include <dl-sysdep-open.h>
#include <endian.h>
static size_t max_capstrlen attribute_relro;
-/* Get the generated information about the trusted directories. */
+/* Get the generated information about the trusted directories. Use
+ an array of concatenated strings to avoid relocations. See
+ gen-trusted-dirs.awk. */
#include "trusted-dirs.h"
static const char system_dirs[] = SYSTEM_DIRS;
{
SYSTEM_DIRS_LEN
};
-#define nsystem_dirs_len \
- (sizeof (system_dirs_len) / sizeof (system_dirs_len[0]))
-
-
-static bool
-is_trusted_path (const char *path, size_t len)
-{
- const char *trun = system_dirs;
-
- for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
- {
- if (len == system_dirs_len[idx] && memcmp (trun, path, len) == 0)
- /* Found it. */
- return true;
-
- trun += system_dirs_len[idx] + 1;
- }
-
- return false;
-}
-
+#define nsystem_dirs_len array_length (system_dirs_len)
static bool
is_trusted_path_normalize (const char *path, size_t len)
static size_t
-is_dst (const char *start, const char *name, const char *str,
- int is_path, int secure)
+is_dst (const char *start, const char *name, const char *str, int secure)
{
size_t len;
bool is_curly = false;
/* Skip over closing curly brace and adjust for the --name. */
len += 2;
}
- else if (name[len] != '\0' && name[len] != '/'
- && (!is_path || name[len] != ':'))
+ else if (name[len] != '\0' && name[len] != '/')
return 0;
if (__glibc_unlikely (secure)
- && ((name[len] != '\0' && name[len] != '/'
- && (!is_path || name[len] != ':'))
- || (name != start + 1 && (!is_path || name[-2] != ':'))))
+ && ((name[len] != '\0' && name[len] != '/')
+ || (name != start + 1)))
return 0;
return len;
size_t
-_dl_dst_count (const char *name, int is_path)
+_dl_dst_count (const char *name)
{
const char *const start = name;
size_t cnt = 0;
/* $ORIGIN is not expanded for SUID/GUID programs (except if it
is $ORIGIN alone) and it must always appear first in path. */
++name;
- if ((len = is_dst (start, name, "ORIGIN", is_path,
- __libc_enable_secure)) != 0
- || (len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0
- || (len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+ if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0
+ || (len = is_dst (start, name, "PLATFORM", 0)) != 0
+ || (len = is_dst (start, name, "LIB", 0)) != 0)
++cnt;
name = strchr (name + len, '$');
char *
-_dl_dst_substitute (struct link_map *l, const char *name, char *result,
- int is_path)
+_dl_dst_substitute (struct link_map *l, const char *name, char *result)
{
const char *const start = name;
size_t len;
++name;
- if ((len = is_dst (start, name, "ORIGIN", is_path,
- __libc_enable_secure)) != 0)
+ if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0)
{
repl = l->l_origin;
check_for_trusted = (__libc_enable_secure
&& l->l_type == lt_executable);
}
- else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
+ else if ((len = is_dst (start, name, "PLATFORM", 0)) != 0)
repl = GLRO(dl_platform);
- else if ((len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+ else if ((len = is_dst (start, name, "LIB", 0)) != 0)
repl = DL_DST_LIB;
if (repl != NULL && repl != (const char *) -1)
/* We cannot use this path element, the value of the
replacement is unknown. */
wp = last_elem;
- name += len;
- while (*name != '\0' && (!is_path || *name != ':'))
- ++name;
- /* Also skip following colon if this is the first rpath
- element, but keep an empty element at the end. */
- if (wp == result && is_path && *name == ':' && name[1] != '\0')
- ++name;
+ break;
}
else
/* No DST we recognize. */
else
{
*wp++ = *name++;
- if (is_path && *name == ':')
- {
- /* In SUID/SGID programs, after $ORIGIN expansion the
- normalized path must be rooted in one of the trusted
- directories. */
- if (__glibc_unlikely (check_for_trusted)
- && !is_trusted_path_normalize (last_elem, wp - last_elem))
- wp = last_elem;
- else
- last_elem = wp;
-
- check_for_trusted = false;
- }
}
}
while (*name != '\0');
belonging to the map is loaded. In this case the path element
containing $ORIGIN is left out. */
static char *
-expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
+expand_dynamic_string_token (struct link_map *l, const char *s)
{
/* We make two runs over the string. First we determine how large the
resulting string is and then we copy it over. Since this is no
char *result;
/* Determine the number of DST elements. */
- cnt = DL_DST_COUNT (s, is_path);
+ cnt = DL_DST_COUNT (s);
/* If we do not have to replace anything simply copy the string. */
if (__glibc_likely (cnt == 0))
if (result == NULL)
return NULL;
- return _dl_dst_substitute (l, s, result, is_path);
+ return _dl_dst_substitute (l, s, result);
}
be freed if the shared object already has this name.
Returns false if the object already had this name. */
static void
-internal_function
add_name_to_object (struct link_map *l, const char *name)
{
struct libname_list *lnp, *lastp;
static struct r_search_path_elem **
fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
- int check_trusted, const char *what, const char *where,
- struct link_map *l)
+ const char *what, const char *where, struct link_map *l)
{
char *cp;
size_t nelems = 0;
- char *to_free;
while ((cp = __strsep (&rpath, sep)) != NULL)
{
struct r_search_path_elem *dirp;
+ char *to_free = NULL;
+ size_t len = 0;
- to_free = cp = expand_dynamic_string_token (l, cp, 1);
-
- size_t len = strlen (cp);
-
- /* `strsep' can pass an empty string. This has to be
- interpreted as `use the current directory'. */
- if (len == 0)
+ /* `strsep' can pass an empty string. */
+ if (*cp != '\0')
{
- static const char curwd[] = "./";
- cp = (char *) curwd;
- }
+ to_free = cp = expand_dynamic_string_token (l, cp);
- /* Remove trailing slashes (except for "/"). */
- while (len > 1 && cp[len - 1] == '/')
- --len;
+ /* expand_dynamic_string_token can return NULL in case of empty
+ path or memory allocation failure. */
+ if (cp == NULL)
+ continue;
- /* Now add one if there is none so far. */
- if (len > 0 && cp[len - 1] != '/')
- cp[len++] = '/';
+ /* Compute the length after dynamic string token expansion and
+ ignore empty paths. */
+ len = strlen (cp);
+ if (len == 0)
+ {
+ free (to_free);
+ continue;
+ }
- /* Make sure we don't use untrusted directories if we run SUID. */
- if (__glibc_unlikely (check_trusted) && !is_trusted_path (cp, len))
- {
- free (to_free);
- continue;
+ /* Remove trailing slashes (except for "/"). */
+ while (len > 1 && cp[len - 1] == '/')
+ --len;
+
+ /* Now add one if there is none so far. */
+ if (len > 0 && cp[len - 1] != '/')
+ cp[len++] = '/';
}
/* See if this directory is already known. */
static bool
-internal_function
decompose_rpath (struct r_search_path_struct *sps,
const char *rpath, struct link_map *l, const char *what)
{
/* Make a copy we can work with. */
const char *where = l->l_name;
- char *copy;
char *cp;
struct r_search_path_elem **result;
size_t nelems;
while (*inhp != '\0');
}
+ /* Ignore empty rpaths. */
+ if (*rpath == '\0')
+ {
+ sps->dirs = (struct r_search_path_elem **) -1;
+ return false;
+ }
+
/* Make a writable copy. */
- copy = __strdup (rpath);
+ char *copy = __strdup (rpath);
if (copy == NULL)
{
errstring = N_("cannot create RUNPATH/RPATH copy");
goto signal_error;
}
- /* Ignore empty rpaths. */
- if (*copy == 0)
- {
- free (copy);
- sps->dirs = (struct r_search_path_elem **) -1;
- return false;
- }
-
/* Count the number of necessary elements in the result array. */
nelems = 0;
for (cp = copy; *cp != '\0'; ++cp)
_dl_signal_error (ENOMEM, NULL, NULL, errstring);
}
- fillin_rpath (copy, result, ":", 0, what, where, l);
+ fillin_rpath (copy, result, ":", what, where, l);
/* Free the copied RPATH string. `fillin_rpath' make own copies if
necessary. */
free (copy);
+ /* There is no path after expansion. */
+ if (result[0] == NULL)
+ {
+ free (result);
+ sps->dirs = (struct r_search_path_elem **) -1;
+ return false;
+ }
+
sps->dirs = result;
/* The caller will change this value if we haven't used a real malloc. */
sps->malloced = 1;
void
-internal_function
_dl_init_paths (const char *llp)
{
size_t idx;
+ ncapstr * sizeof (enum r_dir_status))
/ sizeof (struct r_search_path_elem));
- rtld_search_dirs.dirs[0] = (struct r_search_path_elem *)
- malloc ((sizeof (system_dirs) / sizeof (system_dirs[0]))
- * round_size * sizeof (struct r_search_path_elem));
+ rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size
+ * sizeof (*rtld_search_dirs.dirs[0]));
if (rtld_search_dirs.dirs[0] == NULL)
{
errstring = N_("cannot create cache for search path");
if (llp != NULL && *llp != '\0')
{
- size_t nllp;
- const char *cp = llp;
- char *llp_tmp;
-
-#ifdef SHARED
- /* Expand DSTs. */
- size_t cnt = DL_DST_COUNT (llp, 1);
- if (__glibc_likely (cnt == 0))
- llp_tmp = strdupa (llp);
- else
- {
- /* Determine the length of the substituted string. */
- size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt);
-
- /* Allocate the necessary memory. */
- llp_tmp = (char *) alloca (total + 1);
- llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1);
- }
-#else
- llp_tmp = strdupa (llp);
-#endif
+ char *llp_tmp = strdupa (llp);
/* Decompose the LD_LIBRARY_PATH contents. First determine how many
elements it has. */
- nllp = 1;
- while (*cp)
- {
- if (*cp == ':' || *cp == ';')
- ++nllp;
- ++cp;
- }
+ size_t nllp = 1;
+ for (const char *cp = llp_tmp; *cp != '\0'; ++cp)
+ if (*cp == ':' || *cp == ';')
+ ++nllp;
env_path_list.dirs = (struct r_search_path_elem **)
malloc ((nllp + 1) * sizeof (struct r_search_path_elem *));
}
(void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;",
- __libc_enable_secure, "LD_LIBRARY_PATH",
- NULL, l);
+ "LD_LIBRARY_PATH", NULL, l);
if (env_path_list.dirs[0] == NULL)
{
static
#endif
struct link_map *
-_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
- char *realname, struct link_map *loader, int l_type,
- int mode, void **stack_endp, Lmid_t nsid)
+_dl_map_object_from_fd (const char *name, const char *origname, int fd,
+ struct filebuf *fbp, char *realname,
+ struct link_map *loader, int l_type, int mode,
+ void **stack_endp, Lmid_t nsid)
{
struct link_map *l = NULL;
const ElfW(Ehdr) *header;
const ElfW(Phdr) *ph;
size_t maplength;
int type;
- struct stat64 st;
/* Initialize to keep the compiler happy. */
const char *errstring = NULL;
int errval = 0;
bool make_consistent = false;
/* Get file information. */
- if (__glibc_unlikely (__fxstat64 (_STAT_VER, fd, &st) < 0))
+ struct r_file_id id;
+ if (__glibc_unlikely (!_dl_get_file_id (fd, &id)))
{
errstring = N_("cannot stat shared object");
call_lose_errno:
}
/* Look again to see if the real name matched another already loaded. */
- for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
- if (l->l_removed == 0 && l->l_ino == st.st_ino && l->l_dev == st.st_dev)
+ for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
+ if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id))
{
/* The object is already loaded.
Just bump its reference count and return it. */
/* When loading into a namespace other than the base one we must
avoid loading ld.so since there can only be one copy. Ever. */
if (__glibc_unlikely (nsid != LM_ID_BASE)
- && ((st.st_ino == GL(dl_rtld_map).l_ino
- && st.st_dev == GL(dl_rtld_map).l_dev)
+ && (_dl_file_id_match_p (&id, &GL(dl_rtld_map).l_file_id)
|| _dl_name_match_p (name, &GL(dl_rtld_map))))
{
/* This is indeed ld.so. Create a new link_map which refers to
segments are mapped in. We record the addresses it says
verbatim, and later correct for the run-time load address. */
case PT_DYNAMIC:
- l->l_ld = (void *) ph->p_vaddr;
- l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+ if (ph->p_filesz)
+ {
+ /* Debuginfo only files from "objcopy --only-keep-debug"
+ contain a PT_DYNAMIC segment with p_filesz == 0. Skip
+ such a segment to avoid a crash later. */
+ l->l_ld = (void *) ph->p_vaddr;
+ l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+ }
break;
case PT_PHDR:
}
struct loadcmd *c = &loadcmds[nloadcmds++];
- c->mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
- c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
- & ~(GLRO(dl_pagesize) - 1));
+ c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize));
+ c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize));
c->dataend = ph->p_vaddr + ph->p_filesz;
c->allocend = ph->p_vaddr + ph->p_memsz;
- c->mapoff = ph->p_offset & ~(GLRO(dl_pagesize) - 1);
+ c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize));
/* Determine whether there is a gap between the last segment
and this one. */
}
#ifdef SHARED
- if (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0)
- /* We are loading the executable itself when the dynamic linker
- was executed directly. The setup will happen later. */
- break;
-
-# ifdef _LIBC_REENTRANT
- /* In a static binary there is no way to tell if we dynamically
- loaded libpthread. */
- if (GL(dl_error_catch_tsd) == &_dl_initial_error_catch_tsd)
-# endif
+ /* We are loading the executable itself when the dynamic
+ linker was executed directly. The setup will happen
+ later. Otherwise, the TLS data structures are already
+ initialized, and we assigned a TLS modid above. */
+ assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
+#else
+ assert (false && "TLS not initialized in static application");
#endif
- {
- /* We have not yet loaded libpthread.
- We can do the TLS setup right now! */
-
- void *tcb;
-
- /* The first call allocates TLS bookkeeping data structures.
- Then we allocate the TCB for the initial thread. */
- if (__glibc_unlikely (_dl_tls_setup ())
- || __glibc_unlikely ((tcb = _dl_allocate_tls (NULL)) == NULL))
- {
- errval = ENOMEM;
- errstring = N_("\
-cannot allocate TLS data structures for initial thread");
- goto call_lose;
- }
-
- /* Now we install the TCB in the thread register. */
- errstring = TLS_INIT_TP (tcb);
- if (__glibc_likely (errstring == NULL))
- {
- /* Now we are all good. */
- l->l_tls_modid = ++GL(dl_tls_max_dtv_idx);
- break;
- }
-
- /* The kernel is too old or somesuch. */
- errval = 0;
- _dl_deallocate_tls (tcb, 1);
- goto call_lose;
- }
-
- /* Uh-oh, the binary expects TLS support but we cannot
- provide it. */
- errval = 0;
- errstring = N_("cannot handle TLS data");
- goto call_lose;
break;
case PT_GNU_STACK:
l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr
*/
errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds,
- maplength, has_holes, loader);
+ maplength, has_holes, loader);
if (__glibc_unlikely (errstring != NULL))
goto call_lose;
}
if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
{
- if (__glibc_unlikely (__check_caller (RETURN_ADDRESS (0), allow_ldso) != 0))
- {
- errstring = N_("invalid caller");
- goto call_lose;
- }
-
/* The stack is presently not executable, but this module
requires that it be executable. We must change the
protection of the variable which contains the flags used in
GL(dl_initfirst) = l;
/* Finally the file information. */
- l->l_dev = st.st_dev;
- l->l_ino = st.st_ino;
+ l->l_file_id = id;
+
+#ifdef SHARED
+ /* When auditing is used the recorded names might not include the
+ name by which the DSO is actually known. Add that as well. */
+ if (__glibc_unlikely (origname != NULL))
+ add_name_to_object (l, origname);
+#else
+ /* Audit modules only exist when linking is dynamic so ORIGNAME
+ cannot be non-NULL. */
+ assert (origname == NULL);
+#endif
/* When we profile the SONAME might be needed for something else but
loading. Add it right away. */
ignore only ELF files for other architectures. Non-ELF files and
ELF files with different header information cause fatal errors since
this could mean there is something wrong in the installation and the
- user might want to know about this. */
+ user might want to know about this.
+
+ If FD is not -1, then the file is already open and FD refers to it.
+ In that case, FD is consumed for both successful and error returns. */
static int
-open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
+open_verify (const char *name, int fd,
+ struct filebuf *fbp, struct link_map *loader,
int whatcode, int mode, bool *found_other_class, bool free_name)
{
/* This is the expected ELF header. */
if (__glibc_unlikely (GLRO(dl_naudit) > 0) && whatcode != 0
&& loader->l_auditing == 0)
{
+ const char *original_name = name;
struct audit_ifaces *afct = GLRO(dl_audit);
for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
{
afct = afct->next;
}
+
+ if (fd != -1 && name != original_name && strcmp (name, original_name))
+ {
+ /* An audit library changed what we're supposed to open,
+ so FD no longer matches it. */
+ __close (fd);
+ fd = -1;
+ }
}
#endif
- /* Open the file. We always open files read-only. */
- int fd = __open (name, O_RDONLY | O_CLOEXEC);
+ if (fd == -1)
+ /* Open the file. We always open files read-only. */
+ fd = __open (name, O_RDONLY | O_CLOEXEC);
+
if (fd != -1)
{
ElfW(Ehdr) *ehdr;
ElfW(Phdr) *phdr, *ph;
ElfW(Word) *abi_note;
+ ElfW(Word) *abi_note_malloced = NULL;
unsigned int osversion;
size_t maplength;
if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
{
ElfW(Addr) size = ph->p_filesz;
+ /* NB: Some PT_NOTE segment may have alignment value of 0
+ or 1. gABI specifies that PT_NOTE segments should be
+ aligned to 4 bytes in 32-bit objects and to 8 bytes in
+ 64-bit objects. As a Linux extension, we also support
+ 4 byte alignment in 64-bit objects. If p_align is less
+ than 4, we treate alignment as 4 bytes since some note
+ segments have 0 or 1 byte alignment. */
+ ElfW(Addr) align = ph->p_align;
+ if (align < 4)
+ align = 4;
+ else if (align != 4 && align != 8)
+ continue;
if (ph->p_offset + size <= (size_t) fbp->len)
abi_note = (void *) (fbp->buf + ph->p_offset);
else
{
- abi_note = alloca (size);
+ /* Note: __libc_use_alloca is not usable here, because
+ thread info may not have been set up yet. */
+ if (size < __MAX_ALLOCA_CUTOFF)
+ abi_note = alloca (size);
+ else
+ {
+ /* There could be multiple PT_NOTEs. */
+ abi_note_malloced = realloc (abi_note_malloced, size);
+ if (abi_note_malloced == NULL)
+ goto read_error;
+
+ abi_note = abi_note_malloced;
+ }
__lseek (fd, ph->p_offset, SEEK_SET);
if (__libc_read (fd, (void *) abi_note, size) != size)
- goto read_error;
+ {
+ free (abi_note_malloced);
+ goto read_error;
+ }
}
while (memcmp (abi_note, &expected_note, sizeof (expected_note)))
{
-#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word)))
- ElfW(Addr) note_size = 3 * sizeof (ElfW(Word))
- + ROUND (abi_note[0])
- + ROUND (abi_note[1]);
+ ElfW(Addr) note_size
+ = ELF_NOTE_NEXT_OFFSET (abi_note[0], abi_note[1],
+ align);
if (size - 32 < note_size)
{
break;
}
+ free (abi_note_malloced);
}
return fd;
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
_dl_debug_printf (" trying file=%s\n", buf);
- fd = open_verify (buf, fbp, loader, whatcode, mode,
+ fd = open_verify (buf, -1, fbp, loader, whatcode, mode,
found_other_class, false);
if (this_dir->status[cnt] == unknown)
{
if (sps->malloced)
free (sps->dirs);
- /* rtld_search_dirs is attribute_relro, therefore avoid writing
- into it. */
- if (sps != &rtld_search_dirs)
+ /* rtld_search_dirs and env_path_list are attribute_relro, therefore
+ avoid writing into it. */
+ if (sps != &rtld_search_dirs && sps != &env_path_list)
sps->dirs = (void *) -1;
}
/* Map in the shared object file NAME. */
struct link_map *
-internal_function
_dl_map_object (struct link_map *loader, const char *name,
int type, int trace_mode, int mode, Lmid_t nsid)
{
int fd;
+ const char *origname = NULL;
char *realname;
char *name_copy;
struct link_map *l;
{
if (afct->objsearch != NULL)
{
+ const char *before = name;
name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
LA_SER_ORIG);
if (name == NULL)
fd = -1;
goto no_file;
}
+ if (before != name && strcmp (before, name) != 0)
+ {
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("audit changed filename %s -> %s\n",
+ before, name);
+
+ if (origname == NULL)
+ origname = before;
+ }
}
afct = afct->next;
&loader->l_runpath_dirs, &realname, &fb, loader,
LA_SER_RUNPATH, &found_other_class);
+ if (fd == -1)
+ {
+ realname = _dl_sysdep_open_object (name, namelen, &fd);
+ if (realname != NULL)
+ {
+ fd = open_verify (realname, fd,
+ &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
+ LA_SER_CONFIG, mode, &found_other_class,
+ false);
+ if (fd == -1)
+ free (realname);
+ }
+ }
+
#ifdef USE_LDCONFIG
if (fd == -1
&& (__glibc_likely ((mode & __RTLD_SECURE) == 0)
if (cached != NULL)
{
- fd = open_verify (cached,
+ fd = open_verify (cached, -1,
&fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
LA_SER_CONFIG, mode, &found_other_class,
false);
{
/* The path may contain dynamic string tokens. */
realname = (loader
- ? expand_dynamic_string_token (loader, name, 0)
+ ? expand_dynamic_string_token (loader, name)
: __strdup (name));
if (realname == NULL)
fd = -1;
else
{
- fd = open_verify (realname, &fb,
+ fd = open_verify (realname, -1, &fb,
loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode,
&found_other_class, true);
if (__glibc_unlikely (fd == -1))
}
void *stack_end = __libc_stack_end;
- return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode,
- &stack_end, nsid);
+ return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
+ type, mode, &stack_end, nsid);
}
struct add_path_state
}
void
-internal_function
_dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
{
if (counting)