From patchwork Mon Oct 17 19:38:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asaf Fisher X-Patchwork-Id: 58957 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 A7B263857B81 for ; Mon, 17 Oct 2022 19:39:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A7B263857B81 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1666035579; bh=AsEttQb5WBvGMSgeagsRASLW3o41fmKBg7RMnLifQiY=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=HovXRIwmRGYt67m+EU/7KhEIZDkCrfY84TUS68JD647nzQszXMbXxxx45nlP2ri15 AmmC6hGFKKdBJYSbBLvRnyVa0mllgcvqKKiyZdOaBG5JAGQOSqoK2ZigfdHL6CIXb/ BsRsHkl/rmhlTqCLr7U7WzIiOpAl/+ZGD6xk6p5g= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-ed1-x533.google.com (mail-ed1-x533.google.com [IPv6:2a00:1450:4864:20::533]) by sourceware.org (Postfix) with ESMTPS id D987E3858D32 for ; Mon, 17 Oct 2022 19:39:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org D987E3858D32 Received: by mail-ed1-x533.google.com with SMTP id r14so17536266edc.7 for ; Mon, 17 Oct 2022 12:39:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=AsEttQb5WBvGMSgeagsRASLW3o41fmKBg7RMnLifQiY=; b=3a89Y0L3O/tFyWZB/O+rkccOFwq1tnkiHynrqnHbPk6JcWYYFFNq9yvDWbMJG0lJ4Q YEEi36gpd8Ctikn86c2JlK0iCDUqidsbcM2GM+mFaL3rS9g6hh2/5RABpyeHCyBuLrHP ncotHppqAv5ZhBqTehJzDtaFrNPhj+ycwCfEMu4mV5YwUSI5ixPmIqKp+sEcVtUUNb5M M7YBWHK8W6964TfixwQoP9NKjoFJUOBAZ7BU/5JlVdBswIoNIt4UaJEmVZ5VfqSy0bG6 4PksN8xGpYWi9PCPAYwUORmhz2xQv7vjb4w3iTuU48XxagLt3IV64DZT2Q3tT7HwAPm8 GQAA== X-Gm-Message-State: ACrzQf16v+2icuxNyh9zHopdwXFy4qDEMSvpimeYHAN1n53SBD/ATETc hpsudFleACeBRc9+O4XU+kFeDjNAl+hylzuR X-Google-Smtp-Source: AMsMyM73vVguth7Q2Dipnzw6xghvKr7zS9v5qKFmTfCgTYmL6o1hEkRgnJiPbr3hdX6Dl7Ue764f0A== X-Received: by 2002:aa7:d357:0:b0:45b:dab5:9789 with SMTP id m23-20020aa7d357000000b0045bdab59789mr12094918edr.222.1666035543123; Mon, 17 Oct 2022 12:39:03 -0700 (PDT) Received: from codespaces-99e6ae.mo2cupmyp0zuvhb2b0itoyabtg.ax.internal.cloudapp.net ([20.160.121.11]) by smtp.gmail.com with ESMTPSA id p11-20020a170906604b00b0078df3b4464fsm6699544ejj.19.2022.10.17.12.39.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Oct 2022 12:39:02 -0700 (PDT) To: gdb-patches@sourceware.org Subject: [PATCH 1/2] Add test to check GDB handles dlopen of /proc/self/fd/[num] correctly Date: Mon, 17 Oct 2022 19:38:57 +0000 Message-Id: <20221017193858.3006-2-asaffisher.dev@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221017193858.3006-1-asaffisher.dev@gmail.com> References: <20221017193858.3006-1-asaffisher.dev@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, 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: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Asaf Fisher via Gdb-patches From: Asaf Fisher Reply-To: Asaf Fisher Cc: Asaf Fisher Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" This test checks that GDB handles correctly paths in the form of `/proc/self/...` when inferior dlopen them. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29586 --- gdb/testsuite/gdb.base/solib-proc-self.cc | 72 ++++++++++++++++++ gdb/testsuite/gdb.base/solib-proc-self.exp | 86 ++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 gdb/testsuite/gdb.base/solib-proc-self.cc create mode 100644 gdb/testsuite/gdb.base/solib-proc-self.exp diff --git a/gdb/testsuite/gdb.base/solib-proc-self.cc b/gdb/testsuite/gdb.base/solib-proc-self.cc new file mode 100644 index 00000000000..dc0b446d53c --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-proc-self.cc @@ -0,0 +1,72 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2007-2022 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __WIN32__ +#include +#define dlopen(name, mode) LoadLibrary (name) +#define dlclose(handle) FreeLibrary (handle) +#define dlerror() "an error occurred" +#else +#include +#endif + +int main() +{ + void *handle; + /* Read the so's content to a buffer */ + std::ifstream read_so_file = std::ifstream(SHLIB_NAME); + read_so_file.seekg(0, std::ios::end); + std::streamsize size = read_so_file.tellg(); + read_so_file.seekg(0, std::ios::beg); + std::vector buffer(size); + if (!read_so_file.read(buffer.data(), size)) + { + fprintf (stderr, "Failed to load solib\n"); + exit(1); + } + + int mem_fd = memfd_create("test", 0); + + /* Write the so's data to the memory mapped file. */ + write(mem_fd, buffer.data(), buffer.size()); + + /* Generate the /proc/self/fd/[num] path */ + std::string prof_self_fd_path; /* break-here */ + std::stringstream prof_self_fd_path_stream = std::stringstream(prof_self_fd_path); + prof_self_fd_path_stream << "/proc/self/fd/" << mem_fd; + + /* Call dlopen on it */ + handle = dlopen (prof_self_fd_path_stream.str().c_str(), RTLD_LAZY); + if (!handle) + { + fprintf (stderr, "%s\n", dlerror ()); + exit (1); + } + /* YAY it worked */ + dlclose (handle); + + return 0; +} diff --git a/gdb/testsuite/gdb.base/solib-proc-self.exp b/gdb/testsuite/gdb.base/solib-proc-self.exp new file mode 100644 index 00000000000..b59ba357492 --- /dev/null +++ b/gdb/testsuite/gdb.base/solib-proc-self.exp @@ -0,0 +1,86 @@ +# Copyright 2007-2022 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . */ + +# Test connecting and disconnecting at shared library events. + +if {[skip_shlib_tests]} { + untested "could not run to main" + return 0 +} + +standard_testfile .cc + +# Chose random lib +set libfile so-disc-shr +set libsrc "${srcdir}/${subdir}/${libfile}.c" +set libname "${libfile}.so" +set libobj [standard_output_file ${libname}] + +# Compile the shared lib +if { [gdb_compile_shlib $libsrc $libobj {debug}] != ""} { + return -1 +} + +# Compile test +if [ prepare_for_testing "failed to prepare" $testfile $srcfile "list shlib_load debug c++ additional_flags=-DSHLIB_NAME=\"${libobj}\"" ] { + return -1 +} + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} +gdb_load_shlib $libobj + +if ![runto_main] then { + return 0 +} + +# Get inferior's PID for later +set inferior_pid -1 +gdb_test_multiple "info inferior 1" "get inferior pid" { + -re "process (\[0-9\]*).*$gdb_prompt $" { + set inferior_pid $expect_out(1,string) + pass $gdb_test_name + } +} + +# Turn on the solib-events so we can see that gdb resolves everything correctly +gdb_test_no_output "set stop-on-solib-events 1" + +# I use this breakpoint to get the memory mapped fd. +gdb_breakpoint [gdb_get_line_number "break-here"] +gdb_continue_to_breakpoint "break-here" ".* break-here .*" + +set msg "Getting MEMFD" +set memfd "" +gdb_test_multiple "p mem_fd" $msg { + -re "\\\$$decimal = (\[^\r\n\]*)\r\n$gdb_prompt $" { + set memfd $expect_out(1,string) + pass $msg + } +} + +gdb_test "continue" "Stopped due to shared library event.*" "continue to load" + +# Check if inferior resolved the /proc/self/fd/[num] to /proc/[pid]/fd/[num] +set msg "Inferior's /proc/self resolving $inferior_pid $memfd" +set inferior_proc_self_path "" +gdb_test_multiple "continue" $msg { + -re "Attempting to replace `self` with inferior's PID. -> (\/proc\/$inferior_pid\/fd\/$memfd\[^\r\n\]*)\r\n.*$gdb_prompt $" { + set inferior_proc_self_path $expect_out(1,string) + pass $msg + } +} From patchwork Mon Oct 17 19:38:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asaf Fisher X-Patchwork-Id: 58959 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 5BF153858036 for ; Mon, 17 Oct 2022 19:40:06 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5BF153858036 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1666035606; bh=lhZ8imXwKWb/W+6b/TkKWPhczv24PYGHpODbc3pDlKw=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=xpF3peZ3+F4M8I4zvamjy0FW1WvG+j4rIFbtNZrbo0psxHuF863lWhsQlqwxb0+di K+6m20TQUVOG83IrpQSArG5+YQ9SgdJ0rWf7b25DpHno47olN5v9TcM/wEIc/r9IDi EnbpuYFqxRxYje/y5lw9vnB1GaRshLPrcvymRsSU= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-ed1-x52b.google.com (mail-ed1-x52b.google.com [IPv6:2a00:1450:4864:20::52b]) by sourceware.org (Postfix) with ESMTPS id 37FFE3858C50 for ; Mon, 17 Oct 2022 19:39:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 37FFE3858C50 Received: by mail-ed1-x52b.google.com with SMTP id a13so17591854edj.0 for ; Mon, 17 Oct 2022 12:39:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=lhZ8imXwKWb/W+6b/TkKWPhczv24PYGHpODbc3pDlKw=; b=lk+6gkftqx+q4szLMXTzMaBnySJ3WUIKIMRWRGUh/87ZWPpb0lU/SFX099KCwAV+6W l7rHP1wp6EUUh3QX9fZ4f7zUyfZ4Tt3XfhnhTpc32V87m5EgOf3TlwDP52ePCNdS1v7K PhzrEazkqTtxONoINs0g1iK5VbnMdazhgHmJtEUJk1LDr8bqC2jr8uOubSnPUJeLSzKM r/BDTlHofLvTqehZLAhHQjyYTdqVmbiCklmjmKP9rFH0M0dewkCcGnNjqySnlvuepH0O p+OLFJIdBTzOzKcUzWMZJ6Cx/l6xfQOmuZBWJpSFLHklaNW8xYzEcjNC6FIELKc1QGN+ 5ClQ== X-Gm-Message-State: ACrzQf3wQR5eNlmiWYtMt0V5zQYHHqDLvniLQ0LWToHqwT/HaBySoA8G Nv7CUm+gDSoF0dYqD93az63jBmMTEcn8iFSy X-Google-Smtp-Source: AMsMyM7RVpukY7ga2UeuIFu4F2sO8VmUJSSjZkwzU4YOq0dY3hnUcSHvWXnP2gdHZYmJ4YQRHRHaYg== X-Received: by 2002:a05:6402:27cd:b0:45c:db6f:7e77 with SMTP id c13-20020a05640227cd00b0045cdb6f7e77mr11947976ede.149.1666035543684; Mon, 17 Oct 2022 12:39:03 -0700 (PDT) Received: from codespaces-99e6ae.mo2cupmyp0zuvhb2b0itoyabtg.ax.internal.cloudapp.net ([20.160.121.11]) by smtp.gmail.com with ESMTPSA id p11-20020a170906604b00b0078df3b4464fsm6699544ejj.19.2022.10.17.12.39.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 17 Oct 2022 12:39:03 -0700 (PDT) To: gdb-patches@sourceware.org Subject: [PATCH 2/2] Make GDB resolve dlopen of memory mapped shared libraries Date: Mon, 17 Oct 2022 19:38:58 +0000 Message-Id: <20221017193858.3006-3-asaffisher.dev@gmail.com> X-Mailer: git-send-email 2.38.0 In-Reply-To: <20221017193858.3006-1-asaffisher.dev@gmail.com> References: <20221017193858.3006-1-asaffisher.dev@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-9.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, 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: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Asaf Fisher via Gdb-patches From: Asaf Fisher Reply-To: Asaf Fisher Cc: Asaf Fisher Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" Introduced `check_proc_self_file` that checks if a path used by inferior in dlopen is in the form of `/proc/self/...` and if so resolves it to `/proc/[pid]/...` Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=29586 --- gdb/solib-svr4.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 7e83819a03d..231a4fb40e5 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -34,6 +34,7 @@ #include "regcache.h" #include "gdbthread.h" #include "observable.h" +#include "gdbsupport/pathstuff.h" #include "solist.h" #include "solib.h" @@ -46,6 +47,9 @@ #include "gdb_bfd.h" #include "probe.h" +#define SLASH_SELF "/self" +#define PROC_SELF "/proc" SLASH_SELF + static struct link_map_offsets *svr4_fetch_link_map_offsets (void); static int svr4_have_link_map_offsets (void); static void svr4_relocate_main_executable (void); @@ -1187,6 +1191,54 @@ svr4_default_sos (svr4_info *info) return newobj; } +/* Check and fix a cenerio where the so path that we extract has a path to + /proc/self e.g. /proc/self/fd/[fd_num] If inferior dlopen a path that has + /proc/self, GDB must not open it directly becuase the files in /proc/self are + unique for each process. Instead we resolve /proc/self to + /proc/[inferior_pid]. This change will give GDB the correct path */ + +static size_t check_proc_self_file(char *so_name, char *normalized_so_name, + size_t out_normalized_so_name_len) { + /* We dont want a path with /../ yak. */ + gdb::unique_xmalloc_ptr normalized_path_obj = gdb_realpath(so_name); + gdb::string_view normalized_path = gdb::string_view( + normalized_path_obj.get(), + std::min(strlen(normalized_path_obj.get()), out_normalized_so_name_len)); + + /* Is the path really a /proc/self? */ + if (0 != normalized_path.rfind(PROC_SELF, 0)) return 0; + + /* Lets get the part of the path after /proc/self e.g. /proc/self/fd -> /fd */ + size_t slash_self_index = normalized_path.rfind(SLASH_SELF); + if (std::string::npos == slash_self_index) return 0; + size_t after_self_index = slash_self_index + strlen(SLASH_SELF); + gdb::string_view after_self_path = normalized_path.substr(after_self_index); + + /* Get inferior path */ + int inferior_pid = inferior_ptid.pid(); + std::string inferior_procfs_path = string_printf("/proc/%d", inferior_pid); + + /* Check if there's enoght space in the out buffer for the normalized path. */ + size_t normalized_so_name_length = + inferior_procfs_path.length() + after_self_path.length(); + if (out_normalized_so_name_len < normalized_so_name_length) return 0; + + /* Build the full path */ + inferior_procfs_path.append(std::string(after_self_path)); + + warning(_("Detected loaded library (%s) from /proc/self.\nAttempting to " + "replace `self` with inferior's PID. -> %s"), + normalized_path.begin(), inferior_procfs_path.c_str()); + + auto out_length = + std::min(inferior_procfs_path.length(), out_normalized_so_name_len); + + /* Copy the new path to the out buffer */ + strncpy(normalized_so_name, inferior_procfs_path.c_str(), out_length); + + return out_length; +} + /* Read the whole inferior libraries chain starting at address LM. Expect the first entry in the chain's previous entry to be PREV_LM. Add the entries to the tail referenced by LINK_PTR_PTR. Ignore the @@ -1246,8 +1298,10 @@ svr4_read_so_list (svr4_info *info, CORE_ADDR lm, CORE_ADDR prev_lm, warning (_("Can't read pathname for load map.")); continue; } - - strncpy (newobj->so_name, buffer.get (), SO_NAME_MAX_PATH_SIZE - 1); + /* Check if path is in /proc/self */ + if (0 == check_proc_self_file(buffer.get(), newobj->so_name, + SO_NAME_MAX_PATH_SIZE - 1)) + strncpy(newobj->so_name, buffer.get(), SO_NAME_MAX_PATH_SIZE - 1); newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0'; strcpy (newobj->so_original_name, newobj->so_name);