From patchwork Wed Jul 31 20:02:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 94900 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BC3BD385C6D1 for ; Wed, 31 Jul 2024 20:03:59 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pl1-x62a.google.com (mail-pl1-x62a.google.com [IPv6:2607:f8b0:4864:20::62a]) by sourceware.org (Postfix) with ESMTPS id E352A3858C33 for ; Wed, 31 Jul 2024 20:03:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E352A3858C33 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 E352A3858C33 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::62a ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456199; cv=none; b=Xa1kwJW6hnrECUTC/ONGQzTruaI4DT/bLFEUNQuToJKepcmfBDvY3ZrEyR0ohSThNtYpsu1sf+OhVHnYUGCSyH5zy25QlTnaYPmQpghFJN5lRNhrandIZXvu0L0zhLo5TsDloNi87dbcKymgcBYWSuMtrSLrBlYqPz/wzs13efo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456199; c=relaxed/simple; bh=0ysnPjRdIheuSDpDvLtlabkeqckUw4zQQ+KkPfVO7bA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=EA3TMVItULIFNUqJCV3CoKmQ6qNj+ajp1WxnP/d9l4cleeTpjVZdAY4tdT9byatAMjdHacVeGONWosDJQ8466LZ9RRy6fkIPCmstjd7PVpz7o5MYIsP2uxn84BBmcWcGLfzwX4KbCgAfRZZZnwPXpvkrfr+AVe9rSsJrD5YEm9g= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pl1-x62a.google.com with SMTP id d9443c01a7336-1fc5239faebso42705425ad.1 for ; Wed, 31 Jul 2024 13:03:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1722456196; x=1723060996; 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=RHvyD6Fsry74hIiTf1TwSqxwHjliffo16SLcTmTnzGQ=; b=qar0Ei83fz5pufylWmlnXcE4gT3oErSnadetGk8KW35BBCH88JN/yBIfoCu1acCaWR qtFqhmUT/6eeLm9bHhApKnS4HHKbdD6f8MQuwiu93Jz2AfqWMXTh+twHKjcux+FalAb0 Pg4bRMRRjvm847R8CVrLR0z+JYpbfL9+peFzKPbTPmrc2/uxwZXOFKZuayvxiPSNgf0g XoCxykYaIId80DS4NYDgplG5upSk5iNaXeeriCMmYLI/ZSa5XKHeGrqHq0JxDhRppJRW 43JbK0fwgXGOqFizvFYmcsE92IxJ31hAwhkqs3bsTh6CEH3+sni1Be881Xy7m0UtRXPP C8sA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722456196; x=1723060996; 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=RHvyD6Fsry74hIiTf1TwSqxwHjliffo16SLcTmTnzGQ=; b=Vei9G5vj32ONMamzEKrl6lWcuMeDyl1a0dimsShcC6lmK6ZIqFp8ENWbyFKzBEUCP0 CDmt/ihSknaUv1FROfk++gwJhjRHzMqm5zVqlFFoG0Nq0pEOjfQ+y6MqZ4ek0jnPzofm 6r8FTpvlJyaFdSLIXHTt/Uarh9hqSxJWFhKwkQO449k5+GItwjKDyGqXdjmHVgij6jUC gAG4czVRTx+iYXF30pAQbkkToOSjB6Dddb8N1C4BMiyuqm5OW7NCacOhrui1PGQrgq+y FCGge6J4Lqlm2vInbKEBOSMNSbR5t0VonDYmxlAGQzlZ8/fzYV7TdQ1rl+AijgnqF/Cq YbjA== X-Gm-Message-State: AOJu0YzmJ1Jk8JBl3TEfxd7Nqk0FwsyOHKUh7KKf4PeTJ/osEwjO3egr hxoFJO4o+lP46jg+9cMFFl3OO4qEt7pDWqSQjggCLZ51Hu8cCd+TynbtbRT/FNhvF+/h/Q4wFcM 1 X-Google-Smtp-Source: AGHT+IHjSQLr9p8qN5gQBioI2rwLXjeyo4+VIPvu8WfcVAwvJOUupyLF2MBSLIAPexOPLinOQ1AwLQ== X-Received: by 2002:a17:902:f707:b0:1f9:f906:9088 with SMTP id d9443c01a7336-1ff4ce7ca63mr4809105ad.22.1722456196109; Wed, 31 Jul 2024 13:03:16 -0700 (PDT) Received: from mandiga.. ([2804:1b3:a7c1:1944:b913:6070:fef0:3852]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1fed7fbd8d4sm124106725ad.271.2024.07.31.13.03.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 31 Jul 2024 13:03:14 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Cc: Stephen Roettger , Jeff Xu , Florian Weimer , Mike Hommey Subject: [PATCH v2 1/5] elf: Use RTLD_NODELETE is more places Date: Wed, 31 Jul 2024 17:02:04 -0300 Message-ID: <20240731200307.2269811-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> References: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham 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~patchwork=sourceware.org@sourceware.org * On dlopen dependencies for objects opened with RTLD_NODELETE (since it does not make sense to unload a dependency of a RTLD_NODELETE object); * For the main map executable. * For the main map DT_NEEDED dependencies. * On __libc_unwind_link_get for libgcc_s.so (used for backtrace and unwind). Checked on x86_64-linux-gnu. --- elf/dl-open.c | 3 ++- elf/rtld.c | 6 +++--- include/dlfcn.h | 2 ++ misc/unwind-link.c | 5 +++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/elf/dl-open.c b/elf/dl-open.c index c378da16c0..076b32b977 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -636,7 +636,8 @@ dl_open_worker_begin (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_NODELETE)); /* 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 bfdf632e77..1090d89bfe 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -811,7 +811,7 @@ do_preload (const char *fname, struct link_map *main_map, const char *where) args.str = fname; args.loader = main_map; - args.mode = __RTLD_SECURE; + args.mode = __RTLD_SECURE | RTLD_NODELETE; unsigned int old_nloaded = GL(dl_ns)[LM_ID_BASE]._ns_nloaded; @@ -1638,7 +1638,7 @@ dl_main (const ElfW(Phdr) *phdr, /* Create a link_map for the executable itself. This will be what dlopen on "" returns. */ main_map = _dl_new_object ((char *) "", "", lt_executable, NULL, - __RTLD_OPENEXEC, LM_ID_BASE); + __RTLD_OPENEXEC | RTLD_NODELETE, LM_ID_BASE); assert (main_map != NULL); main_map->l_phdr = phdr; main_map->l_phnum = phnum; @@ -1966,7 +1966,7 @@ dl_main (const ElfW(Phdr) *phdr, RTLD_TIMING_VAR (start); rtld_timer_start (&start); _dl_map_object_deps (main_map, preloads, npreloads, - state.mode == rtld_mode_trace, 0); + state.mode == rtld_mode_trace, RTLD_NODELETE); rtld_timer_accum (&load_time, start); } diff --git a/include/dlfcn.h b/include/dlfcn.h index f49ee1b0c9..06e2ecbdd2 100644 --- a/include/dlfcn.h +++ b/include/dlfcn.h @@ -50,6 +50,8 @@ extern char **__libc_argv attribute_hidden; better error handling semantics for the library. */ #define __libc_dlopen(name) \ __libc_dlopen_mode (name, RTLD_NOW | __RTLD_DLOPEN) +#define __libc_dlopen_nodelete(name) \ + __libc_dlopen_mode (name, RTLD_NODELETE | RTLD_NOW | __RTLD_DLOPEN) extern void *__libc_dlopen_mode (const char *__name, int __mode) attribute_hidden; extern void *__libc_dlsym (void *__map, const char *__name) diff --git a/misc/unwind-link.c b/misc/unwind-link.c index 213a0162a4..7267ecbec3 100644 --- a/misc/unwind-link.c +++ b/misc/unwind-link.c @@ -48,7 +48,7 @@ __libc_unwind_link_get (void) /* Initialize a copy of the data, so that we do not need about unlocking in case the dynamic loader somehow triggers unwinding. */ - void *local_libgcc_handle = __libc_dlopen (LIBGCC_S_SO); + void *local_libgcc_handle = __libc_dlopen_nodelete (LIBGCC_S_SO); if (local_libgcc_handle == NULL) { __libc_lock_unlock (lock); @@ -100,7 +100,8 @@ __libc_unwind_link_get (void) __libc_lock_lock (lock); if (atomic_load_relaxed (&global_libgcc_handle) != NULL) - /* This thread lost the race. Clean up. */ + /* This thread lost the race. Drop the l_direct_opencount and issue + the debug log. */ __libc_dlclose (local_libgcc_handle); else { From patchwork Wed Jul 31 20:02:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 94902 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4A9603858424 for ; Wed, 31 Jul 2024 20:04:46 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pl1-x633.google.com (mail-pl1-x633.google.com [IPv6:2607:f8b0:4864:20::633]) by sourceware.org (Postfix) with ESMTPS id 588AB3858410 for ; Wed, 31 Jul 2024 20:03:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 588AB3858410 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 588AB3858410 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::633 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456207; cv=none; b=uB12ou89U4ear2GClJIQnrVeM9MuwbRdPvHsfBP9i7YDH3V+iWsAElyaEdMuC/ijr48KiVLLENz2LWIsZfPfbh/f8ootiW/4zWF+KTvzTHUESsimRd1ILvIKA1LFXlU0heSgDYOF++iJh01G7hJCU0WyksyUhzOgHpizijHS2io= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456207; c=relaxed/simple; bh=JsT7/2Xwp6XNHcZ0IjbN0o6HKYfesa77rZsew4oBXi0=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=WilK4bW9Y1N6vaaKIdfi/tlv8/7M8qrt5Xs6s38ePdEUD+0wD85OubvXNvGqanpwyOxuWXO8dwUsXO//v8kjKc0Aiiqeg4jqcJ4b3ijSgAavNiMa3XIpj8g6Zw8GAkG2Uui6MOydKruhBnnLlj6E/XcJfuqLI3LpUSU9oejGokg= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pl1-x633.google.com with SMTP id d9443c01a7336-1fee6435a34so42045035ad.0 for ; Wed, 31 Jul 2024 13:03:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1722456199; x=1723060999; 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=K7HGQ3qN6ZtYk4oswFJ+s8QUmUnfchPdH9CGYfdZRNc=; b=zaGrVqpPwbGnMwVrd+PpH/hjTPe2tDmgr3ZGzqKP3A4Tp4w7h/YRWAancPWFPP94T+ AkqZFBX5BiCwn8kCdZK8XgYT/uKc77Jh6MTIopftHUd2uIdzI4lhZQ8eVqYJAljr9Q0T HJyZvNUUY7mrESm7HZle43trmOGmfRJzfo2huWjqXcLCZ/K2fwXZE7zGy2dVx69OvuYz 39mE4TzuisxcAmoHNJk9mEvo9KNq1gDgaO7AOU79f2syBEnfzGW+/pHK6pYe6crO9i+N KOKRCoY60lcG6rve47ATGd+TQyTtOryNJ4qrRAO6VcR5zYUhku0ZlLs2rBx6hVLuCdPc lTVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722456199; x=1723060999; 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=K7HGQ3qN6ZtYk4oswFJ+s8QUmUnfchPdH9CGYfdZRNc=; b=RnGA0xLcLWfnjDHHzff6Ax9tzXJKssmBoELGRoCF61ILqoPVTk/TKuOq+cq0QefuF1 7cH72ZwgU4NKBPKQoI1bkcccdGiepJMW10shzvlXGJnn2yGrH2lF9cNdaVQTFWmS7cNm 0svaaesTGgv0JdVWeoQZel/nUlwAHms6NDyWSe7LUQ969XlkVJm1ei4ncKc0RyOTAIYz hAW+Se7Z0ve/XeT717iSbI/BUYqNy0ZeL/FNBgX+4Y9kLLmcgohZxe/ytwd9Rrp9qAWL xXc9YeH9B/iEC/s6d2UZafiP5irKXjjvyWUtwZqByoBZ+9i5rI7cpi8OgB7BYYLDCtAF xiZQ== X-Gm-Message-State: AOJu0Yx2VHndaa5H5GET7yqO8uAUSeuwXeFbXwTUDncwfioPRt2OS5Kl 91YT0fqIqjxeEp4zkJjACsqh34dfxjXrxFcBb2aAiCImyv/rpHKDiTLpdsz4Li4obfBXpUcj3su x X-Google-Smtp-Source: AGHT+IFh9BOyRu3aEjD/JpOA9Cjz0dXZgVbQShgPwoX9OsAV1yFT9566DDl+GYqp/2Mzc/ZdO9VWNg== X-Received: by 2002:a17:902:cecb:b0:1fd:93d2:fb9b with SMTP id d9443c01a7336-1ff4d249c66mr5102555ad.58.1722456198463; Wed, 31 Jul 2024 13:03:18 -0700 (PDT) Received: from mandiga.. ([2804:1b3:a7c1:1944:b913:6070:fef0:3852]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1fed7fbd8d4sm124106725ad.271.2024.07.31.13.03.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 31 Jul 2024 13:03:17 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Cc: Stephen Roettger , Jeff Xu , Florian Weimer , Mike Hommey Subject: [PATCH v2 2/5] linux: Add mseal syscall support Date: Wed, 31 Jul 2024 17:02:05 -0300 Message-ID: <20240731200307.2269811-3-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> References: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.4 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 autolearn=ham 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~patchwork=sourceware.org@sourceware.org It has been added on Linux 6.10 (8be7258aad44b5e25977a98db136f677fa6f4370) as a way to block operations such as mapping, moving to another location, shrinking the size, expanding the size, or modifying it to a pre-existent memory mapping. Although the system only work on 64 bit CPU, the entrypoint was added for all ABIs (since kernel might eventually implement it to additional ones and/or the abi can execute on a 64-bit kernel). Checked on x86_64-linux-gnu. --- NEWS | 4 ++ manual/memory.texi | 66 ++++++++++++++++++ sysdeps/unix/sysv/linux/Makefile | 1 + sysdeps/unix/sysv/linux/Versions | 3 + sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 + sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 + sysdeps/unix/sysv/linux/arc/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 + sysdeps/unix/sysv/linux/bits/mman-shared.h | 8 +++ sysdeps/unix/sysv/linux/csky/libc.abilist | 1 + sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 + sysdeps/unix/sysv/linux/i386/libc.abilist | 1 + sysdeps/unix/sysv/linux/kernel-features.h | 8 +++ .../sysv/linux/loongarch/lp64/libc.abilist | 1 + .../sysv/linux/m68k/coldfire/libc.abilist | 1 + .../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 + .../sysv/linux/microblaze/be/libc.abilist | 1 + .../sysv/linux/microblaze/le/libc.abilist | 1 + .../sysv/linux/mips/mips32/fpu/libc.abilist | 1 + .../sysv/linux/mips/mips64/n32/libc.abilist | 1 + .../sysv/linux/mips/mips64/n64/libc.abilist | 1 + sysdeps/unix/sysv/linux/nios2/libc.abilist | 1 + sysdeps/unix/sysv/linux/or1k/libc.abilist | 1 + .../linux/powerpc/powerpc32/fpu/libc.abilist | 1 + .../powerpc/powerpc32/nofpu/libc.abilist | 1 + .../linux/powerpc/powerpc64/be/libc.abilist | 1 + .../linux/powerpc/powerpc64/le/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv32/libc.abilist | 1 + .../unix/sysv/linux/riscv/rv64/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-32/libc.abilist | 1 + .../unix/sysv/linux/s390/s390-64/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 + sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 + .../sysv/linux/sparc/sparc32/libc.abilist | 1 + .../sysv/linux/sparc/sparc64/libc.abilist | 1 + sysdeps/unix/sysv/linux/syscalls.list | 1 + sysdeps/unix/sysv/linux/tst-mseal.c | 67 +++++++++++++++++++ .../unix/sysv/linux/x86_64/64/libc.abilist | 1 + .../unix/sysv/linux/x86_64/x32/libc.abilist | 1 + 40 files changed, 190 insertions(+) create mode 100644 sysdeps/unix/sysv/linux/tst-mseal.c diff --git a/NEWS b/NEWS index d488874aba..a964ce00a0 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,10 @@ Major new features: which is why this mode is not enabled by default. A future version of the library may turn it on by default, however. +* On Linux, the mseal function has been added. It allows to seal memory + mappings to avoid further change during process execution such as protection + permissions, unmapping, moving to another location, or shrinking the size. + Deprecated and removed features, and other changes affecting compatibility: [Add deprecations, removals and changes affecting compatibility here] diff --git a/manual/memory.texi b/manual/memory.texi index 3710d7ec66..0c1b9fc7c2 100644 --- a/manual/memory.texi +++ b/manual/memory.texi @@ -3072,6 +3072,72 @@ process memory, no matter how it was allocated. However, portable use of the function requires that it is only used with memory regions returned by @code{mmap} or @code{mmap64}. +@deftypefun int mseal (void *@var{address}, size_t @var{length}, unsigned long @var{flags}) +@standards{Linux, sys/mman.h} +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + +A successful call to the @code {mseal} function seals the memory range of +@var{length} bytes, starting at @var{address}. The sealed memory is +protection against further modifictions such as: + +@itemize @bullet +@item +Unmapping, moving to another location, extending or shrinking the size, +via @code{munmap} and @code{mremap}. + +@item +Moving or expanding a different VMA into the current location, via +@code{mremap}. + +@item +Modifying the memory range with @code{mmap} along with flag @code{MAP_FIXED}. + +@item +Expanding the size with @code{mremap}. + +@item +Change the protection flags with @code{mprotect} or @code{pkey_mprotect}. + +@item +Destructive behaviors on anonymous memory, such as @code{madvice} with +@code{MADV_DONTNEED}. +@end itemize + +The @var{address} must be an allocated virtual memory done by @code{mmap} +or @code{mremap}, and it must be page aligned. The end address (@var{address} +plus @var{length}) must be within an allocated virtual memory range. There +should be no unallocated memory between the start and end of address range. + +The @var{flags} is currently ununsed. + +The @code{mseal} function returns @math{0} on sucess and @math{-1} on +failure. + +The following @code{errno} error conditions are defined for this +function: + +@table @code +@item EPERM +The system blocked the operation, and the given address is unmodified +without partion update. This error is also returned when @code{mseal} +is issued on a 32 bit CPUs (the sealing is currently supported only on +64-bit CPUs, although 32 bit binaries running on 64 bit kernel is +supported). + +@item ENOMEM +Either the @var{address} is not allocated, or the end address is not +allocation, or there is an unallocated memory between start and end address. + +@item ENOSYS +The kernel does not support the @code{mseal} syscall. + +@strong{NB:} The memory sealing changes the lifetime of a mapping, where the +sealing memory could not be unmapped until the process terminates or starts +another one through @code{execve} function. + +@end table +@end deftypefun + @subsection Memory Protection Keys @cindex memory protection key diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 097b5a26fc..9e57621720 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -210,6 +210,7 @@ tests += \ tst-misalign-clone \ tst-mlock2 \ tst-mount \ + tst-mseal \ tst-ntp_adjtime \ tst-ntp_gettime \ tst-ntp_gettimex \ diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions index 268ba1b6ac..162d07002b 100644 --- a/sysdeps/unix/sysv/linux/Versions +++ b/sysdeps/unix/sysv/linux/Versions @@ -328,6 +328,9 @@ libc { posix_spawnattr_getcgroup_np; posix_spawnattr_setcgroup_np; } + GLIBC_2.41 { + mseal; + } GLIBC_PRIVATE { # functions used in other libraries __syscall_rt_sigqueueinfo; diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist index 68eeca1c08..5f93f5664e 100644 --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist @@ -2748,3 +2748,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist index 34c187b721..191dfb973a 100644 --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist @@ -3095,6 +3095,7 @@ GLIBC_2.4 wcstold F GLIBC_2.4 wcstold_l F GLIBC_2.4 wprintf F GLIBC_2.4 wscanf F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist index 916c18ea94..c81fa573b2 100644 --- a/sysdeps/unix/sysv/linux/arc/libc.abilist +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist @@ -2509,3 +2509,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist index ea95de282a..5dfd3f239b 100644 --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist @@ -2801,6 +2801,7 @@ GLIBC_2.4 xdrstdio_create F GLIBC_2.4 xencrypt F GLIBC_2.4 xprt_register F GLIBC_2.4 xprt_unregister F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist index 1cdbc983e1..381a48296e 100644 --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist @@ -2798,6 +2798,7 @@ GLIBC_2.4 xdrstdio_create F GLIBC_2.4 xencrypt F GLIBC_2.4 xprt_register F GLIBC_2.4 xprt_unregister F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/bits/mman-shared.h b/sysdeps/unix/sysv/linux/bits/mman-shared.h index d8ed4436b6..2681218cf9 100644 --- a/sysdeps/unix/sysv/linux/bits/mman-shared.h +++ b/sysdeps/unix/sysv/linux/bits/mman-shared.h @@ -80,6 +80,14 @@ int pkey_free (int __key) __THROW; range. */ int pkey_mprotect (void *__addr, size_t __len, int __prot, int __pkey) __THROW; +/* Seal the address range to avoid further modifications, such as remmap to + shrink or expand the VMA, change protection permission with mprotect, + unmap with munmap, destructive semantic such madvise with MADV_DONTNEED. + The address range must be valid VMA, withouth any gap (unallocated memory) + between start and end, and ADDR much be page aligned (LEN will be page + aligned implicitly). */ +int mseal (void *__addr, size_t __len, unsigned long flags) __THROW; + __END_DECLS #endif /* __USE_GNU */ diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist index 96d45961e2..82dbff8090 100644 --- a/sysdeps/unix/sysv/linux/csky/libc.abilist +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist @@ -2785,3 +2785,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist index fbcd60c2b3..e4565fe4a8 100644 --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist @@ -2821,6 +2821,7 @@ GLIBC_2.4 sys_errlist D 0x400 GLIBC_2.4 sys_nerr D 0x4 GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist index c989b433c0..7f7d37997a 100644 --- a/sysdeps/unix/sysv/linux/i386/libc.abilist +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist @@ -3005,6 +3005,7 @@ GLIBC_2.4 sys_errlist D 0x210 GLIBC_2.4 sys_nerr D 0x4 GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h index a25cf07e9f..b9038d18bf 100644 --- a/sysdeps/unix/sysv/linux/kernel-features.h +++ b/sysdeps/unix/sysv/linux/kernel-features.h @@ -257,4 +257,12 @@ # define __ASSUME_FCHMODAT2 0 #endif +/* The mseal system call was introduced across all architectures in Linux 6.10 + (although only supported on 64-bit CPUs). */ +#if __LINUX_KERNEL_VERSION >= 0x060A00 +# define __ASSUME_MSEAL 1 +#else +# define __ASSUME_MSEAL 0 +#endif + #endif /* kernel-features.h */ diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist index 0023ec1fa1..347f6de473 100644 --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist @@ -2269,3 +2269,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist index d9bd6a9b56..85d0667ecf 100644 --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist @@ -2781,6 +2781,7 @@ GLIBC_2.4 xdrstdio_create F GLIBC_2.4 xencrypt F GLIBC_2.4 xprt_register F GLIBC_2.4 xprt_unregister F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist index 439796d693..4edb1857da 100644 --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist @@ -2948,6 +2948,7 @@ GLIBC_2.4 sys_errlist D 0x210 GLIBC_2.4 sys_nerr D 0x4 GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist index 1069d3252c..31cb00633a 100644 --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist @@ -2834,3 +2834,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist index 17abe08c8b..f13a2cf501 100644 --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist @@ -2831,3 +2831,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist index 799e508950..c9882d829a 100644 --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist @@ -2909,6 +2909,7 @@ GLIBC_2.4 renameat F GLIBC_2.4 symlinkat F GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist index 03d9655f26..c9d94c2892 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist @@ -2915,6 +2915,7 @@ GLIBC_2.4 renameat F GLIBC_2.4 symlinkat F GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist index 05e402ed30..5b30761894 100644 --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist @@ -2817,6 +2817,7 @@ GLIBC_2.4 renameat F GLIBC_2.4 symlinkat F GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist index 3aa81766aa..8e17cf707b 100644 --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist @@ -2873,3 +2873,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist index 959e59e7e7..bb62db6df5 100644 --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist @@ -2259,3 +2259,4 @@ GLIBC_2.40 getcontext F GLIBC_2.40 makecontext F GLIBC_2.40 setcontext F GLIBC_2.40 swapcontext F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist index 9714305608..627d67d5f8 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist @@ -3138,6 +3138,7 @@ GLIBC_2.4 wcstold F GLIBC_2.4 wcstold_l F GLIBC_2.4 wprintf F GLIBC_2.4 wscanf F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist index 0beb52c542..9ee68a3f78 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist @@ -3183,6 +3183,7 @@ GLIBC_2.4 wcstold F GLIBC_2.4 wcstold_l F GLIBC_2.4 wprintf F GLIBC_2.4 wscanf F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist index cfc2ebd3ec..287a87e1db 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist @@ -2892,6 +2892,7 @@ GLIBC_2.4 wcstold F GLIBC_2.4 wcstold_l F GLIBC_2.4 wprintf F GLIBC_2.4 wscanf F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist index 8c9efc5a16..c5c4b20852 100644 --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist @@ -2968,3 +2968,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist index 6397a9cb91..933037c9de 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist @@ -2512,3 +2512,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F GLIBC_2.40 __riscv_hwprobe F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist index 71bbf94f66..4692879639 100644 --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist @@ -2712,3 +2712,4 @@ GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F GLIBC_2.40 __riscv_hwprobe F +GLIBC_2.41 mseal F diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist index a7467e2850..a809ce580a 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist @@ -3136,6 +3136,7 @@ GLIBC_2.4 wcstold F GLIBC_2.4 wcstold_l F GLIBC_2.4 wprintf F GLIBC_2.4 wscanf F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist index fd1cb2972d..5c0232c9df 100644 --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist @@ -2929,6 +2929,7 @@ GLIBC_2.4 wcstold F GLIBC_2.4 wcstold_l F GLIBC_2.4 wprintf F GLIBC_2.4 wscanf F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist index ff6e6b1a13..d6fcb949b9 100644 --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist @@ -2828,6 +2828,7 @@ GLIBC_2.4 sys_errlist D 0x210 GLIBC_2.4 sys_nerr D 0x4 GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist index 449d92bbc5..e02fdee7c4 100644 --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist @@ -2825,6 +2825,7 @@ GLIBC_2.4 sys_errlist D 0x210 GLIBC_2.4 sys_nerr D 0x4 GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist index e615be759a..cd5d95f771 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist @@ -3157,6 +3157,7 @@ GLIBC_2.4 wcstold F GLIBC_2.4 wcstold_l F GLIBC_2.4 wprintf F GLIBC_2.4 wscanf F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist index bd36431dd7..d27bcb7c5e 100644 --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist @@ -2793,6 +2793,7 @@ GLIBC_2.4 sys_errlist D 0x430 GLIBC_2.4 sys_nerr D 0x4 GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list index 9ac42c3436..00ebceb574 100644 --- a/sysdeps/unix/sysv/linux/syscalls.list +++ b/sysdeps/unix/sysv/linux/syscalls.list @@ -39,6 +39,7 @@ mlockall - mlockall i:i mlockall mount EXTRA mount i:sssUp __mount mount mount_setattr EXTRA mount_setattr i:isUpU mount_setattr move_mount EXTRA move_mount i:isisU move_mount +mseal EXTRA mseal i:bUU __mseal mseal munlock - munlock i:aU munlock munlockall - munlockall i: munlockall nfsservctl EXTRA nfsservctl i:ipp __compat_nfsservctl nfsservctl@GLIBC_2.0:GLIBC_2.28 diff --git a/sysdeps/unix/sysv/linux/tst-mseal.c b/sysdeps/unix/sysv/linux/tst-mseal.c new file mode 100644 index 0000000000..dfed57411e --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-mseal.c @@ -0,0 +1,67 @@ +/* Basic tests for mseal. + Copyright (C) 2024 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 int +do_test (void) +{ + TEST_VERIFY_EXIT (mseal (MAP_FAILED, 0, 0) == -1); + if (errno == ENOSYS) + FAIL_UNSUPPORTED ("kernel does not support mseal"); + TEST_COMPARE (errno, EINVAL); + + size_t pagesize = getpagesize (); + void *p = xmmap (NULL, 4 * pagesize, PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE, -1); + xmunmap (p + 2 * pagesize, pagesize); + + /* Unaligned address. */ + TEST_VERIFY_EXIT (mseal (p + 1, pagesize, 0) == -1); + TEST_COMPARE (errno, EINVAL); + + /* Length too big. */ + TEST_VERIFY_EXIT (mseal (p, 3 * pagesize, 0) == -1); + TEST_COMPARE (errno, ENOMEM); + + TEST_VERIFY_EXIT (mseal (p, pagesize, 0) == 0); + /* Apply the same seal should be idempotent. */ + TEST_VERIFY_EXIT (mseal (p, pagesize, 0) == 0); + + TEST_VERIFY_EXIT (mprotect (p, pagesize, PROT_WRITE) == -1); + TEST_COMPARE (errno, EPERM); + + TEST_VERIFY_EXIT (munmap (p, pagesize) == -1); + TEST_COMPARE (errno, EPERM); + + TEST_VERIFY_EXIT (mremap (p, pagesize, 2 * pagesize, 0) == MAP_FAILED); + TEST_COMPARE (errno, EPERM); + + TEST_VERIFY_EXIT (madvise (p, pagesize, MADV_DONTNEED) == -1); + TEST_COMPARE (errno, EPERM); + + xmunmap (p + pagesize, pagesize); + xmunmap (p + 3 * pagesize, pagesize); + + return 0; +} + +#include diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist index aea7848ed6..8b72a917a9 100644 --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist @@ -2744,6 +2744,7 @@ GLIBC_2.4 sys_errlist D 0x420 GLIBC_2.4 sys_nerr D 0x4 GLIBC_2.4 unlinkat F GLIBC_2.4 unshare F +GLIBC_2.41 mseal F GLIBC_2.5 __readlinkat_chk F GLIBC_2.5 inet6_opt_append F GLIBC_2.5 inet6_opt_find F diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist index 4ab3681914..9a72854f8c 100644 --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist @@ -2763,3 +2763,4 @@ GLIBC_2.39 stdc_trailing_zeros_ui F GLIBC_2.39 stdc_trailing_zeros_ul F GLIBC_2.39 stdc_trailing_zeros_ull F GLIBC_2.39 stdc_trailing_zeros_us F +GLIBC_2.41 mseal F From patchwork Wed Jul 31 20:02:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 94903 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3A0F83857000 for ; Wed, 31 Jul 2024 20:05:33 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pl1-x630.google.com (mail-pl1-x630.google.com [IPv6:2607:f8b0:4864:20::630]) by sourceware.org (Postfix) with ESMTPS id 9A9F0385843B for ; Wed, 31 Jul 2024 20:03:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9A9F0385843B 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 9A9F0385843B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::630 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456210; cv=none; b=piWJvxvj6qMzf+TJnQmVqV2jveFKJJ/MTW1P990Kiw9jMSPUGmkPin7CTIp9RE1AFwg+DsdJ0tT14oFYd4Am/Upx75wlkJ6Wea6yoqLazokv3PFI/sIZm9qEV7OKDpg2NQ/1OBMbeU3tXtul0S7m7X+jdlVfcjsXBHzAZlLpyEM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456210; c=relaxed/simple; bh=MXWxItLBdoDjUsBX5AA9R0uTAJvxPd9lnuIatHyxo14=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=e3V4lwdnkE9X3rQKiWEWJJZ0NnxM+AEvLVmCvL4+f3anSxMnBA9HI/yInoM9vwFhfIQMeQ/VN3jkQ3PTkToiWaahThk9pV/DXsrofV5uXS7sBS3SArNjCeFN3Fvg124N8MH8crHlVLSpJRFUMHIz5jhQRyRoW+2bOvofayDN+iE= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pl1-x630.google.com with SMTP id d9443c01a7336-1fd65aaac27so10135155ad.1 for ; Wed, 31 Jul 2024 13:03:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1722456202; x=1723061002; 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=upPkaYAbnA8CIXtHuxSq7INooZLiCKOtWY1ALdTj4NU=; b=zARj+OqGcb+DbYnuR8AUY2gPiXxAu6RZ7zC1dgbGl+7glxRQ+Ucwy1yOyBVzgDw+JL vGludkGWbX8JgjCK26tKZjinbb4FryZf/ddAHkZxICXJy8szsHBTw+7XhVvOzrhQpHLi Cp6X00SMRMrhHo0VBF2W49SaWkiPuyFfP4V7gUmT45Gzp1fYviiMkHmC+x6Ef8+6u+8k uSe2pNe9n3f/684iU+fNdVU70mra00tkMowBhx4NwEvdf5MEdw3I1EfrJ7/23p/34nIN bZUEVgq7Oiew3e5ouYEjdCy5aSBXrQRqAx8Atv9PmvpsJSu+m6pDRoZ5zRTKl0R95zpd IMcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722456202; x=1723061002; 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=upPkaYAbnA8CIXtHuxSq7INooZLiCKOtWY1ALdTj4NU=; b=KbzAeNhpsMO1A1RexzHKyMVeG8yQH2PeGJ8IVaYbIIsV4HmlxiDGzxI18oHUwF72ws PlhTRebo5kcePZmQglESrqTHEp5M1GRBBqoycpimAPE5yXz588YMaZM/Z/p3JM3EfLJA BktTGaL1QhEsiPJxongbS4T25gQWcjlbhXrru1PFo2tAIm0d26LLZxQ1As2fOdeO8olV hWV5VSG+6OR501L7WqhFHsRDS0arSKAuo19CljWmyqwfJ3aZJwFs2QvlVuMycU+kIKOh E7riyeTjHCkk+kO8ogeBSXqtTyr8euzf/e0MyUGpkAwrgCDfrmQXVyG5XygHr71HVJDw 1Xkw== X-Gm-Message-State: AOJu0Ywm8gPnCRblLcgL1wwKyKFvqg8mh9NWucoxJ/Qkfbgy1ATJclAh Pfdzh8wsgYkiFF9HHPGWdO6FtlafCIDrYKqM/m0QiMja0UHchBEuu/Aiv+vEkuGrlfSWc8UJcOq H X-Google-Smtp-Source: AGHT+IFn0KaNMgg4IX0gKuXQLG3Q2eg9rzQ/CNm2Olj0N+Dv7GAnBQ7r3P8aiG1/D3wN4PD7RSM6yg== X-Received: by 2002:a17:903:1c1:b0:1fb:a38b:c5b7 with SMTP id d9443c01a7336-1ff4d6131f7mr4508865ad.1.1722456200931; Wed, 31 Jul 2024 13:03:20 -0700 (PDT) Received: from mandiga.. ([2804:1b3:a7c1:1944:b913:6070:fef0:3852]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1fed7fbd8d4sm124106725ad.271.2024.07.31.13.03.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 31 Jul 2024 13:03:20 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Cc: Stephen Roettger , Jeff Xu , Florian Weimer , Mike Hommey Subject: [PATCH v2 3/5] elf: Add support to memory sealing Date: Wed, 31 Jul 2024 17:02:06 -0300 Message-ID: <20240731200307.2269811-4-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> References: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.5 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 autolearn=ham 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~patchwork=sourceware.org@sourceware.org The new Linux mseal syscall allows seal memory mappings to avoid further changes such as memory protection or remap. The sealing is done in multiple places where the memory is supposed to be immutable over program execution: * All shared library dependencies from the binary, including the read-only segments after PT_GNU_RELRO setup. * The binary itself, including dynamic and static links. In both It is up either to binary or the loader to set up the sealing. * Any preload libraries. * Any library loaded with dlopen with RTLD_NODELETE flag (including libgcc.so loaded to enable unwind and/or thread cancellation). * Audit modules. * The loader bump allocator. For binary dependencies, the RTLD_NODELETE signals the link_map should be sealed. It also makes dlopen objects with the flag sealed as well. The sealing is controlled by a new tunable, glibc.rtld.seal, with three different states: 0. Disabled, where no memory sealing is done. 1. Enabled, where the loader will issue the mseal syscall on the memory mappings but any failure will be ignored. This is the default. 2. Enforce, similar to Enabled but any failure from the mseal will terminate the process. Checked on x86_64-linux-gnu and aarch64-linux-gnu. --- NEWS | 11 + elf/dl-load.c | 2 + elf/dl-map-segments.h | 5 + elf/dl-minimal-malloc.c | 2 + elf/dl-mseal-mode.h | 29 ++ elf/dl-open.c | 4 + elf/dl-reloc.c | 51 ++++ elf/dl-support.c | 7 + elf/dl-tunables.list | 6 + elf/rtld.c | 7 + elf/setup-vdso.h | 2 + elf/tst-rtld-list-tunables.exp | 1 + include/link.h | 6 + manual/tunables.texi | 42 +++ string/strerrorname_np.c | 1 + sysdeps/generic/dl-mseal.h | 25 ++ sysdeps/generic/ldsodefs.h | 6 + sysdeps/unix/sysv/linux/Makefile | 47 +++ sysdeps/unix/sysv/linux/dl-mseal.c | 51 ++++ sysdeps/unix/sysv/linux/dl-mseal.h | 29 ++ .../unix/sysv/linux/tst-dl_mseal-auditmod.c | 23 ++ .../unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c | 19 ++ .../unix/sysv/linux/tst-dl_mseal-dlopen-1.c | 19 ++ .../unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c | 19 ++ .../unix/sysv/linux/tst-dl_mseal-dlopen-2.c | 19 ++ sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c | 19 ++ sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c | 19 ++ .../unix/sysv/linux/tst-dl_mseal-preload.c | 19 ++ .../unix/sysv/linux/tst-dl_mseal-skeleton.c | 272 ++++++++++++++++++ sysdeps/unix/sysv/linux/tst-dl_mseal-static.c | 36 +++ sysdeps/unix/sysv/linux/tst-dl_mseal.c | 67 +++++ 31 files changed, 865 insertions(+) create mode 100644 elf/dl-mseal-mode.h create mode 100644 sysdeps/generic/dl-mseal.h create mode 100644 sysdeps/unix/sysv/linux/dl-mseal.c create mode 100644 sysdeps/unix/sysv/linux/dl-mseal.h create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-auditmod.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-preload.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-static.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal.c diff --git a/NEWS b/NEWS index a964ce00a0..fbfc86b2b2 100644 --- a/NEWS +++ b/NEWS @@ -29,6 +29,17 @@ Major new features: mappings to avoid further change during process execution such as protection permissions, unmapping, moving to another location, or shrinking the size. +* On Linux, the loader will memory seal multiple places where the memory is + supposed to immutable over program execution: all shared library + dependencies from the binary, the binary itself, any preload libraries, + any library loaded with dlopen and the RTLD_NODELETE flag, any audit modules, + and the loader metadata. + +* A new tunable, glibc.rtld.seal, can be used to control the memory sealing + with thread different states: disable, where sealing will not be applied, + enabled, where any memory sealing failure is ignored; and enforced, where + any memory failure terminates the process. The default is enabled. + Deprecated and removed features, and other changes affecting compatibility: [Add deprecations, removals and changes affecting compatibility here] diff --git a/elf/dl-load.c b/elf/dl-load.c index 8a89b71016..4c2371ec46 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1431,6 +1431,8 @@ cannot enable executable stack as shared object requires"); /* Assign the next available module ID. */ _dl_assign_tls_modid (l); + l->l_seal = mode & RTLD_NODELETE ? lt_seal_toseal : lt_seal_dont; + #ifdef DL_AFTER_LOAD DL_AFTER_LOAD (l); #endif diff --git a/elf/dl-map-segments.h b/elf/dl-map-segments.h index 30977cf800..f224a9a367 100644 --- a/elf/dl-map-segments.h +++ b/elf/dl-map-segments.h @@ -18,6 +18,7 @@ . */ #include +#include /* Map a segment and align it properly. */ @@ -188,6 +189,10 @@ _dl_map_segments (struct link_map *l, int fd, -1, 0); if (__glibc_unlikely (mapat == MAP_FAILED)) return DL_MAP_SEGMENTS_ERROR_MAP_ZERO_FILL; + /* We need to seal this here because it will not be part of + the PT_LOAD segments, nor it is taken in RELRO + calculation. */ + _dl_mseal (mapat, zeroend - zeropage); } } diff --git a/elf/dl-minimal-malloc.c b/elf/dl-minimal-malloc.c index 25d870728d..2e1cbbdae5 100644 --- a/elf/dl-minimal-malloc.c +++ b/elf/dl-minimal-malloc.c @@ -27,6 +27,7 @@ #include #include #include +#include static void *alloc_ptr, *alloc_end, *alloc_last_block; @@ -62,6 +63,7 @@ __minimal_malloc (size_t n) if (page == MAP_FAILED) return NULL; __set_vma_name (page, nup, " glibc: loader malloc"); + _dl_mseal (page, nup); if (page != alloc_end) alloc_ptr = page; alloc_end = page + nup; diff --git a/elf/dl-mseal-mode.h b/elf/dl-mseal-mode.h new file mode 100644 index 0000000000..7f9ede4db7 --- /dev/null +++ b/elf/dl-mseal-mode.h @@ -0,0 +1,29 @@ +/* Memory sealing. Generic definitions. + Copyright (C) 2024 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 + . */ + +#ifndef _DL_SEAL_MODE_H +#define _DL_SEAL_MODE_H + +enum dl_seal_mode +{ + DL_SEAL_DISABLE = 0, + DL_SEAL_ENABLE = 1, + DL_SEAL_ENFORCE = 2, +}; + +#endif diff --git a/elf/dl-open.c b/elf/dl-open.c index 076b32b977..f53b1b0572 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -838,6 +838,10 @@ dl_open_worker (void *a) if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n", new->l_name, new->l_ns, new->l_direct_opencount); + + /* The seal flag is set only for NEW, however its dependencies could not be + unloaded and thus can also be sealed. */ + _dl_mseal_map (new, true); } void * diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 4bf7aec88b..6bb424f789 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -28,6 +28,7 @@ #include <_itoa.h> #include #include "dynamic-link.h" +#include /* Statistics function. */ #ifdef SHARED @@ -347,6 +348,11 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], done, do it. */ if (l->l_relro_size != 0) _dl_protect_relro (l); + + /* Seal the memory mapping after RELRO setup, we can use the PT_LOAD + segments because even if relro splits the the original RW VMA, + mseal works with multiple VMAs with different flags. */ + _dl_mseal_map (l, false); } @@ -369,6 +375,51 @@ cannot apply additional memory protection after relocation"); } } +static void +_dl_mseal_map_1 (struct link_map *l) +{ + /* We only checked if the map is already sealed here so we can seal audit + module dependencies after the initial audit setup. */ + if (l->l_seal == lt_seal_sealed) + return; + + int r = -1; + if (l->l_contiguous) + r = _dl_mseal ((void *) l->l_map_start, l->l_map_end - l->l_map_start); + else + { + const ElfW(Phdr) *ph; + for (ph = l->l_phdr; ph < &l->l_phdr[l->l_phnum]; ++ph) + switch (ph->p_type) + { + case PT_LOAD: + { + ElfW(Addr) mapstart = l->l_addr + + (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)); + ElfW(Addr) allocend = l->l_addr + ph->p_vaddr + ph->p_memsz; + r = _dl_mseal ((void *) mapstart, allocend - mapstart); + } + break; + } + } + + if (r == 0) + l->l_seal = lt_seal_sealed; +} + +void +_dl_mseal_map (struct link_map *l, bool dep) +{ + if (l->l_seal == lt_seal_dont || l->l_seal == lt_seal_sealed) + return; + + if (l->l_searchlist.r_list == NULL || !dep) + _dl_mseal_map_1 (l); + else + for (unsigned int i = 0; i < l->l_searchlist.r_nlist; ++i) + _dl_mseal_map_1 (l->l_searchlist.r_list[i]); +} + void __attribute_noinline__ _dl_reloc_bad_type (struct link_map *map, unsigned int type, int plt) diff --git a/elf/dl-support.c b/elf/dl-support.c index 451932dd03..8290a380f3 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -45,6 +45,7 @@ #include #include #include +#include extern char *__progname; char **_dl_argv = &__progname; /* This is checked for some error messages. */ @@ -99,6 +100,7 @@ static struct link_map _dl_main_map = .l_used = 1, .l_tls_offset = NO_TLS_OFFSET, .l_serial = 1, + .l_seal = SUPPORT_MSEAL, }; /* Namespace information. */ @@ -340,6 +342,11 @@ _dl_non_dynamic_init (void) /* Setup relro on the binary itself. */ if (_dl_main_map.l_relro_size != 0) _dl_protect_relro (&_dl_main_map); + + /* Seal the memory mapping after RELRO setup, we can use the PT_LOAD + segments because even if relro splits the the original RW VMA, + mseal works with multiple VMAs with different flags. */ + _dl_mseal_map (&_dl_main_map, false); } #ifdef DL_SYSINFO_IMPLEMENTATION diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list index 40ac5b3776..5eb3a2380b 100644 --- a/elf/dl-tunables.list +++ b/elf/dl-tunables.list @@ -135,6 +135,12 @@ glibc { maxval: 1 default: 0 } + seal { + type: INT_32 + minval: 0 + maxval: 2 + default: 1 + } } mem { diff --git a/elf/rtld.c b/elf/rtld.c index 1090d89bfe..efe7e97b04 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -53,6 +53,7 @@ #include #include #include +#include #include @@ -477,6 +478,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) GL(dl_rtld_map).l_real = &GL(dl_rtld_map); GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start; GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end; + GL(dl_rtld_map).l_seal = 1; /* Copy the TLS related data if necessary. */ #ifndef DONT_USE_BOOTSTRAP_MAP # if NO_TLS_OFFSET != 0 @@ -1043,6 +1045,10 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); /* Mark the DSO as being used for auditing. */ dlmargs.map->l_auditing = 1; + + /* Seal the audit modules and their dependencies. */ + dlmargs.map->l_seal = lt_seal_toseal; + _dl_mseal_map (dlmargs.map, true); } /* Load all audit modules. */ @@ -1125,6 +1131,7 @@ rtld_setup_main_map (struct link_map *main_map) /* And it was opened directly. */ ++main_map->l_direct_opencount; main_map->l_contiguous = 1; + main_map->l_seal = 1; /* A PT_LOAD segment at an unexpected address will clear the l_contiguous flag. The ELF specification says that PT_LOAD diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h index 888e1e4897..f115e6eb78 100644 --- a/elf/setup-vdso.h +++ b/elf/setup-vdso.h @@ -66,6 +66,8 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), /* The vDSO is always used. */ l->l_used = 1; + /* The PT_LOAD may not cover all the vdso mapping. */ + l->l_seal = lt_seal_dont; /* Initialize l_local_scope to contain just this map. This allows the use of dl_lookup_symbol_x to resolve symbols within the vdso. diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp index db0e1c86e9..d40a478dd7 100644 --- a/elf/tst-rtld-list-tunables.exp +++ b/elf/tst-rtld-list-tunables.exp @@ -15,3 +15,4 @@ glibc.rtld.dynamic_sort: 2 (min: 1, max: 2) glibc.rtld.enable_secure: 0 (min: 0, max: 1) glibc.rtld.nns: 0x4 (min: 0x1, max: 0x10) glibc.rtld.optional_static_tls: 0x200 (min: 0x0, max: 0x[f]+) +glibc.rtld.seal: 1 (min: 0, max: 2) diff --git a/include/link.h b/include/link.h index cb0d7d8e2f..fd8e7f25bf 100644 --- a/include/link.h +++ b/include/link.h @@ -212,6 +212,12 @@ struct link_map unsigned int l_find_object_processed:1; /* Zero if _dl_find_object_update needs to process this lt_library map. */ + enum /* Memory sealing status. */ + { + lt_seal_dont, /* Do not seal the object. */ + lt_seal_toseal, /* The library is marked to be sealed. */ + lt_seal_sealed /* The library is sealed. */ + } l_seal:2; /* NODELETE status of the map. Only valid for maps of type lt_loaded. Lazy binding sets l_nodelete_active directly, diff --git a/manual/tunables.texi b/manual/tunables.texi index 0b1b2898c0..d15eabc9e8 100644 --- a/manual/tunables.texi +++ b/manual/tunables.texi @@ -355,6 +355,48 @@ tests for @code{AT_SECURE} programs and not meant to be a security feature. The default value of this tunable is @samp{0}. @end deftp +@deftp Tunable glibc.rtld.seal +Sets whether to enable memory sealing during program execution. The sealed +memory prevents further changes to the maped memory region, such as shrinking +or expanding, mapping another segment over a pre-existing region, or change +the memory protection flags (check the @code{mseal} for more information). +The sealing is done in multiple places where the memory is supposed to be +immuatable over program execution: + +@itemize @bullet +@item +All shared library dependencies from the binary, including the read-only segments +after @code{PT_GNU_RELRO} setup. + +@item +The binary itself, including dynamic and static linked. In both cases it is up +either to binary or the loader to setup the sealing. + +@item +The vDSO vma provided by the kernel (if existent). + +@item +Any preload libraries. + +@item +Any library loaded with @code{dlopen} with @code{RTLD_NODELETE} flag. + +@item +Any runtime library used for process unwind (such as required by @code{backtrace} +or @code{pthread_exit}). + +@item +All audit modules and their dependencies. +@end itemize + +The tunable accepts three diferent values: @samp{0} where sealing is disabled, +@samp{1} where sealing is enabled, and @samp{2} where sealing is enforced. For +the enforced mode, if the memory can not be sealed the process terminates the +execution. + +The default value of this tunable is @samp{1}. +@end deftp + @node Elision Tunables @section Elision Tunables @cindex elision tunables diff --git a/string/strerrorname_np.c b/string/strerrorname_np.c index 042cea381c..e0e22fa79e 100644 --- a/string/strerrorname_np.c +++ b/string/strerrorname_np.c @@ -17,6 +17,7 @@ . */ #include +#include const char * strerrorname_np (int errnum) diff --git a/sysdeps/generic/dl-mseal.h b/sysdeps/generic/dl-mseal.h new file mode 100644 index 0000000000..d542fcac75 --- /dev/null +++ b/sysdeps/generic/dl-mseal.h @@ -0,0 +1,25 @@ +/* Memory sealing. Generic version. + Copyright (C) 2024 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 + . */ + +static inline int +_dl_mseal (void *addr, size_t len) +{ + return 0; +} + +#define SUPPORT_MSEAL lt_seal_dont diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 656e8a3fa0..aad5a219df 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -1017,6 +1017,12 @@ extern void _dl_relocate_object (struct link_map *map, /* Protect PT_GNU_RELRO area. */ extern void _dl_protect_relro (struct link_map *map) attribute_hidden; +/* Protect MAP with mseal. If MAP is contiguous the while region is + sealed, otherwise iterate over the phdr to seal each PT_LOAD. The DEP + specify whether to seal the dependencies as well. */ +extern void _dl_mseal_map (struct link_map *map, bool dep) + attribute_hidden; + /* Call _dl_signal_error with a message about an unhandled reloc type. TYPE is the result of ELFW(R_TYPE) (r_info), i.e. an R__* value. PLT is nonzero if this was a PLT reloc; it just affects the message. */ diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 9e57621720..3161363db1 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -629,6 +629,10 @@ sysdep-rtld-routines += \ dl-sbrk \ # sysdep-rtld-routines +dl-routines += \ + dl-mseal \ + # dl-routines + others += \ pldd \ # others @@ -638,6 +642,49 @@ install-bin += \ # install-bin $(objpfx)pldd: $(objpfx)xmalloc.o + +tests-static += \ + tst-dl_mseal-static \ + # tests-static + +tests += \ + $(tests-static) \ + tst-dl_mseal \ + # tests + +modules-names += \ + tst-dl_mseal-auditmod \ + tst-dl_mseal-dlopen-1 \ + tst-dl_mseal-dlopen-1-1 \ + tst-dl_mseal-dlopen-2 \ + tst-dl_mseal-dlopen-2-1 \ + tst-dl_mseal-mod-1 \ + tst-dl_mseal-mod-2 \ + tst-dl_mseal-preload \ + # modules-names + +$(objpfx)tst-dl_mseal.out: \ + $(objpfx)tst-dl_mseal-auditmod.so \ + $(objpfx)tst-dl_mseal-preload.so \ + $(objpfx)tst-dl_mseal-mod-1.so \ + $(objpfx)tst-dl_mseal-mod-2.so \ + $(objpfx)tst-dl_mseal-dlopen-1.so \ + $(objpfx)tst-dl_mseal-dlopen-1-1.so \ + $(objpfx)tst-dl_mseal-dlopen-2.so \ + $(objpfx)tst-dl_mseal-dlopen-2-1.so + +tst-dl_mseal-ARGS = -- $(host-test-program-cmd) +$(objpfx)tst-dl_mseal: $(objpfx)tst-dl_mseal-mod-1.so +LDFLAGS-tst-dl_mseal = -Wl,--no-as-needed +$(objpfx)tst-dl_mseal-mod-1.so: $(objpfx)tst-dl_mseal-mod-2.so +LDFLAGS-tst-dl_mseal-mod-1.so = -Wl,--no-as-needed + +$(objpfx)tst-dl_mseal-dlopen-1.so: $(objpfx)tst-dl_mseal-dlopen-1-1.so +LDFLAGS-tst-dl_mseal-dlopen-1.so = -Wl,--no-as-needed +$(objpfx)tst-dl_mseal-dlopen-2.so: $(objpfx)tst-dl_mseal-dlopen-2-1.so +LDFLAGS-tst-dl_mseal-dlopen-2.so = -Wl,--no-as-needed + +tst-dl_mseal-static-ARGS = -- $(host-test-program-cmd) endif ifeq ($(subdir),rt) diff --git a/sysdeps/unix/sysv/linux/dl-mseal.c b/sysdeps/unix/sysv/linux/dl-mseal.c new file mode 100644 index 0000000000..69124b34af --- /dev/null +++ b/sysdeps/unix/sysv/linux/dl-mseal.c @@ -0,0 +1,51 @@ +/* Memory sealing. Linux version. + Copyright (C) 2024 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 + +int +_dl_mseal (void *addr, size_t len) +{ + int32_t mode = TUNABLE_GET (glibc, rtld, seal, int32_t, NULL); + if (mode == DL_SEAL_DISABLE) + return 0; + + int r; +#if __ASSUME_MSEAL + r = INTERNAL_SYSCALL_CALL (mseal, addr, len, 0); +#else + r = -ENOSYS; + static int mseal_supported = true; + if (atomic_load_relaxed (&mseal_supported)) + { + r = INTERNAL_SYSCALL_CALL (mseal, addr, len, 0); + if (r == -ENOSYS) + atomic_store_relaxed (&mseal_supported, false); + } +#endif + if (mode == DL_SEAL_ENFORCE && r != 0) + _dl_fatal_printf ("Fatal error: sealing is enforced and an error " + "ocurred for the 0x%lx-0x%lx range\n", + (long unsigned int) addr, + (long unsigned int) addr + len); + return r; +} diff --git a/sysdeps/unix/sysv/linux/dl-mseal.h b/sysdeps/unix/sysv/linux/dl-mseal.h new file mode 100644 index 0000000000..89b19e33c4 --- /dev/null +++ b/sysdeps/unix/sysv/linux/dl-mseal.h @@ -0,0 +1,29 @@ +/* Memory sealing. Linux version. + Copyright (C) 2024 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 + . */ + +/* Seal the ADDR or size LEN to protect against modifications, such as + changes on the permission flags (through mprotect), remap (through + mmap and/or remap), shrink, destruction changes (madvise with + MADV_DONTNEED), or change its size. The input has the same constraints + as the mseal syscall. + + Return 0 in case of success or a negative value otherwise (a negative + errno). */ +int _dl_mseal (void *addr, size_t len) attribute_hidden; + +#define SUPPORT_MSEAL lt_seal_toseal diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-auditmod.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-auditmod.c new file mode 100644 index 0000000000..d909a1561c --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-auditmod.c @@ -0,0 +1,23 @@ +/* Audit module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +unsigned int +la_version (unsigned int v) +{ + return v; +} diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c new file mode 100644 index 0000000000..ef1372f47e --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1-1.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int foo2_1 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1.c new file mode 100644 index 0000000000..3c2cbe6035 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-1.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int foo2 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c new file mode 100644 index 0000000000..0cd647de46 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2-1.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int bar2_1 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2.c new file mode 100644 index 0000000000..f719dd3cba --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-2.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int bar2 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c new file mode 100644 index 0000000000..3bd188efe8 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-1.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int foo1 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c new file mode 100644 index 0000000000..636e9777af --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-2.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int bar1 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-preload.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-preload.c new file mode 100644 index 0000000000..7831608dd4 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-preload.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int foo (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c new file mode 100644 index 0000000000..fbf18d9b7c --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c @@ -0,0 +1,272 @@ +/* Basic tests for sealing. Static version. + Copyright (C) 2024 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if UINTPTR_MAX == UINT64_MAX +# define PTR_FMT "#018" PRIxPTR +#else +# define PTR_FMT "#010" PRIxPTR +#endif + +static int +new_flags (const char flags[4]) +{ + bool read_flag = flags[0] == 'r'; + bool write_flag = flags[1] == 'w'; + bool exec_flag = flags[2] == 'x'; + + write_flag = !write_flag; + + return (read_flag ? PROT_READ : 0) + | (write_flag ? PROT_WRITE : 0) + | (exec_flag ? PROT_EXEC : 0); +} + +/* Libraries/VMA that could not be sealed, and that checking for sealing + does not work (kernel does not allow changing protection). */ +static const char *non_sealed_vmas[] = +{ + ".", /* basename value for empty string anonymous + mappings. */ + "[heap]", + "[vsyscall]", + "[vvar]", + "[stack]", + "zero", /* /dev/zero */ +}; + +static int +is_in_string_list (const char *s, const char *const list[], size_t len) +{ + for (size_t i = 0; i != len; i++) + if (strcmp (s, list[i]) == 0) + return i; + return -1; +} +#define IS_IN_STRING_LIST(__s, __list) \ + is_in_string_list (__s, __list, array_length (__list)) + +static void * +tf (void *closure) +{ + pthread_exit (NULL); + return NULL; +} + +static int +handle_restart (void) +{ +#ifndef TEST_STATIC + xdlopen (LIB_DLOPEN_NODELETE, RTLD_NOW | RTLD_NODELETE); + xdlopen (LIB_DLOPEN_DEFAULT, RTLD_NOW); +#endif + + /* pthread_exit will load LIBGCC_S_SO. */ + xpthread_join (xpthread_create (NULL, tf, NULL)); + + FILE *fp = xfopen ("/proc/self/maps", "r"); + char *line = NULL; + size_t linesiz = 0; + + unsigned long pagesize = getpagesize (); + + bool found_expected[array_length(expected_sealed_libs)] = { false }; + while (xgetline (&line, &linesiz, fp) > 0) + { + uintptr_t start; + uintptr_t end; + char flags[5] = { 0 }; + char name[256] = { 0 }; + int idx; + + /* The line is in the form: + start-end flags offset dev inode pathname */ + int r = sscanf (line, + "%" SCNxPTR "-%" SCNxPTR " %4s %*s %*s %*s %256s", + &start, + &end, + flags, + name); + TEST_VERIFY_EXIT (r == 3 || r == 4); + + int found = false; + + const char *libname = basename (name); + if ((idx = IS_IN_STRING_LIST (libname, expected_sealed_libs)) + != -1) + { + /* Check if we can change the protection flags of the segment. */ + int new_prot = new_flags (flags); + TEST_VERIFY_EXIT (mprotect ((void *) start, end - start, + new_prot) == -1); + TEST_VERIFY_EXIT (errno == EPERM); + + /* Also checks trying to map over the sealed libraries. */ + { + char *p = mmap ((void *) start, pagesize, new_prot, + MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + TEST_VERIFY_EXIT (p == MAP_FAILED); + TEST_VERIFY_EXIT (errno == EPERM); + } + + /* And if remap is also blocked. */ + { + char *p = mremap ((void *) start, end - start, end - start, 0); + TEST_VERIFY_EXIT (p == MAP_FAILED); + TEST_VERIFY_EXIT (errno == EPERM); + } + + printf ("sealed: vma: %" PTR_FMT "-%" PTR_FMT " %s %s\n", + start, + end, + flags, + name); + + found_expected[idx] = true; + found = true; + } + else if ((idx = IS_IN_STRING_LIST (libname, expected_non_sealed_libs)) + != -1) + { + /* Check if expected non-sealed segments protection can indeed be + changed. The idea is to use something that would not break + process execution, so just try to mprotect with all protection + bits. */ + int new_prot = PROT_READ | PROT_WRITE | PROT_EXEC; + TEST_VERIFY_EXIT (mprotect ((void *) start, end - start, new_prot) + == 0); + + printf ("not-sealed: vma: %" PTR_FMT "-%" PTR_FMT " %s %s\n", + start, + end, + flags, + name); + + found = true; + } + + if (!found) + { + if (IS_IN_STRING_LIST (libname, non_sealed_vmas) != -1) + printf ("not-sealed: vma: %" PTR_FMT "-%" PTR_FMT " %s %s\n", + start, + end, + flags, + name); + else + FAIL_EXIT1 ("unexpected vma: %" PTR_FMT "-%" PTR_FMT " %s %s\n", + start, + end, + flags, + name); + } + } + xfclose (fp); + + printf ("\n"); + + /* Also check if all the expected sealed maps were found. */ + for (int i = 0; i < array_length (expected_sealed_libs); i++) + if (!found_expected[i]) + FAIL_EXIT1 ("expected VMA %s not sealed\n", expected_sealed_libs[i]); + + return 0; +} + +static int restart; +#define CMDLINE_OPTIONS \ + { "restart", no_argument, &restart, 1 }, + +static int +do_test (int argc, char *argv[]) +{ + /* We must have either: + - One or four parameters left if called initially: + + path to ld.so optional + + "--library-path" optional + + the library path optional + + the application name */ + if (restart) + return handle_restart (); + + /* Check the test requirements. */ + { + int r = mseal (NULL, 0, 0); + if (r == -1 && errno == ENOSYS) + FAIL_UNSUPPORTED ("mseal is not supported by the kernel"); + else + TEST_VERIFY_EXIT (r == 0); + } + support_need_proc ("Reads /proc/self/maps to get stack names."); + + char *spargv[9]; + int i = 0; + for (; i < argc - 1; i++) + spargv[i] = argv[i + 1]; + spargv[i++] = (char *) "--direct"; + spargv[i++] = (char *) "--restart"; + spargv[i] = NULL; + + char *envvarss[4]; + envvarss[0] = (char *) "GLIBC_TUNABLES=glibc.rtld.seal=2"; +#ifndef TEST_STATIC + envvarss[1] = (char *) "LD_PRELOAD=" LIB_PRELOAD; + envvarss[2] = (char *) "LD_AUDIT=" LIB_AUDIT, + envvarss[3] = NULL; +#else + envvarss[1] = NULL; +#endif + + struct support_capture_subprocess result = + support_capture_subprogram (spargv[0], spargv, envvarss); + support_capture_subprocess_check (&result, "tst-dl_mseal", 0, + sc_allow_stdout); + + { + FILE *out = fmemopen (result.out.buffer, result.out.length, "r"); + TEST_VERIFY (out != NULL); + char *line = NULL; + size_t linesz = 0; + while (xgetline (&line, &linesz, out)) + printf ("%s", line); + fclose (out); + } + + support_capture_subprocess_free (&result); + + return 0; +} + +#define TEST_FUNCTION_ARGV do_test +#include diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-static.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-static.c new file mode 100644 index 0000000000..e2a5fc2669 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-static.c @@ -0,0 +1,36 @@ +/* Basic tests for sealing. Static version. + Copyright (C) 2024 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 + . */ + +/* This test checks the memory sealing work on a statically built binary. */ + +#define GLIBC_RTLD_SEAL "2" +#define TEST_STATIC 1 + +/* Expected libraries that loader will seal. */ +static const char *expected_sealed_libs[] = +{ + "tst-dl_mseal-static", +}; + +/* Expected non sealed libraries. */ +static const char *expected_non_sealed_libs[] = +{ + "[vdso]", +}; + +#include "tst-dl_mseal-skeleton.c" diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal.c b/sysdeps/unix/sysv/linux/tst-dl_mseal.c new file mode 100644 index 0000000000..2673e51825 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal.c @@ -0,0 +1,67 @@ +/* Basic tests for sealing. + Copyright (C) 2024 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 + +/* Check if memory sealing works as expected on multiples places: + - On the binary itself. + - On a LD_PRELOAD library. + - On a depedency modules (tst-dl_mseal-mod-{1,2}.so). + - On a audit modules (tst-dl_mseal-auditmod.so). + - On a dlopen dependency opened with RTLD_NODELET + (tst-dl_mseal-dlopen-{2,2-1}.so). + - On the libgcc_s opened by thread unwind. +*/ + +#define GLIBC_RTLD_SEAL "2" +#define LIB_AUDIT "tst-dl_mseal-auditmod.so" + +#define LIB_PRELOAD "tst-dl_mseal-preload.so" +#define LIB_AUDIT "tst-dl_mseal-auditmod.so" + +#define LIB_DLOPEN_DEFAULT "tst-dl_mseal-dlopen-1.so" +#define LIB_DLOPEN_DEFAULT_DEP "tst-dl_mseal-dlopen-1-1.so" +#define LIB_DLOPEN_NODELETE "tst-dl_mseal-dlopen-2.so" +#define LIB_DLOPEN_NODELETE_DEP "tst-dl_mseal-dlopen-2-1.so" + +/* Expected libraries that loader will seal. */ +static const char *expected_sealed_libs[] = +{ + "libc.so", + "ld.so", + "tst-dl_mseal", + "tst-dl_mseal-mod-1.so", + "tst-dl_mseal-mod-2.so", + LIB_PRELOAD, + LIB_AUDIT, + LIB_DLOPEN_NODELETE, + LIB_DLOPEN_NODELETE_DEP, + LIBGCC_S_SO, +}; + +/* Expected non sealed libraries. */ +static const char *expected_non_sealed_libs[] = +{ + "tst-dl_mseal-no-memory-seal", + LIB_PRELOAD, + LIB_DLOPEN_DEFAULT, + LIB_DLOPEN_DEFAULT_DEP, + "[vdso]", +}; + +#include "tst-dl_mseal-skeleton.c" From patchwork Wed Jul 31 20:02:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 94901 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2FF71385DC3C for ; Wed, 31 Jul 2024 20:04:07 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pl1-x632.google.com (mail-pl1-x632.google.com [IPv6:2607:f8b0:4864:20::632]) by sourceware.org (Postfix) with ESMTPS id 589B13858283 for ; Wed, 31 Jul 2024 20:03:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 589B13858283 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 589B13858283 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::632 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456208; cv=none; b=xk37XJ5l1dxBPM5RImBLOBcwR4IHQ65LoucU/kCizQMD/vbxVPFUFKOQ2EgoJJsqq2qfxXl1YpXSuY5qqtFm5HH+hC2Dtv7K0bJb8erUWUZaoIoBWxKwo4Wjtl/i9P33ICRKIRbX/hNnoSOUBILHRUBumktjxFfxi9GuNQV91B0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456208; c=relaxed/simple; bh=5jiJmsfvQMHb7PuaooYFabjo3SJSxld3HJVCtpZR2ls=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=G3+ETeFFvalsvnl1U7APzaPC2D+omoFMATnX2iqjWicBpuvpXbPfpiPHsk6R3EFiTO8y61LytxT5Oo6a5LVzL6wgxvu1j7s4Gx8Z09owqB/vSWfwhJ8jz1yBeudxVTjH9A8Kfx/GNftBHw7UzBxSYgzuy+XwcKWhuH/VPMDlc3Q= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pl1-x632.google.com with SMTP id d9443c01a7336-1fd9e70b592so42803825ad.3 for ; Wed, 31 Jul 2024 13:03:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1722456203; x=1723061003; 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=Fgt9d5LP1LprzxcdzicBf+tjVmYkCVud6ErtxvVCba8=; b=TSCP7KjsaaPMO/FJGfugZB3tkes/rg1skOS+wnmI+Tpg0gfpcllFny6TeK39ZhRvHv wDx5lRY7UGOaD15LxzX5avVG/ONifCo5eKAI9hLgWEwE3tK1hKv9Stkq6vELsrElrXZF eKFtJodly4Vll69HR6yzZYvfbYa6dDm2x6OoZZa2imacOG8BrTrYKtgCDgUluIXUend6 Na1uRRTJ/xF/bWHYCzIis+gkLZojkdUxijTAWW8e7SFc2TpTAtV62pWOxkLKfHbC1wCx 9oHron2w7r3P7wKnr857MJsrqMZTAf2AMmR7YOSc+2iOaO7nnHA01DvzaXe+aj7IDeVx Vy/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722456203; x=1723061003; 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=Fgt9d5LP1LprzxcdzicBf+tjVmYkCVud6ErtxvVCba8=; b=DXXqSZlql1VN7NB8pe28UxnlG8IDcYEzxQNt/g7siatokfRDhlhhfWnEnfLfHBNjOG xXqD461IBAlAJgm6b8mZC/FgMN2uafGaz4p+DNFyVJI8hAJCvD9iY/ndCvvlpG1mUhzK 41n+CpKXv0s18J96y2FVX0+AtGe2mxeyNHo96pNfdMINlTcHPtZXYsRTt0zaoWIVcfJ9 Uyq6yj9ZstzaceX01QzpX1HO4Zy5hUs7ir9dvaU9GSvnzHCzydaver7JnYK0REijXl9i AJoppYlPtZtordNouyTQ5ovZ/UFr4Ipo9E8oeH0EHYfDNP6FneWUKi0Vy/pxKgrDFRlr PJSg== X-Gm-Message-State: AOJu0Yz2hFISuLaN5fZwrmRAeb63YYAU5cpEYDiSKlr8r3FizpHhqmSp ofd+0qRDwl5kVbliSVygjQQLAcsrCcX32WZl7theZEcI2njwP25C2BvyzNLjjZdddgGk2twOcUH z X-Google-Smtp-Source: AGHT+IHC5r8Hm3R0x8DeD0iZf35dkNwPpNMvPCNzGvS6j+SAzdRdBcld+5O3QGcFoGve6BpT2ssx3w== X-Received: by 2002:a17:903:28c3:b0:1fc:86cc:4254 with SMTP id d9443c01a7336-1ff4ceaefbcmr4207625ad.33.1722456203636; Wed, 31 Jul 2024 13:03:23 -0700 (PDT) Received: from mandiga.. ([2804:1b3:a7c1:1944:b913:6070:fef0:3852]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1fed7fbd8d4sm124106725ad.271.2024.07.31.13.03.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 31 Jul 2024 13:03:22 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Cc: Stephen Roettger , Jeff Xu , Florian Weimer , Mike Hommey Subject: [PATCH v2 4/5] elf: Also parse gnu properties for static linked binaries Date: Wed, 31 Jul 2024 17:02:07 -0300 Message-ID: <20240731200307.2269811-5-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> References: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham 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~patchwork=sourceware.org@sourceware.org So the static binary can opt-out of memory sealing. Checked on x86_64-linux-gnu. --- elf/dl-support.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/elf/dl-support.c b/elf/dl-support.c index 8290a380f3..a02ae712b3 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -45,6 +45,7 @@ #include #include #include +#include #include extern char *__progname; @@ -336,6 +337,18 @@ _dl_non_dynamic_init (void) _dl_main_map.l_relro_size = ph->p_memsz; break; } + /* Process program headers again, but scan them backwards so + that PT_NOTE can be skipped if PT_GNU_PROPERTY exits. */ + for (const ElfW(Phdr) *ph = &_dl_phdr[_dl_phnum]; ph != _dl_phdr; --ph) + switch (ph[-1].p_type) + { + case PT_NOTE: + _dl_process_pt_note (&_dl_main_map, -1, &ph[-1]); + break; + case PT_GNU_PROPERTY: + _dl_process_pt_gnu_property (&_dl_main_map, -1, &ph[-1]); + break; + } call_function_static_weak (_dl_find_object_init); From patchwork Wed Jul 31 20:02:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adhemerval Zanella X-Patchwork-Id: 94905 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B4135385C6C6 for ; Wed, 31 Jul 2024 20:06:29 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from mail-pl1-x633.google.com (mail-pl1-x633.google.com [IPv6:2607:f8b0:4864:20::633]) by sourceware.org (Postfix) with ESMTPS id F2B743858294 for ; Wed, 31 Jul 2024 20:03:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F2B743858294 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 F2B743858294 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::633 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456212; cv=none; b=jtRUJPoxIYChtuwp3BG8P29QBOF1Kz161i/gtcHOq2HoZ+98w4RoKjXTcLJssGEyoPbU7AEeg+IcEhUFOFLOeS1ZKBLcX6tFNn7gtqEpJTxX1Sqmt0okjob/OdLbDiDMh9EIU7IyQUPqGMYI0FQEdOn2ZPZUkdEx+C8cQcIag7s= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1722456212; c=relaxed/simple; bh=wbhYkZR8TMP+mxDAclqevZv0tPn2P3yAW1mX6h2Vlnk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=WMqJnVdwXM87utWsQjgxRBC3yIi/eyPPzWpaD3Hl3enSWPU0S1nTXrVkbT/mUz0xIBrCmcAtxR5h+NwcafmWGg2gBa8B5pqY1IrvfR8rmlM/sFVDCTJQ0oZ59GQY1NIy4fu3YzbIixhTHo/7KQqSUMbTw6xccOVCUtHs+54wkOQ= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-pl1-x633.google.com with SMTP id d9443c01a7336-1fd70ba6a15so45624025ad.0 for ; Wed, 31 Jul 2024 13:03:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1722456206; x=1723061006; 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=/Lexn72Eg7QKKEKnBUx9cEEomzCRRA6drfWxU5dXw6Q=; b=IhPt0FDyp+nqNy6u3qnTL+BKanu9C9bMNKSNVGUQzhxKBz/qVXWWjSxfakmgySe0t6 qTgK0P4X4TYDGqpiUkKRWajTVbpk2L03PyO3/DX/TssIuY4bRftCh0i410zmWtj8T41p jMQTANSfO3GBqZhIDQr76O5eNZvAPdxBhq6TdhnKMl4K6QIrL0avcauFgQlw1gL+k/fe nTFH25vvRtNse7TSS0zbrV1LHG9SX04MXRrkrPDn3fuRb3DUJ0LwMYSIBQy/8N23Xfew aiKZ2SrCkSicE3Iq7frsH0LOqCX5vlvTIGYByoAppnreElBGtuN5yFxGS3Fh6Uqlk9BW N1tQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1722456206; x=1723061006; 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=/Lexn72Eg7QKKEKnBUx9cEEomzCRRA6drfWxU5dXw6Q=; b=L5C/TfPWDG7Zug1fphQc0u5efkUsosyUXCpLZ4xOWuh+xTTmMqq3gT23brUSombaZA d5mu4wVN/gtTs3pE3Z+8pgxvWEUClIw5qqPpC14MQdgymdSpUhX9y9sFmMQc6IeW/Yek XmDfCt2VphDdYB1DomhBnuOmFeQ0nOT7eO8xt8wnCbvpvEgaOlohMSlIQuAKy0+2uHv5 VPBeMsx/GWwacaPIrkixFdE1rsh+QjxjCWLVOk57Xg/uBdhYJ84ZL2Q+qQZSMCTzWMTz JmMTeIQwTtQRh/2s/LZxT3ieK5kEWDp8TqAu+GJSx+TJL+rMtOagYkbFiKAG6TxiWqxj UH6A== X-Gm-Message-State: AOJu0Yxo9MuTb5EqhiQ0OwQWRaLqs35fK1hw7l8h6MlqTEAWAgGgiNL7 kRJ9Q011p4NoKfdvUuHkM2jSJ7nBij0NlQAJzajDSYtVRovFL0iv3UAfLaBPIMibo6N8CPSGQxI Y X-Google-Smtp-Source: AGHT+IFrNHggKXZAtUYxS8efGa8LdPWVH8vpUzXuIrUmy4J1kSQ0U4eWJf5qTmjMF7R7fHUVaYDsEg== X-Received: by 2002:a17:902:e542:b0:1fb:7e13:a7cd with SMTP id d9443c01a7336-1ff4ceb5bd4mr5129695ad.37.1722456205992; Wed, 31 Jul 2024 13:03:25 -0700 (PDT) Received: from mandiga.. ([2804:1b3:a7c1:1944:b913:6070:fef0:3852]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-1fed7fbd8d4sm124106725ad.271.2024.07.31.13.03.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 31 Jul 2024 13:03:25 -0700 (PDT) From: Adhemerval Zanella To: libc-alpha@sourceware.org Cc: Stephen Roettger , Jeff Xu , Florian Weimer , Mike Hommey Subject: [PATCH v2 5/5] elf: Add support for GNU_PROPERTY_NO_MEMORY_SEAL Date: Wed, 31 Jul 2024 17:02:08 -0300 Message-ID: <20240731200307.2269811-6-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> References: <20240731200307.2269811-1-adhemerval.zanella@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-12.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 autolearn=ham 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~patchwork=sourceware.org@sourceware.org The GNU_PROPERTY_NO_MEMORY_SEAL is a GNU property per module instructing the glibc not to seal the object PT_LOAD. It can be used for any reason the modules require to seal not to be enabled (i.e., on Firefox hack to bypass the dynamic loader and enable DT_RELR on older glibc [1]). In this case, it is up to the module to apply memory sealing itself. The sealing is applied by default, and it is always enforced with glibc.rtld.seal=2. Checked on aarch64-linux-gnu, x86_64-linux-gnu, and powerpc64le-linux-gnu. [1] https://glandium.org/blog/?p=4297 --- configure | 35 ++++++++++ configure.ac | 5 ++ elf/dl-load.c | 4 +- elf/dl-open.c | 2 +- elf/dl-reloc.c | 18 ++--- elf/dl-support.c | 4 +- elf/elf.h | 2 + elf/rtld.c | 10 +-- include/link.h | 1 + string/strerrorname_np.c | 1 - sysdeps/aarch64/dl-prop.h | 5 ++ sysdeps/generic/dl-mseal.h | 2 - sysdeps/generic/dl-prop-mseal.h | 38 +++++++++++ sysdeps/generic/dl-prop.h | 5 ++ sysdeps/generic/ldsodefs.h | 11 ++-- sysdeps/unix/sysv/linux/Makefile | 46 +++++++++++++ sysdeps/unix/sysv/linux/dl-mseal.h | 2 - .../tst-dl_mseal-dlopen-no-memory-seal-2-1.c | 19 ++++++ .../tst-dl_mseal-dlopen-no-memory-seal-2.c | 19 ++++++ .../linux/tst-dl_mseal-mod-no-memory-seal-1.c | 19 ++++++ .../linux/tst-dl_mseal-mod-no-memory-seal-2.c | 19 ++++++ .../tst-dl_mseal-no-memory-seal-auditmod.c | 1 + .../tst-dl_mseal-no-memory-seal-preload.c | 1 + .../sysv/linux/tst-dl_mseal-no-memory-seal.c | 65 +++++++++++++++++++ .../unix/sysv/linux/tst-dl_mseal-skeleton.c | 6 +- .../tst-dl_mseal-static-no-memory-seal.c | 38 +++++++++++ sysdeps/x86/dl-prop.h | 4 ++ 27 files changed, 350 insertions(+), 32 deletions(-) create mode 100644 sysdeps/generic/dl-prop-mseal.h create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2-1.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-1.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-2.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-auditmod.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-preload.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal.c create mode 100644 sysdeps/unix/sysv/linux/tst-dl_mseal-static-no-memory-seal.c diff --git a/configure b/configure index 1d543548cd..31deacc983 100755 --- a/configure +++ b/configure @@ -7102,6 +7102,41 @@ printf "%s\n" "$libc_linker_feature" >&6; } config_vars="$config_vars have-no-dynamic-linker = $libc_cv_no_dynamic_linker" +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -z no-memory-seal" >&5 +printf %s "checking for linker that supports -z no-memory-seal... " >&6; } +libc_linker_feature=no +cat > conftest.c <&5 + (eval $ac_try) 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then + if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,-z,no-memory-seal -nostdlib \ + -nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \ + | grep "warning: -z no-memory-seal ignored" > /dev/null 2>&1; then + true + else + libc_linker_feature=yes + fi +fi +rm -f conftest* +if test $libc_linker_feature = yes; then + libc_cv_z_no_memory_seal=yes +else + libc_cv_z_no_memory_seal=no +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5 +printf "%s\n" "$libc_linker_feature" >&6; } +config_vars="$config_vars +have-z-no-memory-seal = $libc_cv_z_no_memory_seal" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for -static-pie" >&5 printf %s "checking for -static-pie... " >&6; } if test ${libc_cv_static_pie+y} diff --git a/configure.ac b/configure.ac index 9cbc0bf68f..a8fc276cfb 100644 --- a/configure.ac +++ b/configure.ac @@ -1278,6 +1278,11 @@ LIBC_LINKER_FEATURE([--no-dynamic-linker], [libc_cv_no_dynamic_linker=no]) LIBC_CONFIG_VAR([have-no-dynamic-linker], [$libc_cv_no_dynamic_linker]) +LIBC_LINKER_FEATURE([-z no-memory-seal], + [-Wl,-z,no-memory-seal], + [libc_cv_z_no_memory_seal=yes], [libc_cv_z_no_memory_seal=no]) +LIBC_CONFIG_VAR([have-z-no-memory-seal], [$libc_cv_z_no_memory_seal]) + AC_CACHE_CHECK(for -static-pie, libc_cv_static_pie, [dnl LIBC_TRY_CC_OPTION([-static-pie], [libc_cv_static_pie=yes], diff --git a/elf/dl-load.c b/elf/dl-load.c index 4c2371ec46..17b64363f7 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1431,7 +1431,9 @@ cannot enable executable stack as shared object requires"); /* Assign the next available module ID. */ _dl_assign_tls_modid (l); - l->l_seal = mode & RTLD_NODELETE ? lt_seal_toseal : lt_seal_dont; + /* Do not alter the sealing if the GNU property disables it. */ + if (l->l_seal == lt_seal_undefined && mode & RTLD_NODELETE) + l->l_seal = lt_seal_toseal; #ifdef DL_AFTER_LOAD DL_AFTER_LOAD (l); diff --git a/elf/dl-open.c b/elf/dl-open.c index f53b1b0572..7cc39fba5b 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -841,7 +841,7 @@ dl_open_worker (void *a) /* The seal flag is set only for NEW, however its dependencies could not be unloaded and thus can also be sealed. */ - _dl_mseal_map (new, true); + _dl_mseal_map (new, true, false); } void * diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 6bb424f789..4a81c3914c 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -352,7 +352,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], /* Seal the memory mapping after RELRO setup, we can use the PT_LOAD segments because even if relro splits the the original RW VMA, mseal works with multiple VMAs with different flags. */ - _dl_mseal_map (l, false); + _dl_mseal_map (l, false, false); } @@ -376,11 +376,10 @@ cannot apply additional memory protection after relocation"); } static void -_dl_mseal_map_1 (struct link_map *l) +_dl_mseal_map_1 (struct link_map *l, bool force) { - /* We only checked if the map is already sealed here so we can seal audit - module dependencies after the initial audit setup. */ - if (l->l_seal == lt_seal_sealed) + if (l->l_seal == lt_seal_dont + || (!force && (l->l_seal != lt_seal_toseal))) return; int r = -1; @@ -408,16 +407,13 @@ _dl_mseal_map_1 (struct link_map *l) } void -_dl_mseal_map (struct link_map *l, bool dep) +_dl_mseal_map (struct link_map *l, bool dep, bool force) { - if (l->l_seal == lt_seal_dont || l->l_seal == lt_seal_sealed) - return; - if (l->l_searchlist.r_list == NULL || !dep) - _dl_mseal_map_1 (l); + _dl_mseal_map_1 (l, force); else for (unsigned int i = 0; i < l->l_searchlist.r_nlist; ++i) - _dl_mseal_map_1 (l->l_searchlist.r_list[i]); + _dl_mseal_map_1 (l->l_searchlist.r_list[i], force); } void diff --git a/elf/dl-support.c b/elf/dl-support.c index a02ae712b3..dd02943dd0 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -101,7 +101,7 @@ static struct link_map _dl_main_map = .l_used = 1, .l_tls_offset = NO_TLS_OFFSET, .l_serial = 1, - .l_seal = SUPPORT_MSEAL, + .l_seal = lt_seal_toseal, }; /* Namespace information. */ @@ -359,7 +359,7 @@ _dl_non_dynamic_init (void) /* Seal the memory mapping after RELRO setup, we can use the PT_LOAD segments because even if relro splits the the original RW VMA, mseal works with multiple VMAs with different flags. */ - _dl_mseal_map (&_dl_main_map, false); + _dl_mseal_map (&_dl_main_map, false, false); } #ifdef DL_SYSINFO_IMPLEMENTATION diff --git a/elf/elf.h b/elf/elf.h index 33aea7f743..62f493b9ee 100644 --- a/elf/elf.h +++ b/elf/elf.h @@ -1357,6 +1357,8 @@ typedef struct #define GNU_PROPERTY_STACK_SIZE 1 /* No copy relocation on protected data symbol. */ #define GNU_PROPERTY_NO_COPY_ON_PROTECTED 2 +/* No memory sealing. */ +#define GNU_PROPERTY_NO_MEMORY_SEAL 3 /* A 4-byte unsigned integer property: A bit is set if it is set in all relocatable inputs. */ diff --git a/elf/rtld.c b/elf/rtld.c index efe7e97b04..23b651ee55 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -478,7 +478,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) GL(dl_rtld_map).l_real = &GL(dl_rtld_map); GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start; GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end; - GL(dl_rtld_map).l_seal = 1; + GL(dl_rtld_map).l_seal = lt_seal_toseal; /* Copy the TLS related data if necessary. */ #ifndef DONT_USE_BOOTSTRAP_MAP # if NO_TLS_OFFSET != 0 @@ -1046,9 +1046,9 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d); /* Mark the DSO as being used for auditing. */ dlmargs.map->l_auditing = 1; - /* Seal the audit modules and their dependencies. */ - dlmargs.map->l_seal = lt_seal_toseal; - _dl_mseal_map (dlmargs.map, true); + /* Since audit modules can not be loaded with RTLD_NODELETE, force the + sealing of the modules and its dependencies. */ + _dl_mseal_map (dlmargs.map, true, true); } /* Load all audit modules. */ @@ -1131,7 +1131,7 @@ rtld_setup_main_map (struct link_map *main_map) /* And it was opened directly. */ ++main_map->l_direct_opencount; main_map->l_contiguous = 1; - main_map->l_seal = 1; + main_map->l_seal = lt_seal_toseal; /* A PT_LOAD segment at an unexpected address will clear the l_contiguous flag. The ELF specification says that PT_LOAD diff --git a/include/link.h b/include/link.h index fd8e7f25bf..176f4abddd 100644 --- a/include/link.h +++ b/include/link.h @@ -214,6 +214,7 @@ struct link_map lt_library map. */ enum /* Memory sealing status. */ { + lt_seal_undefined = 0, /* No set. */ lt_seal_dont, /* Do not seal the object. */ lt_seal_toseal, /* The library is marked to be sealed. */ lt_seal_sealed /* The library is sealed. */ diff --git a/string/strerrorname_np.c b/string/strerrorname_np.c index e0e22fa79e..042cea381c 100644 --- a/string/strerrorname_np.c +++ b/string/strerrorname_np.c @@ -17,7 +17,6 @@ . */ #include -#include const char * strerrorname_np (int errnum) diff --git a/sysdeps/aarch64/dl-prop.h b/sysdeps/aarch64/dl-prop.h index df05c0211d..c66d9a49f0 100644 --- a/sysdeps/aarch64/dl-prop.h +++ b/sysdeps/aarch64/dl-prop.h @@ -19,6 +19,8 @@ #ifndef _DL_PROP_H #define _DL_PROP_H +#include + extern void _dl_bti_protect (struct link_map *, int) attribute_hidden; extern void _dl_bti_check (struct link_map *, const char *) @@ -45,6 +47,9 @@ static inline int _dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, uint32_t datasz, void *data) { + if (_dl_process_gnu_property_seal (l, fd, type, datasz, data)) + return 0; + if (!GLRO(dl_aarch64_cpu_features).bti) /* Skip note processing. */ return 0; diff --git a/sysdeps/generic/dl-mseal.h b/sysdeps/generic/dl-mseal.h index d542fcac75..dccf78ae38 100644 --- a/sysdeps/generic/dl-mseal.h +++ b/sysdeps/generic/dl-mseal.h @@ -21,5 +21,3 @@ _dl_mseal (void *addr, size_t len) { return 0; } - -#define SUPPORT_MSEAL lt_seal_dont diff --git a/sysdeps/generic/dl-prop-mseal.h b/sysdeps/generic/dl-prop-mseal.h new file mode 100644 index 0000000000..b9dbd24fa5 --- /dev/null +++ b/sysdeps/generic/dl-prop-mseal.h @@ -0,0 +1,38 @@ +/* Support for GNU properties. Generic version. + Copyright (C) 2024 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 + . */ + +#ifndef _DL_PROP_MSEAL_H +#define _LD_PROP_MSEAL_H + +#include +#include + +static __always_inline bool +_dl_process_gnu_property_seal (struct link_map *l, int fd, uint32_t type, + uint32_t datasz, void *data) +{ + if (type == GNU_PROPERTY_NO_MEMORY_SEAL && datasz == 0) + { + int32_t mode = TUNABLE_GET (glibc, rtld, seal, int32_t, NULL); + l->l_seal = (mode == DL_SEAL_ENFORCE) ? lt_seal_toseal : lt_seal_dont; + return true; + } + return false; +} + +#endif diff --git a/sysdeps/generic/dl-prop.h b/sysdeps/generic/dl-prop.h index 1d92920a96..5fac690c81 100644 --- a/sysdeps/generic/dl-prop.h +++ b/sysdeps/generic/dl-prop.h @@ -19,6 +19,8 @@ #ifndef _DL_PROP_H #define _DL_PROP_H +#include + /* The following functions are used by the dynamic loader and the dlopen machinery to process PT_NOTE and PT_GNU_PROPERTY entries in the binary or shared object. The notes can be used to change the @@ -47,6 +49,9 @@ static inline int __attribute__ ((always_inline)) _dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, uint32_t datasz, void *data) { + if (_dl_process_gnu_property_seal (l, fd, type, datasz, data)) + return 0; + /* Continue until GNU_PROPERTY_1_NEEDED is found. */ if (type == GNU_PROPERTY_1_NEEDED) { diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index aad5a219df..577f3ae06b 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -1017,10 +1017,13 @@ extern void _dl_relocate_object (struct link_map *map, /* Protect PT_GNU_RELRO area. */ extern void _dl_protect_relro (struct link_map *map) attribute_hidden; -/* Protect MAP with mseal. If MAP is contiguous the while region is - sealed, otherwise iterate over the phdr to seal each PT_LOAD. The DEP - specify whether to seal the dependencies as well. */ -extern void _dl_mseal_map (struct link_map *map, bool dep) +/* Issue memory sealing for the link map MAP. If MAP is contiguous the + whole region is sealed, otherwise iterate over the program headerrs and + seal each PT_LOAD segment.i + The DEP specify whether to seal the dependencies as well, while FORCE + ignores if previous seal configuration (such as + GNU_PROPERTY_NO_MEMORY_SEAL mark). */ +extern void _dl_mseal_map (struct link_map *map, bool dep, bool force) attribute_hidden; /* Call _dl_signal_error with a message about an unhandled reloc type. diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 3161363db1..c82aeb3403 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -685,6 +685,52 @@ $(objpfx)tst-dl_mseal-dlopen-2.so: $(objpfx)tst-dl_mseal-dlopen-2-1.so LDFLAGS-tst-dl_mseal-dlopen-2.so = -Wl,--no-as-needed tst-dl_mseal-static-ARGS = -- $(host-test-program-cmd) + +ifeq ($(have-z-no-memory-seal),yes) +tests-static += \ + tst-dl_mseal-static-no-memory-seal \ + # tests-static + +tests += \ + tst-dl_mseal-no-memory-seal \ + tst-dl_mseal-static-no-memory-seal \ + # tests + +modules-names += \ + tst-dl_mseal-dlopen-no-memory-seal-2 \ + tst-dl_mseal-dlopen-no-memory-seal-2-1 \ + tst-dl_mseal-mod-no-memory-seal-1 \ + tst-dl_mseal-mod-no-memory-seal-2 \ + tst-dl_mseal-no-memory-seal-auditmod \ + tst-dl_mseal-no-memory-seal-preload \ + # modules-names + +$(objpfx)tst-dl_mseal-no-memory-seal.out: \ + $(objpfx)tst-dl_mseal-no-memory-seal-auditmod.so \ + $(objpfx)tst-dl_mseal-no-memory-seal-preload.so \ + $(objpfx)tst-dl_mseal-mod-no-memory-seal-1.so \ + $(objpfx)tst-dl_mseal-mod-no-memory-seal-2.so \ + $(objpfx)tst-dl_mseal-dlopen-1.so \ + $(objpfx)tst-dl_mseal-dlopen-1-1.so \ + $(objpfx)tst-dl_mseal-dlopen-no-memory-seal-2.so \ + $(objpfx)tst-dl_mseal-dlopen-no-memory-seal-2-1.so + +tst-dl_mseal-no-memory-seal-ARGS = -- $(host-test-program-cmd) + +LDFLAGS-tst-dl_mseal-no-memory-seal-preload.so = -Wl,-z,no-memory-seal + +LDFLAGS-tst-dl_mseal-no-memory-seal-auditmod.so = -Wl,-z,no-memory-seal +$(objpfx)tst-dl_mseal-no-memory-seal: $(objpfx)tst-dl_mseal-mod-no-memory-seal-1.so +LDFLAGS-tst-dl_mseal-no-memory-seal = -Wl,-z,no-memory-seal -Wl,--no-as-needed +$(objpfx)tst-dl_mseal-mod-no-memory-seal-1.so: $(objpfx)tst-dl_mseal-mod-no-memory-seal-2.so +LDFLAGS-tst-dl_mseal-mod-no-memory-seal-1.so = -Wl,--no-as-needed +LDFLAGS-tst-dl_mseal-mod-no-memory-seal-2.so = -Wl,-z,no-memory-seal -Wl,--no-as-needed +$(objpfx)tst-dl_mseal-dlopen-no-memory-seal-2.so: $(objpfx)tst-dl_mseal-dlopen-no-memory-seal-2-1.so +LDFLAGS-tst-dl_mseal-dlopen-no-memory-seal-2.so = -Wl,--no-as-needed -Wl,-z,no-memory-seal + +LDFLAGS-tst-dl_mseal-static-no-memory-seal = -Wl,-z,no-memory-seal +tst-dl_mseal-static-no-memory-seal-ARGS = -- $(host-test-program-cmd) +endif endif ifeq ($(subdir),rt) diff --git a/sysdeps/unix/sysv/linux/dl-mseal.h b/sysdeps/unix/sysv/linux/dl-mseal.h index 89b19e33c4..25e3f724dc 100644 --- a/sysdeps/unix/sysv/linux/dl-mseal.h +++ b/sysdeps/unix/sysv/linux/dl-mseal.h @@ -25,5 +25,3 @@ Return 0 in case of success or a negative value otherwise (a negative errno). */ int _dl_mseal (void *addr, size_t len) attribute_hidden; - -#define SUPPORT_MSEAL lt_seal_toseal diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2-1.c new file mode 100644 index 0000000000..0cd647de46 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2-1.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int bar2_1 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2.c new file mode 100644 index 0000000000..f719dd3cba --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-dlopen-no-memory-seal-2.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int bar2 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-1.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-1.c new file mode 100644 index 0000000000..3bd188efe8 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-1.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int foo1 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-2.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-2.c new file mode 100644 index 0000000000..636e9777af --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-mod-no-memory-seal-2.c @@ -0,0 +1,19 @@ +/* Additional module for tst-dl_mseal test. + Copyright (C) 2024 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 + . */ + +int bar1 (void) { return 42; } diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-auditmod.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-auditmod.c new file mode 100644 index 0000000000..a5b257d05e --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-auditmod.c @@ -0,0 +1 @@ +#include "tst-dl_mseal-auditmod.c" diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-preload.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-preload.c new file mode 100644 index 0000000000..32b4153e79 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal-preload.c @@ -0,0 +1 @@ +#include "tst-dl_mseal-preload.c" diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal.c new file mode 100644 index 0000000000..014a8e76c7 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-no-memory-seal.c @@ -0,0 +1,65 @@ +/* Basic tests for sealing. + Copyright (C) 2024 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 + +/* This test checks the GNU_PROPERTY_NO_MEMORY_SEAL handling on multiple + places: + + - On the binary itself. + - On a LD_PRELOAD library. + - On a depedency module (tst-dl_mseal-mod-no-memory-seal-2.so). + - On a audit modules (tst-dl_mseal-no-memory-seal-auditmod.so). + - On a dlopen dependency opened with RTLD_NODELET + (tst-dl_mseal-dlopen-no-memory-seal-2.so). +*/ + +#define LIB_PRELOAD "tst-dl_mseal-no-memory-seal-preload.so" +#define GLIBC_RTLD_SEAL "1" + +#define LIB_DLOPEN_DEFAULT "tst-dl_mseal-dlopen-1.so" +#define LIB_DLOPEN_DEFAULT_DEP "tst-dl_mseal-dlopen-1-1.so" +#define LIB_DLOPEN_NODELETE "tst-dl_mseal-dlopen-no-memory-seal-2.so" +#define LIB_DLOPEN_NODELETE_DEP "tst-dl_mseal-dlopen-no-memory-seal-2-1.so" + +#define LIB_AUDIT "tst-dl_mseal-no-memory-seal-auditmod.so" + +/* Expected libraries that loader will seal. */ +static const char *expected_sealed_libs[] = +{ + "libc.so", + "ld.so", + "tst-dl_mseal-mod-no-memory-seal-1.so", + LIB_DLOPEN_NODELETE_DEP, + LIBGCC_S_SO, +}; + +/* Expected non sealed libraries. */ +static const char *expected_non_sealed_libs[] = +{ + "[vdso]", + "tst-dl_mseal-no-memory-seal", + LIB_PRELOAD, + LIB_AUDIT, + "tst-dl_mseal-mod-no-memory-seal-2.so", + LIB_DLOPEN_DEFAULT, + LIB_DLOPEN_DEFAULT_DEP, + LIB_DLOPEN_NODELETE, +}; + +#include "tst-dl_mseal-skeleton.c" diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c index fbf18d9b7c..6c77b14d86 100644 --- a/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-skeleton.c @@ -1,4 +1,4 @@ -/* Basic tests for sealing. Static version. +/* Basic tests for sealing. Copyright (C) 2024 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -198,7 +198,7 @@ handle_restart (void) /* Also check if all the expected sealed maps were found. */ for (int i = 0; i < array_length (expected_sealed_libs); i++) - if (!found_expected[i]) + if (expected_sealed_libs[i][0] && !found_expected[i]) FAIL_EXIT1 ("expected VMA %s not sealed\n", expected_sealed_libs[i]); return 0; @@ -239,7 +239,7 @@ do_test (int argc, char *argv[]) spargv[i] = NULL; char *envvarss[4]; - envvarss[0] = (char *) "GLIBC_TUNABLES=glibc.rtld.seal=2"; + envvarss[0] = (char *) "GLIBC_TUNABLES=glibc.rtld.seal=" GLIBC_RTLD_SEAL; #ifndef TEST_STATIC envvarss[1] = (char *) "LD_PRELOAD=" LIB_PRELOAD; envvarss[2] = (char *) "LD_AUDIT=" LIB_AUDIT, diff --git a/sysdeps/unix/sysv/linux/tst-dl_mseal-static-no-memory-seal.c b/sysdeps/unix/sysv/linux/tst-dl_mseal-static-no-memory-seal.c new file mode 100644 index 0000000000..257500ea47 --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-dl_mseal-static-no-memory-seal.c @@ -0,0 +1,38 @@ +/* Basic tests for sealing. Static version. + Copyright (C) 2024 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 + . */ + +/* This test checks the GNU_PROPERTY_NO_MEMORY_SEAL handling on a statically + built binary. In this case only the vDSO (if existent) will be sealed. */ + +#define GLIBC_RTLD_SEAL "1" +#define TEST_STATIC 1 + +/* Expected libraries that loader will seal. */ +static const char *expected_sealed_libs[] = +{ + "", +}; + +/* Expected non sealed libraries. */ +static const char *expected_non_sealed_libs[] = +{ + "[vdso]", + "tst-dl_mseal-static-no-memory-seal", +}; + +#include "tst-dl_mseal-skeleton.c" diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h index 08387dfaff..26a687d611 100644 --- a/sysdeps/x86/dl-prop.h +++ b/sysdeps/x86/dl-prop.h @@ -19,6 +19,7 @@ #ifndef _DL_PROP_H #define _DL_PROP_H +#include #include extern void _dl_cet_check (struct link_map *, const char *) @@ -241,6 +242,9 @@ _dl_process_gnu_property (struct link_map *l, int fd, uint32_t type, uint32_t datasz, void *data) { /* This is called on each GNU property. */ + if (_dl_process_gnu_property_seal (l, fd, type, datasz, data)) + return 0; + unsigned int needed_1 = 0; unsigned int feature_1_and = 0; unsigned int isa_1_needed = 0;