From patchwork Mon Mar 30 17:43:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vivek Dasmohapatra X-Patchwork-Id: 38680 Return-Path: X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by sourceware.org (Postfix) with ESMTPS id 502B6388754A for ; Mon, 30 Mar 2020 17:44:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 502B6388754A Received: from noise.collabora.co.uk (unknown [IPv6:2a00:5f00:102:0:c0a7:51ff:feaf:e642]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: vivek) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 8D638296718; Mon, 30 Mar 2020 18:43:58 +0100 (BST) From: =?utf-8?q?Vivek_Das=C2=A0Mohapatra?= To: vivek@etla.org, libc-alpha@sourceware.org Subject: [RFC][PATCH v4 13/15] Suppress inter-namespace DSO sharing for audit libraries Date: Mon, 30 Mar 2020 18:43:47 +0100 Message-Id: X-Mailer: git-send-email 2.11.0 In-Reply-To: References: In-Reply-To: References: X-Spam-Status: No, score=-27.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 30 Mar 2020 17:44:02 -0000 Audit libraries should not participate in DSO sharing: In particular libraries tagged with DF_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 an internal __RTLD_ISOLATE flag from the relevant entry point in the dl modes argument. --- elf/dl-load.c | 5 +++-- elf/dl-open.c | 16 +++++++++++++--- elf/rtld.c | 2 +- include/dlfcn.h | 1 + 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index a2d78f8615..a3d4fc2ce0 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1002,7 +1002,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, /* DSOs in the main namespace which are flagged DF_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) @@ -1094,7 +1094,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, /* We need to check for DT_FLAGS_1 & DF_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))) { dt_flags_1 = _get_dt_flags (fd, header, phdr); @@ -2087,6 +2087,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 0197cd07e0..b3e9dbfe0d 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -477,9 +477,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 @@ -514,8 +521,10 @@ dl_open_worker (void *a) /* Target Lmid is not the base and we haven't explicitly asked for a proxy: We need to check for a matching DSO in the base Lmid in case it is flagged DF_1_UNIQUE in which case we add RTLD_SHARED to the mode and set - want_proxy. */ + 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); @@ -626,7 +635,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 553cfbd1b7..8b1734ed12 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -616,7 +616,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/include/dlfcn.h b/include/dlfcn.h index 93dd369ab1..6fb7a3c778 100644 --- a/include/dlfcn.h +++ b/include/dlfcn.h @@ -12,6 +12,7 @@ #define __RTLD_AUDIT 0x08000000 #define __RTLD_SECURE 0x04000000 /* Apply additional security checks. */ #define __RTLD_NOIFUNC 0x02000000 /* Suppress calling ifunc functions. */ +#define __RTLD_ISOLATE 0x01000000 /* Suppress RTLD_SHARED and/or DF_1_UNIQUE */ #define __LM_ID_CALLER -2