Message ID | 20210209171839.7911-12-vivek@collabora.com |
---|---|
State | New |
Headers | show |
Series | Implementation of RTLD_SHARED for dlmopen | expand |
On 09/02/2021 14:18, Vivek Das Mohapatra via Libc-alpha wrote: > If _dl_map_object_from_fd finds that a DSO it was asked to > load into a non-base namespace is already loaded (into the > main namespace) and is flagged DF_GNU_1_UNIQUE then it should > return that DSO's link map entry. > > In such cases _dl_open_worker must notice that this has > happened and dontinue down the link map proxy generation s/dontinue/continue. > path instead of normal link map entry preparation. > --- > elf/dl-load.c | 26 ++++++++++++++++++++++++++ > elf/dl-open.c | 10 ++++++++++ > 2 files changed, 36 insertions(+) > > diff --git a/elf/dl-load.c b/elf/dl-load.c > index 2a01ab7ad2..780bca99e8 100644 > --- a/elf/dl-load.c > +++ b/elf/dl-load.c > @@ -1020,6 +1020,32 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, > } > #endif > > + /* DSOs in the main namespace which are flagged DF_GNU_1_UNIQUE should only > + be opened into the main namespace. Other namespaces should only get > + proxies. */ > + if (__glibc_unlikely (nsid != LM_ID_BASE)) > + { > + /* Check base ns to see if the name matched another already loaded. */ > + for (l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l != NULL; l = l->l_next) > + if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id)) > + { > + if (!(l->l_gnu_flags_1 & DF_GNU_1_UNIQUE)) > + continue; > + > + /* Already loaded. Bump its reference count and return it. */ > + __close_nocancel (fd); > + > + /* If the name is not listed for this object add it. */ > + free (realname); > + add_name_to_object (l, name); > + > + /* NOTE: It is important that our caller picks up on the fact > + that we have NOT returned an object in the requested namespace > + and handles the proxying correctly */ Missing period and double space before comment end. > + return l; > + } > + } > + > if (mode & RTLD_NOLOAD) > { > /* We are not supposed to load the object unless it is already > diff --git a/elf/dl-open.c b/elf/dl-open.c > index 096aa4c680..441b8b1330 100644 > --- a/elf/dl-open.c > +++ b/elf/dl-open.c > @@ -561,6 +561,16 @@ dl_open_worker (void *a) > return; > } > > + /* If we are trying to load a DF_GNU_1_UNIQUE flagged DSO which was > + NOT ALREADY LOADED (or not loaded with the name we are using) then > + _dl_map_object will have returned an instance from the main namespace. > + We need to detect this and set up the RTLD_SHARED flags. */ > + if (__glibc_unlikely(args->nsid != LM_ID_BASE && new->l_ns == LM_ID_BASE)) Space before '(' > + { > + want_proxy = RTLD_SHARED; > + mode |= RTLD_SHARED; > + } > + > /* 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. */ >
diff --git a/elf/dl-load.c b/elf/dl-load.c index 2a01ab7ad2..780bca99e8 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1020,6 +1020,32 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, } #endif + /* DSOs in the main namespace which are flagged DF_GNU_1_UNIQUE should only + be opened into the main namespace. Other namespaces should only get + proxies. */ + if (__glibc_unlikely (nsid != LM_ID_BASE)) + { + /* Check base ns to see if the name matched another already loaded. */ + for (l = GL(dl_ns)[LM_ID_BASE]._ns_loaded; l != NULL; l = l->l_next) + if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id)) + { + if (!(l->l_gnu_flags_1 & DF_GNU_1_UNIQUE)) + continue; + + /* Already loaded. Bump its reference count and return it. */ + __close_nocancel (fd); + + /* If the name is not listed for this object add it. */ + free (realname); + add_name_to_object (l, name); + + /* NOTE: It is important that our caller picks up on the fact + that we have NOT returned an object in the requested namespace + and handles the proxying correctly */ + return l; + } + } + if (mode & RTLD_NOLOAD) { /* We are not supposed to load the object unless it is already diff --git a/elf/dl-open.c b/elf/dl-open.c index 096aa4c680..441b8b1330 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -561,6 +561,16 @@ dl_open_worker (void *a) return; } + /* If we are trying to load a DF_GNU_1_UNIQUE flagged DSO which was + NOT ALREADY LOADED (or not loaded with the name we are using) then + _dl_map_object will have returned an instance from the main namespace. + We need to detect this and set up the RTLD_SHARED flags. */ + if (__glibc_unlikely(args->nsid != LM_ID_BASE && new->l_ns == LM_ID_BASE)) + { + want_proxy = RTLD_SHARED; + mode |= RTLD_SHARED; + } + /* 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. */