Patchwork [2/3] dl-load: enforce soname uniqueness of loaded libraries

login
register
mail settings
Submitter Nicolas Viennot
Date Jan. 6, 2020, 3:44 p.m.
Message ID <8a449dd92e5f41189f95abbe803c82e3@EXMBDFT10.ad.twosigma.com>
Download mbox | patch
Permalink /patch/37214/
State New
Headers show

Comments

Nicolas Viennot - Jan. 6, 2020, 3:44 p.m.
When loading a new library of name `libname`, the loader currently
checks if any of the already loaded libraries have the soname `libname`.
If so, it returns the already loaded library of soname `libname`. If
not, it checks for the corresponding file `libname` on disk and compares
the device and inode number of already loaded libraries. If there is a
match, it returns the already loaded library of the same inode number.
If not, it proceeds to load the library of path is `libname`.

This patch adds the additional check of comparing the soname of the
newly loaded library with the sonames of already loaded libraries.

This new behavior enforces that no two loaded libaries have the same
soname, bringing a sane property in the system.

Note that this edge case can be encountered during a system upgrade, or
when using certain configuration of file system mounts, where inodes
cannot be relied upon.
---
 elf/dl-load.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

Patch

diff --git a/elf/dl-load.c b/elf/dl-load.c
index c436a447af..c5c997f95b 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -851,6 +851,8 @@  lose (int code, int fd, const char *name, char *realname, struct link_map *l,
   _dl_signal_error (code, name, NULL, msg);
 }
 
+static struct link_map *
+_dl_find_object_from_name(const char *name, Lmid_t nsid);
 
 /* Map in the shared object NAME, actually located in REALNAME, and already
    opened on FD.  */
@@ -1202,6 +1204,52 @@  _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 
   elf_get_dynamic_info (l, NULL);
 
+  /*
+   * Check if we have a loaded object with the same soname.  If that's the
+   * case, return the previously loaded object.  The loop follows a similar
+   * logic compared to the beginning of _dl_map_object().
+   * the loader assumes that the sonames of loaded objects are without
+   * duplicates.
+   */
+
+  if (l->l_info[DT_SONAME] != NULL)
+    {
+      static struct link_map *_l;
+      const char *soname;
+
+      soname = (((const char *) D_PTR (l, l_info[DT_STRTAB])
+		 + l->l_info[DT_SONAME]->d_un.d_val));
+
+      _l = _dl_find_object_from_name(soname, nsid);
+      if (__glibc_unlikely(_l != NULL))
+	{
+	  /* Free current object */
+	  _dl_unmap_segments (l);
+
+	  if (!l->l_libname->dont_free)
+	    free (l->l_libname);
+
+	  if (l->l_phdr_allocated)
+	    free ((void *) l->l_phdr);
+
+	  __close_nocancel (fd);
+	  if (l->l_origin != (char *) -1l)
+	    free ((char *) l->l_origin);
+	  free (l);
+	  free (realname);
+
+	  if (make_consistent)
+	    {
+	      r->r_state = RT_CONSISTENT;
+	      _dl_debug_state ();
+	    }
+
+	  /* Cache the name and return the previously loaded object */
+	  add_name_to_object (_l, name);
+	  return _l;
+	}
+    }
+
   /* Make sure we are not dlopen'ing an object that has the
      DF_1_NOOPEN flag set, or a PIE object.  */
   if ((__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)