From patchwork Sun Feb 24 16:01:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 1047520 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-100239-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="lre6bs8a"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 446qb63WGWz9s71 for ; Mon, 25 Feb 2019 03:02:10 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:mime-version :content-transfer-encoding; q=dns; s=default; b=TyBo963lg9tAWAR4 oF52+yaYDQBn9MHq9xVcB+BE73AraYRTtFGQRIPSe+lrtlXtXyoHjIs1HNX+1tki wPktpoPYiOO8lNY5nqjQNHInHLzGkIRRq+GDmbzQDsO3O6RhtPtNGdaqxWthcDKI RapHjl9bruEpU2T9gzrZSnsz3FI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:subject:date:message-id:mime-version :content-transfer-encoding; s=default; bh=25xXaaFlw9YxynUOMrIqFX IBxTc=; b=lre6bs8a7iA4fmjk1jx8R5kn8gq3LtPfi70PjiqwSqnMYU+BjSb4ld HC/IxOvHD7LghESmUgwbTOl0u/8f2IlPU+1D4nXMZ7vZSLrz7Bw2i2fZAj7JSMQb IDdFG/XOShJ4IzNc4FnNXT1Gyk9KKd+xjcJn84R36CWzUWShV9Pc0= Received: (qmail 36863 invoked by alias); 24 Feb 2019 16:02:04 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 36836 invoked by uid 89); 24 Feb 2019 16:02:03 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.2 required=5.0 tests=BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_SOFTFAIL autolearn=ham version=3.3.2 spammy=5411, scenario, distributed X-HELO: mga07.intel.com From: "H.J. Lu" To: libc-alpha@sourceware.org Subject: [PATCH] Call _dl_open_check after relocation is finished [BZ #24259] Date: Sun, 24 Feb 2019 08:01:59 -0800 Message-Id: <20190224160159.1804-1-hjl.tools@gmail.com> MIME-Version: 1.0 When dlopening a shared object, _dl_open_check will throw an exception if CET shadow stack is enabled and the shared object has no shadow stack support. dl_open_worker must call _dl_open_check after relocation is finished. Otherwise, the dependency shared objects may be mmapped without relocation. This will lead to run-time failure later when they are needed by another dlopened shared object which is shadow stack enabled. [BZ #24259] * elf/dl-open.c (dl_open_worker): Call _dl_open_check after relocation is finished. * sysdeps/x86/Makefile (tests): Add tst-cet-legacy-5a and tst-cet-legacy-5b. (modules-names): Add tst-cet-legacy-mod-5a and tst-cet-legacy-mod-5b. (CFLAGS-tst-cet-legacy-5a.c): New. (CFLAGS-tst-cet-legacy-5b.c): Likewise. (CFLAGS-tst-cet-legacy-mod-5a.c): Likewise. (CFLAGS-tst-cet-legacy-mod-5b.c): Likewise. ($(objpfx)tst-cet-legacy-5a): Likewise. ($(objpfx)tst-cet-legacy-5a.out): Likewise. ($(objpfx)tst-cet-legacy-mod-5a.so): Likewise. ($(objpfx)tst-cet-legacy-mod-5b.so): Likewise. ($(objpfx)tst-cet-legacy-5b): Likewise. ($(objpfx)tst-cet-legacy-5b.out): Likewise. (tst-cet-legacy-5b-ENV): Likewise. * sysdeps/x86/tst-cet-legacy-5.c: New file. * sysdeps/x86/tst-cet-legacy-5a.c: Likewise. * sysdeps/x86/tst-cet-legacy-5b.c: Likewise. * sysdeps/x86/tst-cet-legacy-mod-5.c: Likewise. * sysdeps/x86/tst-cet-legacy-mod-5a.c: Likewise. * sysdeps/x86/tst-cet-legacy-mod-5b.c: Likewise. --- elf/dl-open.c | 7 ++- sysdeps/x86/Makefile | 22 ++++++- sysdeps/x86/tst-cet-legacy-5.c | 76 ++++++++++++++++++++++++ sysdeps/x86/tst-cet-legacy-5a.c | 1 + sysdeps/x86/tst-cet-legacy-5b.c | 1 + sysdeps/x86/tst-cet-legacy-mod-5.c | 91 +++++++++++++++++++++++++++++ sysdeps/x86/tst-cet-legacy-mod-5a.c | 1 + sysdeps/x86/tst-cet-legacy-mod-5b.c | 1 + 8 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 sysdeps/x86/tst-cet-legacy-5.c create mode 100644 sysdeps/x86/tst-cet-legacy-5a.c create mode 100644 sysdeps/x86/tst-cet-legacy-5b.c create mode 100644 sysdeps/x86/tst-cet-legacy-mod-5.c create mode 100644 sysdeps/x86/tst-cet-legacy-mod-5a.c create mode 100644 sysdeps/x86/tst-cet-legacy-mod-5b.c diff --git a/elf/dl-open.c b/elf/dl-open.c index 12a4f8b853..a62cb91975 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -292,8 +292,6 @@ dl_open_worker (void *a) _dl_debug_state (); LIBC_PROBE (map_complete, 3, args->nsid, r, new); - _dl_open_check (new); - /* Print scope information. */ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES)) _dl_show_scope (new, 0); @@ -366,6 +364,11 @@ dl_open_worker (void *a) _dl_relocate_object (l, l->l_scope, reloc_mode, 0); } + /* NB: Since _dl_open_check may throw an exception, it must be called + after relocation is finished. Otherwise, a shared object may be + mapped without relocation. */ + _dl_open_check (new); + /* If the file is not loaded now as a dependency, add the search list of the newly loaded object to the scope. */ bool any_tls = false; diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile index 7ec46ca100..308bba80e5 100644 --- a/sysdeps/x86/Makefile +++ b/sysdeps/x86/Makefile @@ -19,13 +19,16 @@ ifeq ($(subdir),elf) sysdep-dl-routines += dl-cet tests += tst-cet-legacy-1 tst-cet-legacy-1a tst-cet-legacy-2 \ - tst-cet-legacy-2a tst-cet-legacy-3 tst-cet-legacy-4 + tst-cet-legacy-2a tst-cet-legacy-3 tst-cet-legacy-4 \ + tst-cet-legacy-5a tst-cet-legacy-1a-ARGS = -- $(host-test-program-cmd) ifneq (no,$(have-tunables)) -tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c +tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \ + tst-cet-legacy-5b endif modules-names += tst-cet-legacy-mod-1 tst-cet-legacy-mod-2 \ - tst-cet-legacy-mod-4 + tst-cet-legacy-mod-4 tst-cet-legacy-mod-5a \ + tst-cet-legacy-mod-5b CFLAGS-tst-cet-legacy-2.c += -fcf-protection=branch CFLAGS-tst-cet-legacy-2a.c += -fcf-protection @@ -36,6 +39,10 @@ CFLAGS-tst-cet-legacy-4.c += -fcf-protection=branch CFLAGS-tst-cet-legacy-4a.c += -fcf-protection CFLAGS-tst-cet-legacy-4b.c += -fcf-protection CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none +CFLAGS-tst-cet-legacy-5a.c += -fcf-protection +CFLAGS-tst-cet-legacy-5b.c += -fcf-protection +CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=none +CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \ $(objpfx)tst-cet-legacy-mod-2.so @@ -47,6 +54,11 @@ $(objpfx)tst-cet-legacy-2a: $(objpfx)tst-cet-legacy-mod-2.so $(libdl) $(objpfx)tst-cet-legacy-2a.out: $(objpfx)tst-cet-legacy-mod-1.so $(objpfx)tst-cet-legacy-4: $(libdl) $(objpfx)tst-cet-legacy-4.out: $(objpfx)tst-cet-legacy-mod-4.so +$(objpfx)tst-cet-legacy-5a: $(libdl) +$(objpfx)tst-cet-legacy-5a.out: $(objpfx)tst-cet-legacy-mod-5a.so \ + $(objpfx)tst-cet-legacy-mod-5b.so +$(objpfx)tst-cet-legacy-mod-5a.so: $(common-objpfx)nptl/libpthread.so +$(objpfx)tst-cet-legacy-mod-5b.so: $(common-objpfx)nptl/libpthread.so ifneq (no,$(have-tunables)) $(objpfx)tst-cet-legacy-4a: $(libdl) $(objpfx)tst-cet-legacy-4a.out: $(objpfx)tst-cet-legacy-mod-4.so @@ -57,6 +69,10 @@ tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=on $(objpfx)tst-cet-legacy-4c: $(libdl) $(objpfx)tst-cet-legacy-4c.out: $(objpfx)tst-cet-legacy-mod-4.so tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.cpu.x86_shstk=off +$(objpfx)tst-cet-legacy-5b: $(libdl) +$(objpfx)tst-cet-legacy-5b.out: $(objpfx)tst-cet-legacy-mod-5a.so \ + $(objpfx)tst-cet-legacy-mod-5b.so +tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.cpu.hwcaps=-IBT,-SHSTK endif endif diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c new file mode 100644 index 0000000000..fbf640f664 --- /dev/null +++ b/sysdeps/x86/tst-cet-legacy-5.c @@ -0,0 +1,76 @@ +/* Check compatibility of CET-enabled executable with dlopened legacy + shared object. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +static void +do_test_1 (const char *modname, bool fail) +{ + int (*fp) (void); + void *h; + + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + if (fail) + { + const char *err = dlerror (); + if (strstr (err, "shadow stack isn't enabled") == NULL) + { + printf ("incorrect dlopen '%s' error: %s\n", modname, + dlerror ()); + exit (1); + } + + return; + } + + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + fp = dlsym (h, "test"); + if (fp == NULL) + { + printf ("cannot get symbol 'test': %s\n", dlerror ()); + exit (1); + } + + if (fp () != 0) + { + puts ("test () != 0"); + exit (1); + } + + dlclose (h); +} + +static int +do_test (void) +{ + do_test_1 ("tst-cet-legacy-mod-5a.so", true); + do_test_1 ("tst-cet-legacy-mod-5b.so", false); + return 0; +} + +#include diff --git a/sysdeps/x86/tst-cet-legacy-5a.c b/sysdeps/x86/tst-cet-legacy-5a.c new file mode 100644 index 0000000000..fc5a609dff --- /dev/null +++ b/sysdeps/x86/tst-cet-legacy-5a.c @@ -0,0 +1 @@ +#include "tst-cet-legacy-5.c" diff --git a/sysdeps/x86/tst-cet-legacy-5b.c b/sysdeps/x86/tst-cet-legacy-5b.c new file mode 100644 index 0000000000..fc5a609dff --- /dev/null +++ b/sysdeps/x86/tst-cet-legacy-5b.c @@ -0,0 +1 @@ +#include "tst-cet-legacy-5.c" diff --git a/sysdeps/x86/tst-cet-legacy-mod-5.c b/sysdeps/x86/tst-cet-legacy-mod-5.c new file mode 100644 index 0000000000..38d0aaa727 --- /dev/null +++ b/sysdeps/x86/tst-cet-legacy-mod-5.c @@ -0,0 +1,91 @@ +/* Check compatibility of CET-enabled executable with dlopened legacy + shared object. + Copyright (C) 2019 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *p) +{ + int err; + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child: cannot get mutex"); + + puts ("child: got mutex; signalling"); + + pthread_cond_signal (&cond); + + puts ("child: unlock"); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child: cannot unlock"); + + puts ("child: done"); + + return NULL; +} + +int +test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + puts ("parent: get mutex"); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot get mutex"); + + puts ("parent: create child"); + + err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot create thread"); + + puts ("parent: wait for condition"); + + /* This test will fail on spurious wake-ups, which are allowed; however, + the current implementation shouldn't produce spurious wake-ups in the + scenario we are testing here. */ + err = pthread_cond_wait (&cond, &mut); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot wait fir signal"); + + puts ("parent: got signal"); + + err = pthread_join (th, NULL); + if (err != 0) + error (EXIT_FAILURE, err, "parent: failed to join"); + + puts ("done"); + + return 0; +} diff --git a/sysdeps/x86/tst-cet-legacy-mod-5a.c b/sysdeps/x86/tst-cet-legacy-mod-5a.c new file mode 100644 index 0000000000..daa43e4e8d --- /dev/null +++ b/sysdeps/x86/tst-cet-legacy-mod-5a.c @@ -0,0 +1 @@ +#include "tst-cet-legacy-mod-5.c" diff --git a/sysdeps/x86/tst-cet-legacy-mod-5b.c b/sysdeps/x86/tst-cet-legacy-mod-5b.c new file mode 100644 index 0000000000..daa43e4e8d --- /dev/null +++ b/sysdeps/x86/tst-cet-legacy-mod-5b.c @@ -0,0 +1 @@ +#include "tst-cet-legacy-mod-5.c"