@@ -1848,6 +1848,37 @@ open_path (const char *name, size_t namelen, int mode,
return -1;
}
+/* Search for a link map proxy in the given namespace by name.
+ Consider it to be an error if the found object is not a proxy. */
+struct link_map *
+_dl_find_proxy (Lmid_t nsid, const char *name)
+{
+ struct link_map *l;
+
+ for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
+ {
+ if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
+ continue;
+
+ if (!_dl_name_match_p (name, l))
+ continue;
+
+ /* We have a match - stop searching. */
+ break;
+ }
+
+ if (l)
+ {
+ if (l->l_proxy)
+ return l;
+
+ _dl_signal_error (EEXIST, name, NULL,
+ N_("object cannot be demoted to a proxy"));
+ }
+
+ return NULL;
+}
+
/* Map in the shared object file NAME. */
struct link_map *
@@ -1864,6 +1895,20 @@ _dl_map_object (struct link_map *loader, const char *name,
assert (nsid >= 0);
assert (nsid < GL(dl_nns));
+#ifdef SHARED
+ /* Only need to do proxy checks if `nsid' is not LM_ID_BASE. */
+ if (__glibc_unlikely ((mode & RTLD_SHARED) && (nsid != LM_ID_BASE)))
+ {
+ /* Search the namespace in case the object is already proxied. */
+ if((l = _dl_find_proxy (nsid, name)) != NULL)
+ return l;
+
+ /* Further searches should be in the base ns: We will proxy the
+ resulting object in dl_open_worker *after* it is initialised. */
+ nsid = LM_ID_BASE;
+ }
+#endif
+
/* Look for this name among those already loaded. */
for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
{
@@ -183,6 +183,8 @@ dl_open_worker (void *a)
const char *file = args->file;
int mode = args->mode;
struct link_map *call_map = NULL;
+ int want_proxy = mode & RTLD_SHARED;
+ Lmid_t proxy_ns = LM_ID_BASE;
/* Determine the caller's map if necessary. This is needed in case
we have a DST, when we don't know the namespace ID we have to put
@@ -237,6 +239,24 @@ dl_open_worker (void *a)
/* This object is directly loaded. */
++new->l_direct_opencount;
+ /* Proxy already existed in the target ns, nothing left to do. */
+ if (__glibc_unlikely (new->l_proxy))
+ {
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("proxied file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+ return;
+ }
+
+ /* If we want proxy and we get this far then the entry in ‘new’ will
+ be in the main namespace: we should revert to the main namespace code
+ path(s), but remember the namespace we want the proxy to be in. */
+ if (__glibc_unlikely (want_proxy))
+ {
+ proxy_ns = args->nsid;
+ args->nsid = LM_ID_BASE;
+ }
+
/* It was already open. */
if (__glibc_unlikely (new->l_searchlist.r_list != NULL))
{
@@ -252,6 +272,16 @@ dl_open_worker (void *a)
assert (_dl_debug_initialize (0, args->nsid)->r_state == RT_CONSISTENT);
+ if (__glibc_unlikely (want_proxy))
+ {
+ args->map = new = _dl_new_proxy (new, mode, proxy_ns);
+ ++new->l_direct_opencount;
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf ("proxying file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+ }
+
return;
}
@@ -509,6 +539,14 @@ TLS generation counter wrapped! Please report this."));
/* It failed. */
return;
+ if (__glibc_unlikely (want_proxy))
+ {
+ /* args->map is the return slot which the caller sees, but keep
+ the original value of new hanging around so we can see the
+ real link map entry (for logging etc). */
+ args->map = _dl_new_proxy (new, mode, proxy_ns);
+ ++args->map->l_direct_opencount;
+ }
#ifndef SHARED
/* We must be the static _dl_open in libc.a. A static program that
has loaded a dynamic object now has competition. */
@@ -517,8 +555,16 @@ TLS generation counter wrapped! Please report this."));
/* Let the user know about the opencount. */
if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
- _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
- new->l_name, new->l_ns, new->l_direct_opencount);
+ {
+ _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n",
+ new->l_name, new->l_ns, new->l_direct_opencount);
+
+ if (args->map->l_proxy)
+ _dl_debug_printf ("proxying file=%s [%lu]; direct_opencount=%u\n\n",
+ args->map->l_name,
+ args->map->l_ns,
+ args->map->l_direct_opencount);
+ }
}