From patchwork Mon Nov 6 20:25:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella Netto X-Patchwork-Id: 1860450 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=VlX/eLeR; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SPND76gyfz1yQ5 for ; Tue, 7 Nov 2023 07:26:31 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 92D7E385C6E4 for ; Mon, 6 Nov 2023 20:26:27 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-yw1-x1131.google.com (mail-yw1-x1131.google.com [IPv6:2607:f8b0:4864:20::1131]) by sourceware.org (Postfix) with ESMTPS id CF1F13858296 for ; Mon, 6 Nov 2023 20:26:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CF1F13858296 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linaro.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org CF1F13858296 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::1131 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699302369; cv=none; b=MFJmiAWdM5nxpNEuam/Qh2XKfXJJHfNTtMzO7AD7TQGL32eFRE4ATZtmNdUXqpKi9SaW75ubTUXTQaZyd1SxC/HKmvV+ICIuyUYb757lrG/wczu2kFoP4W2ISAsCzcJCd/kyEH2XcCMpIksa9HWBTs/vRqwyXxz5l8t7Ww9n/Y4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699302369; c=relaxed/simple; bh=bxMn5rEuoQuyNiOBpHXOfs8yCYpwXzBjxHO31sQy7BQ=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=nwyGfj24jWWRsdFDhxc1tNcYdp8BdbtZuEbXA7jb2xmQyYTxmZeBNQQH7fdOu2Ej71CUh8e0oLOUV7uyh5jRenR42aLQUNr1vqyfJRrS5Ppc1Cj9a3qZGn2jP/xuyv58R9VM9hPfGOt4WrVopD2rSG1DlWGD10D6LJ8tV4b3t9c= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-yw1-x1131.google.com with SMTP id 00721157ae682-5a84204e7aeso57699987b3.0 for ; Mon, 06 Nov 2023 12:26:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1699302366; x=1699907166; darn=sourceware.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=6YJuri5pn5IAmCMfSYxGyWFTy8wz3fHPNRZUOY0gJFY=; b=VlX/eLeRYifhK2jnz0eMnXgoZaXYkJgYADzkxwIqPOPsBxEsXoLwR5vE5N6/Sd+xhE td3p6+Jtdrhe7O7PMYsY9f1T8GlDx8oqkMjedfRvuHrtl73nmfVjneKzvwWXIF3JdVQ2 JCY6EWEAMRa9YZCafWqBKlcCsVhqibdrFgUPB3051f44SL7NiBoa4BtISuSdz0yOb/2u Z27gRmTNp+yOeYOclqTKdUnIyLsC6O7Li22uyxM3WqXzoSJ8jeJO/DQz8XnqrQrHDgMA qn451uH/Q8hkSeoxPffgAXEo7RRkCJ3fEavC6f2ulyVX7wMt1kitTM39po3VswWuWmJV HvLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699302366; x=1699907166; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6YJuri5pn5IAmCMfSYxGyWFTy8wz3fHPNRZUOY0gJFY=; b=r54m121TJRSipkLs6+VA7L9mp/cRjkONiueQv3WdU1y3CNL+sa8q/SL01K8yljIXhh a1qBC89Kbj1YNc9lhbzxwOBrlnOKXAw/YupUB9/Vs/iTZkKIdjLxXt5YnV2NePAmeScS /Puy+Ks5q2DKwvDNtM/udts0qZIGkCO/zJ/rONh1Ml3t5HpFIbaGDPIkTm900cImG5uY lR3mNuwttdzFpeLivaJQwK3nEsdlBJLFIQm+uCS1Nl1MJmTt0Z3W9m3ix1DZT2zvWU/q Rm2GhN6ulO5jxu3HJ+b0j/eQCPKmVlR1EJLYtPHqEu4N1AWePIyGX6I7t7RJqYCbYsD6 y/cw== X-Gm-Message-State: AOJu0YzEFdUQf50MDNjTPq8XkwwaLes9jNL+lDsU33qdPZrMBX8aNE/D A3XGD3/WxwcgCYi7Wjl7aRtoDghmmDBUzHBufETtDQ== X-Google-Smtp-Source: AGHT+IEaRIZ1vzY/Hsd98cwM8kyavbbwMWCM5GCp88X8Y7eonKZmrvnPRKGsR5UZmR/drrW1UcH4DA== X-Received: by 2002:a81:788f:0:b0:5a7:b10c:4772 with SMTP id t137-20020a81788f000000b005a7b10c4772mr12173604ywc.19.1699302366478; Mon, 06 Nov 2023 12:26:06 -0800 (PST) Received: from mandiga.. ([2804:1b3:a7c0:a715:c1a0:7281:6384:2ee9]) by smtp.gmail.com with ESMTPSA id ci7-20020a05690c0a8700b005a7b8fddfedsm4707154ywb.41.2023.11.06.12.26.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Nov 2023 12:26:05 -0800 (PST) From: Adhemerval Zanella To: libc-alpha@sourceware.org, Siddhesh Poyarekar Cc: DJ Delorie Subject: [PATCH v3 04/19] elf: Add all malloc tunable to unsecvars Date: Mon, 6 Nov 2023 17:25:37 -0300 Message-Id: <20231106202552.3404059-5-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231106202552.3404059-1-adhemerval.zanella@linaro.org> References: <20231106202552.3404059-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-13.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces+incoming=patchwork.ozlabs.org@sourceware.org Some environment variables allow alteration of allocator behavior across setuid boundaries, where a setuid program may ignore the tunable, but its non-setuid child can read it and adjust the memory allocator behavior accordingly. Most library behavior tunings is limited to the current process and does not bleed in scope; so it is unclear how pratical this misfeature is. If behavior change across privilege boundaries is desirable, it would be better done with a wrapper program around the non-setuid child that sets these envvars, instead of using the setuid process as the messenger. The patch as fixes tst-env-setuid, where it fail if any unsecvars is set. It also adds a dynamic test, although it requires --enable-hardcoded-path-in-tests so kernel correctly sets the setuid bit (using the loader command directly would require to set the setuid bit on the loader itself, which is not a usual deployment). Co-authored-by: Siddhesh Poyarekar Checked on x86_64-linux-gnu. Reviewed-by: DJ Delorie --- elf/Makefile | 8 +-- elf/tst-env-setuid-static.c | 1 + elf/tst-env-setuid.c | 128 +++++++++++++++++++++--------------- sysdeps/generic/unsecvars.h | 7 ++ 4 files changed, 86 insertions(+), 58 deletions(-) create mode 100644 elf/tst-env-setuid-static.c diff --git a/elf/Makefile b/elf/Makefile index 5f24a00a92..52981c19d0 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -262,7 +262,7 @@ tests-static-normal := \ tst-array5-static \ tst-dl-iter-static \ tst-dst-static \ - tst-env-setuid \ + tst-env-setuid-static \ tst-getauxval-static \ tst-linkall-static \ tst-single_threaded-pthread-static \ @@ -305,6 +305,7 @@ tests := \ tst-array5 \ tst-auxv \ tst-dl-hash \ + tst-env-setuid \ tst-leaks1 \ tst-stringtable \ tst-tls9 \ @@ -2429,9 +2430,6 @@ $(objpfx)tst-nodelete-dlclose: $(objpfx)tst-nodelete-dlclose-dso.so $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \ $(objpfx)tst-nodelete-dlclose-plugin.so -tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \ - LD_HWCAP_MASK=0x1 - $(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so $(objpfx)tst-debug1mod1.so: $(objpfx)testobj1.so @@ -2983,3 +2981,5 @@ LDFLAGS-tst-dlclose-lazy-mod1.so = -Wl,-z,lazy,--no-as-needed $(objpfx)tst-dlclose-lazy-mod1.so: $(objpfx)tst-dlclose-lazy-mod2.so $(objpfx)tst-dlclose-lazy.out: \ $(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so + +tst-env-setuid-ARGS = -- $(host-test-program-cmd) diff --git a/elf/tst-env-setuid-static.c b/elf/tst-env-setuid-static.c new file mode 100644 index 0000000000..0d88ae88b9 --- /dev/null +++ b/elf/tst-env-setuid-static.c @@ -0,0 +1 @@ +#include "tst-env-setuid.c" diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c index 032ab44be2..ba295a6a14 100644 --- a/elf/tst-env-setuid.c +++ b/elf/tst-env-setuid.c @@ -15,18 +15,14 @@ License along with the GNU C Library; if not, see . */ -/* Verify that tunables correctly filter out unsafe environment variables like - MALLOC_CHECK_ and MALLOC_MMAP_THRESHOLD_ but also retain - MALLOC_MMAP_THRESHOLD_ in an unprivileged child. */ +/* Verify that correctly filter out unsafe environment variables defined + in unsecvars.h. */ -#include -#include -#include -#include +#include +#include #include +#include #include -#include -#include #include #include @@ -36,61 +32,72 @@ static char SETGID_CHILD[] = "setgid-child"; -#ifndef test_child -static int -test_child (void) -{ - if (getenv ("MALLOC_CHECK_") != NULL) - { - printf ("MALLOC_CHECK_ is still set\n"); - return 1; - } - - if (getenv ("MALLOC_MMAP_THRESHOLD_") == NULL) - { - printf ("MALLOC_MMAP_THRESHOLD_ lost\n"); - return 1; - } +#define FILTERED_VALUE "some-filtered-value" +#define UNFILTERED_VALUE "some-unfiltered-value" - if (getenv ("LD_HWCAP_MASK") != NULL) - { - printf ("LD_HWCAP_MASK still set\n"); - return 1; - } +struct envvar_t +{ + const char *env; + const char *value; +}; - return 0; -} -#endif +/* That is not an extensible list of all filtered out environment + variables. */ +static const struct envvar_t filtered_envvars[] = +{ + { "GLIBC_TUNABLES", FILTERED_VALUE }, + { "LD_AUDIT", FILTERED_VALUE }, + { "LD_HWCAP_MASK", FILTERED_VALUE }, + { "LD_LIBRARY_PATH", FILTERED_VALUE }, + { "LD_PRELOAD", FILTERED_VALUE }, + { "LD_PROFILE", FILTERED_VALUE }, + { "MALLOC_ARENA_MAX", FILTERED_VALUE }, + { "MALLOC_PERTURB_", FILTERED_VALUE }, + { "MALLOC_TRACE", FILTERED_VALUE }, + { "MALLOC_TRIM_THRESHOLD_", FILTERED_VALUE }, + { "RES_OPTIONS", FILTERED_VALUE }, +}; + +static const struct envvar_t unfiltered_envvars[] = +{ + { "LD_BIND_NOW", "0" }, + { "LD_BIND_NOT", "1" }, + /* Non longer supported option. */ + { "LD_ASSUME_KERNEL", UNFILTERED_VALUE }, +}; -#ifndef test_parent static int -test_parent (void) +test_child (void) { - if (getenv ("MALLOC_CHECK_") == NULL) - { - printf ("MALLOC_CHECK_ lost\n"); - return 1; - } + int ret = 0; - if (getenv ("MALLOC_MMAP_THRESHOLD_") == NULL) + for (const struct envvar_t *e = filtered_envvars; + e != array_end (filtered_envvars); + e++) { - printf ("MALLOC_MMAP_THRESHOLD_ lost\n"); - return 1; + const char *env = getenv (e->env); + ret |= env != NULL; } - if (getenv ("LD_HWCAP_MASK") == NULL) + for (const struct envvar_t *e = unfiltered_envvars; + e != array_end (unfiltered_envvars); + e++) { - printf ("LD_HWCAP_MASK lost\n"); - return 1; + const char *env = getenv (e->env); + ret |= !(env != NULL && strcmp (env, e->value) == 0); } - return 0; + return ret; } -#endif static int do_test (int argc, char **argv) { + /* For dynamic loader, the test requires --enable-hardcoded-path-in-tests so + the kernel sets the AT_SECURE on process initialization. */ + if (argc >= 2 && strstr (argv[1], LD_SO) != 0) + FAIL_UNSUPPORTED ("dynamic test requires --enable-hardcoded-path-in-tests"); + /* Setgid child process. */ if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0) { @@ -104,20 +111,33 @@ do_test (int argc, char **argv) if (ret != 0) exit (1); - exit (EXIT_SUCCESS); + /* Special return code to make sure that the child executed all the way + through. */ + exit (42); } else { - if (test_parent () != 0) - exit (1); + for (const struct envvar_t *e = filtered_envvars; + e != array_end (filtered_envvars); + e++) + setenv (e->env, e->value, 1); + + for (const struct envvar_t *e = unfiltered_envvars; + e != array_end (unfiltered_envvars); + e++) + setenv (e->env, e->value, 1); int status = support_capture_subprogram_self_sgid (SETGID_CHILD); if (WEXITSTATUS (status) == EXIT_UNSUPPORTED) - return EXIT_UNSUPPORTED; - - if (!WIFEXITED (status)) - FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status); + exit (EXIT_UNSUPPORTED); + + if (WEXITSTATUS (status) != 42) + { + printf (" child failed with status %d\n", + WEXITSTATUS (status)); + support_record_failure (); + } return 0; } diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h index 81397fb90b..f7ebed60e5 100644 --- a/sysdeps/generic/unsecvars.h +++ b/sysdeps/generic/unsecvars.h @@ -18,7 +18,14 @@ "LD_SHOW_AUXV\0" \ "LOCALDOMAIN\0" \ "LOCPATH\0" \ + "MALLOC_ARENA_MAX\0" \ + "MALLOC_ARENA_TEST\0" \ + "MALLOC_MMAP_MAX_\0" \ + "MALLOC_MMAP_THRESHOLD_\0" \ + "MALLOC_PERTURB_\0" \ + "MALLOC_TOP_PAD_\0" \ "MALLOC_TRACE\0" \ + "MALLOC_TRIM_THRESHOLD_\0" \ "NIS_PATH\0" \ "NLSPATH\0" \ "RESOLV_HOST_CONF\0" \