[RFC,3/5] elf/dl-object.c: Implement a helper function to clone link_map entries
Commit Message
Provides the minimal functionality needed to take an existing
link_map entry and create a clone of it in the specified namespace.
---
elf/dl-object.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++
sysdeps/generic/ldsodefs.h | 6 ++++
2 files changed, 84 insertions(+)
Comments
On Tue, 24 Apr 2018, Vivek Das Mohapatra wrote:
> +internal_function
Please send patches relative to current master (once the copyright
assignment is complete). There's no such thing as internal_function any
more.
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <ldsodefs.h>
+#include <libintl.h>
#include <assert.h>
@@ -50,6 +51,83 @@ _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
__rtld_lock_unlock_recursive (GL(dl_load_write_lock));
}
+/* Clone an existing link map entry into a new link map. */
+/* This is based on _dl_new_object, skipping the steps we know we won't need
+ because this is mostly just a shell for the l_real pointer holding the real
+ link map entry (normally l == l->l_real, but not for ld.so in non-main
+ link maps or RTLD_SHARED clones).
+ It also flags the clone by setting l_clone, and sets the the no-delete
+ flag in the original. */
+struct link_map *
+internal_function
+_dl_clone_object (struct link_map *old, int mode, Lmid_t nsid)
+{
+ const char *name;
+ struct link_map *new;
+ struct libname_list *newname;
+#ifdef SHARED
+ /* See _dl_new_object for how this number is arrived at: */
+ unsigned int na = GLRO(dl_naudit) ?: ((mode & __RTLD_OPENEXEC) ? DL_NNS : 0);
+ size_t audit_space = na * sizeof (new->l_audit[0]);
+#else
+# define audit_space 0
+#endif
+
+ name = old->l_name;
+
+ /* Don't clone a clone: Go to the progenitor. */
+ while (old && old->l_clone)
+ old = old->l_real;
+
+ if (old == NULL)
+ _dl_signal_error (EINVAL, name, NULL, N_("cannot clone NULL link_map"));
+
+ /* Object already exists in the target namespace. This should get handled
+ by dl_open_worker but just in case we get this far, handle it: */
+ if (__glibc_unlikely (old->l_ns == nsid))
+ {
+ /* Not actually possible, given the sanity checks above. */
+ if (old->l_clone)
+ return old;
+
+ _dl_signal_error (EEXIST, name, NULL,
+ N_("object cannot be demoted to a clone"));
+ }
+
+ /* Now duplicate as little of _dl_new_object as possible to get a
+ working cloned object in the target link map. */
+ new = (struct link_map *) calloc (sizeof (*new) + audit_space
+ + sizeof (struct link_map *)
+ + sizeof (*newname) + PATH_MAX, 1);
+
+ /* Specific to the clone. */
+ new->l_real = old;
+ new->l_clone = 1;
+ new->l_ns = nsid;
+
+ /* Copied from the origin. */
+ new->l_libname = old->l_libname;
+ new->l_name = old->l_name;
+ new->l_type = old->l_type;
+
+ if (__glibc_unlikely (mode & RTLD_NODELETE))
+ new->l_flags_1 |= DF_1_NODELETE;
+
+ /* Specific to the origin. Ideally we'd do some accounting here but
+ for now it's easier to pin the original so the clone remains valid. */
+ old->l_flags_1 |= DF_1_NODELETE;
+
+ /* Fix up the searchlist so that relocations work. */
+ /* TODO: figure out if we should call _dl_map_object_deps
+ or copy the contents of l_scope, l_searchlist et al. */
+ _dl_map_object_deps (new, NULL, 0, 0,
+ mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT));
+
+ /* And finally put the clone into the target namespace. */
+ _dl_add_to_namespace_list (new, nsid);
+
+ return new;
+}
/* Allocate a `struct link_map' for a new object being loaded,
and enter it into the _dl_loaded list. */
@@ -913,6 +913,12 @@ extern lookup_t _dl_lookup_symbol_x (const char *undef,
extern void _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid)
attribute_hidden;
+/* Clone an existing link map entry into a new link map */
+extern struct link_map *_dl_clone_object (struct link_map *old,
+ int mode,
+ Lmid_t nsid)
+ internal_function attribute_hidden;
+
/* Allocate a `struct link_map' for a new object being loaded. */
extern struct link_map *_dl_new_object (char *realname, const char *libname,
int type, struct link_map *loader,