Message ID | 20210209171839.7911-17-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: > Audit libraries should not participate in DSO sharing: In > particular libraries tagged with DF_GNU_1_UNIQUE should not > be shared between the audit namespace and any others - they > should get their own copy. > > This is signalled to the loader code by passing the RTLD_ISOLATE > flag from the relevant entry point in the dl modes argument. > --- > bits/dlfcn.h | 3 +++ > elf/dl-load.c | 5 +++-- > elf/dl-open.c | 13 +++++++++++-- > elf/rtld.c | 2 +- > sysdeps/mips/bits/dlfcn.h | 3 +++ > 5 files changed, 21 insertions(+), 5 deletions(-) > > diff --git a/bits/dlfcn.h b/bits/dlfcn.h > index 0daa789693..f910528b32 100644 > --- a/bits/dlfcn.h > +++ b/bits/dlfcn.h > @@ -32,6 +32,9 @@ > visible as if the object were linked directly into the program. */ > #define RTLD_GLOBAL 0x00100 > > +/* Suppress RTLD_SHARED and/or DF_GNU_1_UNIQUE. */ > +#define RTLD_ISOLATE 0x00040 > + > /* If the following bit is set in the MODE argument to dlmopen > then the target object is loaded into the main namespace (if > it is not already there) and a shallow copy (proxy) is placed Ok, the idea is to export the new flag to userpace. > diff --git a/elf/dl-load.c b/elf/dl-load.c > index 4e8e7ca031..44fd3b5489 100644 > --- a/elf/dl-load.c > +++ b/elf/dl-load.c > @@ -1079,7 +1079,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, > /* 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)) > + if (__glibc_unlikely ((nsid != LM_ID_BASE) && !(mode & RTLD_ISOLATE))) > { > /* 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) > @@ -1174,7 +1174,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, > > /* We need to check for DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE before we start > initialising any namespace dependent metatada. */ > - if (nsid != LM_ID_BASE) > + if (__glibc_unlikely ((nsid != LM_ID_BASE) && !(mode & RTLD_ISOLATE))) > { > /* Target DSO is flagged as unique: Make sure it gets loaded into > the base namespace. It is up to our caller to generate a proxy in Ok. > @@ -2188,6 +2188,7 @@ _dl_map_object (struct link_map *loader, const char *name, > > assert (nsid >= 0); > assert (nsid < GL(dl_nns)); > + assert (!((mode & RTLD_ISOLATE) && (mode & RTLD_SHARED))); > > #ifdef SHARED > /* Only need to do proxy checks if `nsid' is not LM_ID_BASE. */ > diff --git a/elf/dl-open.c b/elf/dl-open.c > index 38b3587d4a..d3c3e32be2 100644 > --- a/elf/dl-open.c > +++ b/elf/dl-open.c > @@ -485,9 +485,16 @@ dl_open_worker (void *a) > int mode = args->mode; > struct link_map *call_map = NULL; > struct link_map *preloaded = NULL; > - int want_proxy = mode & RTLD_SHARED; > + int want_proxy = 0; > + int dl_isolate = mode & RTLD_ISOLATE; Use 'bool' here. > Lmid_t proxy_ns = LM_ID_BASE; > > + /* Isolation means we should suppress all inter-namespace sharing. */ > + if (dl_isolate) > + mode &= ~RTLD_SHARED; > + else > + want_proxy = mode & RTLD_SHARED; > + Indentation seems off here (4 space instead of 2). > /* 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 > the new object in, or when the file name has no path in which > @@ -539,6 +546,7 @@ dl_open_worker (void *a) > mode and set want_proxy. > NOTE: RTLD_ISOLATE in the mode suppresses this behaviour. */ > if (__glibc_unlikely (args->nsid != LM_ID_BASE) && > + __glibc_likely (!dl_isolate) && > __glibc_likely (!want_proxy)) > { > preloaded = _dl_find_dso (file, LM_ID_BASE); > @@ -650,7 +658,8 @@ dl_open_worker (void *a) > > /* Load that object's dependencies. */ > _dl_map_object_deps (new, NULL, 0, 0, > - mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT)); > + mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT | > + RTLD_ISOLATE)); > > /* So far, so good. Now check the versions. */ Ok. > for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) > diff --git a/elf/rtld.c b/elf/rtld.c > index 596b6ac3d9..82069658b3 100644 > --- a/elf/rtld.c > +++ b/elf/rtld.c > @@ -659,7 +659,7 @@ dlmopen_doit (void *a) > struct dlmopen_args *args = (struct dlmopen_args *) a; > args->map = _dl_open (args->fname, > (RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT > - | __RTLD_SECURE), > + | __RTLD_SECURE | RTLD_ISOLATE), > dl_main, LM_ID_NEWLM, _dl_argc, _dl_argv, > __environ); > } > diff --git a/sysdeps/mips/bits/dlfcn.h b/sysdeps/mips/bits/dlfcn.h > index 1331771a17..a0a35bba5d 100644 > --- a/sysdeps/mips/bits/dlfcn.h > +++ b/sysdeps/mips/bits/dlfcn.h > @@ -39,6 +39,9 @@ > share a single instance of a DSO. */ > #define RTLD_SHARED 0x00020 > > +/* Suppress RTLD_SHARED and/or DF_GNU_1_UNIQUE. */ > +#define RTLD_ISOLATE 0x00040 > + > /* Unix98 demands the following flag which is the inverse to RTLD_GLOBAL. > The implementation does this by default and so we can define the > value to zero. */ > Ok.
diff --git a/bits/dlfcn.h b/bits/dlfcn.h index 0daa789693..f910528b32 100644 --- a/bits/dlfcn.h +++ b/bits/dlfcn.h @@ -32,6 +32,9 @@ visible as if the object were linked directly into the program. */ #define RTLD_GLOBAL 0x00100 +/* Suppress RTLD_SHARED and/or DF_GNU_1_UNIQUE. */ +#define RTLD_ISOLATE 0x00040 + /* If the following bit is set in the MODE argument to dlmopen then the target object is loaded into the main namespace (if it is not already there) and a shallow copy (proxy) is placed diff --git a/elf/dl-load.c b/elf/dl-load.c index 4e8e7ca031..44fd3b5489 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1079,7 +1079,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, /* 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)) + if (__glibc_unlikely ((nsid != LM_ID_BASE) && !(mode & RTLD_ISOLATE))) { /* 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) @@ -1174,7 +1174,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, /* We need to check for DT_GNU_FLAGS_1/DF_GNU_1_UNIQUE before we start initialising any namespace dependent metatada. */ - if (nsid != LM_ID_BASE) + if (__glibc_unlikely ((nsid != LM_ID_BASE) && !(mode & RTLD_ISOLATE))) { /* Target DSO is flagged as unique: Make sure it gets loaded into the base namespace. It is up to our caller to generate a proxy in @@ -2188,6 +2188,7 @@ _dl_map_object (struct link_map *loader, const char *name, assert (nsid >= 0); assert (nsid < GL(dl_nns)); + assert (!((mode & RTLD_ISOLATE) && (mode & RTLD_SHARED))); #ifdef SHARED /* Only need to do proxy checks if `nsid' is not LM_ID_BASE. */ diff --git a/elf/dl-open.c b/elf/dl-open.c index 38b3587d4a..d3c3e32be2 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -485,9 +485,16 @@ dl_open_worker (void *a) int mode = args->mode; struct link_map *call_map = NULL; struct link_map *preloaded = NULL; - int want_proxy = mode & RTLD_SHARED; + int want_proxy = 0; + int dl_isolate = mode & RTLD_ISOLATE; Lmid_t proxy_ns = LM_ID_BASE; + /* Isolation means we should suppress all inter-namespace sharing. */ + if (dl_isolate) + mode &= ~RTLD_SHARED; + else + want_proxy = mode & RTLD_SHARED; + /* 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 the new object in, or when the file name has no path in which @@ -539,6 +546,7 @@ dl_open_worker (void *a) mode and set want_proxy. NOTE: RTLD_ISOLATE in the mode suppresses this behaviour. */ if (__glibc_unlikely (args->nsid != LM_ID_BASE) && + __glibc_likely (!dl_isolate) && __glibc_likely (!want_proxy)) { preloaded = _dl_find_dso (file, LM_ID_BASE); @@ -650,7 +658,8 @@ dl_open_worker (void *a) /* Load that object's dependencies. */ _dl_map_object_deps (new, NULL, 0, 0, - mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT)); + mode & (__RTLD_DLOPEN | RTLD_DEEPBIND | __RTLD_AUDIT | + RTLD_ISOLATE)); /* So far, so good. Now check the versions. */ for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i) diff --git a/elf/rtld.c b/elf/rtld.c index 596b6ac3d9..82069658b3 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -659,7 +659,7 @@ dlmopen_doit (void *a) struct dlmopen_args *args = (struct dlmopen_args *) a; args->map = _dl_open (args->fname, (RTLD_LAZY | __RTLD_DLOPEN | __RTLD_AUDIT - | __RTLD_SECURE), + | __RTLD_SECURE | RTLD_ISOLATE), dl_main, LM_ID_NEWLM, _dl_argc, _dl_argv, __environ); } diff --git a/sysdeps/mips/bits/dlfcn.h b/sysdeps/mips/bits/dlfcn.h index 1331771a17..a0a35bba5d 100644 --- a/sysdeps/mips/bits/dlfcn.h +++ b/sysdeps/mips/bits/dlfcn.h @@ -39,6 +39,9 @@ share a single instance of a DSO. */ #define RTLD_SHARED 0x00020 +/* Suppress RTLD_SHARED and/or DF_GNU_1_UNIQUE. */ +#define RTLD_ISOLATE 0x00040 + /* Unix98 demands the following flag which is the inverse to RTLD_GLOBAL. The implementation does this by default and so we can define the value to zero. */