From patchwork Fri Nov 5 13:59:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 47112 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 9EE413858411 for ; Fri, 5 Nov 2021 14:01:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9EE413858411 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1636120894; bh=FNh59/FyM3CgVJ5wtBnNOusiAgAAO03Cv7hqgCYY2FU=; h=To:Subject:In-Reply-To:References:Date:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=U8n0S0mCn1ygsdbIvCgVrMXNen7u3KDEzFoemfbARvZlsPpZwhmKyrCW/n7H5RC+U E1F5P3T079J0FX92oT59xB4uPnqYUYO1Ki4GOlOC/5LSU39Cd6VPKTIiObQYwnW1Nx gPxaf5mRo1Tr8wU0ZhKHlg2bxnjFQlXwYNNnZac4= X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTPS id D180A3858428 for ; Fri, 5 Nov 2021 14:00:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D180A3858428 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-437-U6Rct4VKMfeTB6J8PryFcA-1; Fri, 05 Nov 2021 10:00:33 -0400 X-MC-Unique: U6Rct4VKMfeTB6J8PryFcA-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 7546A80670A for ; Fri, 5 Nov 2021 13:59:22 +0000 (UTC) Received: from oldenburg.str.redhat.com (unknown [10.39.192.25]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 4D38817A89 for ; Fri, 5 Nov 2021 13:59:20 +0000 (UTC) To: libc-alpha@sourceware.org Subject: [PATCH 2/2] elf: Detect PT_LOAD segments that extend beyond EOF and refuse loading In-Reply-To: References: X-From-Line: 27f078539ae2a5b390705ac6fa1a7437ae8ce97c Mon Sep 17 00:00:00 2001 Message-Id: <27f078539ae2a5b390705ac6fa1a7437ae8ce97c.1636120354.git.fweimer@redhat.com> Date: Fri, 05 Nov 2021 14:59:18 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Florian Weimer via Libc-alpha From: Florian Weimer Reply-To: Florian Weimer Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" We occasionally see elf/tst-debug1 failing with a SIGBUS error with some toolchain versions (recently on aarch64 only). This test tries to emulate loading separated debuginfo, but whether the test object triggers the crash depends on many factors. Accurately rejected separated debuginfo in dlopen probably needs ELF markup, at least if this is to be done efficiently using program headers only. But this change still improves user experience slightly. We already obtain the file size from the kernel in most cases, so no additional system call is added. Based on earlier downstream-only patch by Jeff Law. --- elf/dl-load.c | 78 +++++++++++++++++++++---------------- sysdeps/generic/dl-fileid.h | 7 ++-- 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/elf/dl-load.c b/elf/dl-load.c index a1f1682188..a758bed9af 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -953,47 +953,48 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, struct r_debug *r = _dl_debug_update (nsid); bool make_consistent = false; - /* Get file information. To match the kernel behavior, do not fill - in this information for the executable in case of an explicit - loader invocation. */ + /* Get file information. */ struct r_file_id id; + off64_t file_size; + if (__glibc_unlikely (!_dl_get_file_id (fd, &id, &file_size))) + { + errstring = N_("cannot stat shared object"); + lose_errno: + errval = errno; + lose: + /* The file might already be closed. */ + if (fd != -1) + __close_nocancel (fd); + if (l != NULL && l->l_map_start != 0) + _dl_unmap_segments (l); + if (l != NULL && l->l_origin != (char *) -1l) + free ((char *) l->l_origin); + if (l != NULL && !l->l_libname->dont_free) + free (l->l_libname); + if (l != NULL && l->l_phdr_allocated) + free ((void *) l->l_phdr); + free (l); + free (realname); + + if (make_consistent && r != NULL) + { + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + LIBC_PROBE (map_failed, 2, nsid, r); + } + + _dl_signal_error (errval, name, NULL, errstring); + } + if (mode & __RTLD_OPENEXEC) { assert (nsid == LM_ID_BASE); + /* To match the kernel behavior, do not fill in this information + for the executable in case of an explicit loader invocation. */ memset (&id, 0, sizeof (id)); } else { - if (__glibc_unlikely (!_dl_get_file_id (fd, &id))) - { - errstring = N_("cannot stat shared object"); - lose_errno: - errval = errno; - lose: - /* The file might already be closed. */ - if (fd != -1) - __close_nocancel (fd); - if (l != NULL && l->l_map_start != 0) - _dl_unmap_segments (l); - if (l != NULL && l->l_origin != (char *) -1l) - free ((char *) l->l_origin); - if (l != NULL && !l->l_libname->dont_free) - free (l->l_libname); - if (l != NULL && l->l_phdr_allocated) - free ((void *) l->l_phdr); - free (l); - free (realname); - - if (make_consistent && r != NULL) - { - r->r_state = RT_CONSISTENT; - _dl_debug_state (); - LIBC_PROBE (map_failed, 2, nsid, r); - } - - _dl_signal_error (errval, name, NULL, errstring); - } - /* Look again to see if the real name matched another already loaded. */ for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next) if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id)) @@ -1177,6 +1178,17 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, = N_("ELF load command address/offset not properly aligned"); goto lose; } + if (__glibc_unlikely (ph->p_offset + ph->p_filesz > file_size)) + { + /* If the segment is not fully backed by the file, + accessing memory beyond the last full page results in + SIGBUS. This often happens with non-loadable ELF + objects containing separated debugging information + (which have load segments that match the original ELF + file). */ + errstring = N_("ELF load command past end of file"); + goto lose; + } struct loadcmd *c = &loadcmds[nloadcmds++]; c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize)); diff --git a/sysdeps/generic/dl-fileid.h b/sysdeps/generic/dl-fileid.h index bf437f3d71..c59627429c 100644 --- a/sysdeps/generic/dl-fileid.h +++ b/sysdeps/generic/dl-fileid.h @@ -27,10 +27,10 @@ struct r_file_id ino64_t ino; }; -/* Sample FD to fill in *ID. Returns true on success. - On error, returns false, with errno set. */ +/* Sample FD to fill in *ID, *SIZE. Returns true on success. On + error, returns false, with errno set. */ static inline bool -_dl_get_file_id (int fd, struct r_file_id *id) +_dl_get_file_id (int fd, struct r_file_id *id, off64_t *size) { struct __stat64_t64 st; @@ -39,6 +39,7 @@ _dl_get_file_id (int fd, struct r_file_id *id) id->dev = st.st_dev; id->ino = st.st_ino; + *size = st.st_size; return true; }