From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id aoq/Lf4IimiAAgAAWB0awg (envelope-from ) for ; Wed, 30 Jul 2025 07:58:54 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=WSSRRFIS; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id AAF0B1E102; Wed, 30 Jul 2025 07:58:54 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-10.1 required=5.0 tests=ARC_SIGNED,ARC_VALID, BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED, RCVD_IN_VALIDITY_RPBL,RCVD_IN_VALIDITY_SAFE autolearn=ham autolearn_force=no version=4.0.1 Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id BA9F81E091 for ; Wed, 30 Jul 2025 07:58:53 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 829ED3858D26 for ; Wed, 30 Jul 2025 11:58:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 829ED3858D26 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=WSSRRFIS Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 699353858D1E for ; Wed, 30 Jul 2025 11:58:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 699353858D1E Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 699353858D1E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1753876697; cv=none; b=cCF0QB9pThJTN8xdEXw+IfuAXbHPccclBW5PDFc05E5IbyEdP1eTr8dWtrQONg9nnxLs9XA22Q1OlHssdXTrJopbS4MCIdLW7NgWKw/E5tUKQbeOlxu/EPHpIL87czZzMhQxfITevFxCdpJmr2Mztem4edMq3s46nAVAjKp4jOQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1753876697; c=relaxed/simple; bh=bRkXeQehL6Kuhqft88j2u10HOcwsc00LqrD7yJSyYIU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=cAD/8n187wWIHTFHzWE6LlafdM1op4ZUQj8XO81yhmUvzr/UlOKP2D75dy7fnmnKnW5ua2XqJPTRBPXpkwj8yX0BlAktvh6mUbzaxBXfgsQT0iC3hnv4x9V2ZNAXV7PHCpp6Ri4siNuWzEI+xIW1ikxCkPxIo88oh5xBd4UWy1U= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 699353858D1E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1753876697; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=mtep1N3Yo3Sozp9rQfgWlP+O/pccB16TLqeimTgSzgs=; b=WSSRRFISVb0+oUp1zEhAMgUOKz9xfLi9shI/xh2Uwaz3zEKhia34jI85MkU0QTgJuyF/29 oLnKC8ogQz5RC34vmKfpZ8nXvoCJg4zgHrNTebxQfhI+K3Br5V0k2yzAZ2aRwlnTn/gtVf evurr0yavIX3We8kpDKgZDzzWVm1lyo= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-691-3NAXXGOeM7eI05KHpMv1mQ-1; Wed, 30 Jul 2025 07:58:15 -0400 X-MC-Unique: 3NAXXGOeM7eI05KHpMv1mQ-1 X-Mimecast-MFC-AGG-ID: 3NAXXGOeM7eI05KHpMv1mQ_1753876694 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-3b7931d3d76so1019146f8f.1 for ; Wed, 30 Jul 2025 04:58:15 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753876694; x=1754481494; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=mtep1N3Yo3Sozp9rQfgWlP+O/pccB16TLqeimTgSzgs=; b=Ce5yGEdSZIFoK67WhdSnV3N3ylmwWl+UCev8MA8XlnbFojPoVjvx47KRK9EyYq5Hix CvD6SiHLL7s9zzqaN48Jy263UHGgnp/UEy77qgoK/K4eSWUcnJMaYc2vEDVQEaQp3vGC hJ2EliBKm9BIVktSq8Wylz0sgoYhAItpIWEQOt6Y9rYKidCOhSRFwq28D67tybcSHRr4 H2xWgk/asiYpl/Q1gfdchg/9d44lvzomCT5Z1pG0OKSCkhQIh2IScLuY9MdV6karlLHJ /IyeNpSZewBWjNjwds8BAihsqwtRvBvYlv4h3v/VlKr7wP/76nCr21k1eWobJ2xeIp9I I+vQ== X-Forwarded-Encrypted: i=1; AJvYcCVp3IcqGgPKWz0trQv9ATNzaLbYu7eT/06x09RqRtkhHMdqXUfI3BwHs4BygmGqZvFV+sEHQugn7D2qMw==@sourceware.org X-Gm-Message-State: AOJu0Yw/3reb9ja33PoTyBOWPvEBme4shj++uNk52qhbccjT2VxVhBTX TVfPA2IHxrE+xskGDHgopl+EBsEW2MEYT9C1DJaYRgcv6ZpD2OZ8CxZ0Uhg1srtJTaYOaJfVOV0 mQhyMCawGIz2jSwdaC3dfk49xOnXleE8bByAd9C6DChyWObYUF39hh2A5KYZT4KE= X-Gm-Gg: ASbGncsv8ciDw9jJ/vbCy/YevqmR+hgh7L3K6Upak0SmzgTFQB7vrs3kwaarS7NNdLi s91aRKSVl9PI15MKG/tJP+V4t1TXTeMcLX7r5qnXkpbMO8HKPvr/pWtvIX4T5w83T8cdfdpAWys nsBOGY86dUZuCmg7/Kk74xzKISRr+nRsyHIHLV1I9718Wd91aPcJwpFGKiA5/u8wjcW0+a2UeH0 49cI0Weak4xWwsvZs1WnZ+haCc8r5x9zwOKbg0p1TXlhHMmblSUZkhcH9OVwgXBGWraJfkVEIA7 RfIIMXr6FYARvyDs6qv/pUVj+Ty150mSKrsKYbhFtAbNiah0mcfBoOYG+3v2sw== X-Received: by 2002:a05:6000:4383:b0:3b5:f7a4:3306 with SMTP id ffacd0b85a97d-3b795008908mr2571064f8f.42.1753876694265; Wed, 30 Jul 2025 04:58:14 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHLm8Msf2j3EL68Dh9Sy1PuVC+x74UFnjGskv0Gl0wd7u3gg8Mlw6yFdgjke5j9f4ufgRp1Rw== X-Received: by 2002:a05:6000:4383:b0:3b5:f7a4:3306 with SMTP id ffacd0b85a97d-3b795008908mr2571033f8f.42.1753876693739; Wed, 30 Jul 2025 04:58:13 -0700 (PDT) Received: from localhost (120.81.93.209.dyn.plus.net. [209.93.81.120]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3b778f04744sm15082652f8f.54.2025.07.30.04.58.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Jul 2025 04:58:13 -0700 (PDT) From: Andrew Burgess To: Christina Schimpe , gdb-patches@sourceware.org Cc: thiago.bauermann@linaro.org, luis.machado@arm.com Subject: Re: [PATCH v5 10/12] gdb: Implement amd64 linux shadow stack support for inferior calls. In-Reply-To: <20250628082810.332526-11-christina.schimpe@intel.com> References: <20250628082810.332526-1-christina.schimpe@intel.com> <20250628082810.332526-11-christina.schimpe@intel.com> Date: Wed, 30 Jul 2025 12:58:12 +0100 Message-ID: <87freddh63.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: erB7j-R4xU6heWxWbZJnumAz1BufkJ-IZs1ZtTzBvmc_1753876694 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Christina Schimpe writes: > This patch enables inferior calls to support Intel's Control-Flow > Enforcement Technology (CET), which provides the shadow stack feature > for the x86 architecture. > Following the restriction of the linux kernel, enable inferior calls > for amd64 only. > > Reviewed-by: Thiago Jung Bauermann > Reviewed-By: Eli Zaretskii > Reviewed-By: Luis Machado > --- > gdb/amd64-linux-tdep.c | 63 +++++++++++++++++++ > gdb/doc/gdb.texinfo | 29 +++++++++ > .../gdb.arch/amd64-shadow-stack-cmds.exp | 55 +++++++++++++++- > 3 files changed, 146 insertions(+), 1 deletion(-) > > diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c > index f6ae5395870..899fe2df02c 100644 > --- a/gdb/amd64-linux-tdep.c > +++ b/gdb/amd64-linux-tdep.c > @@ -1932,6 +1932,67 @@ amd64_linux_shadow_stack_element_size_aligned (gdbarch *gdbarch) > return (binfo->bits_per_word / binfo->bits_per_byte); > } > > +/* Read the shadow stack pointer register and return its value, if > + possible. */ > + > +static std::optional > +amd64_linux_get_shadow_stack_pointer (gdbarch *gdbarch, regcache *regcache) > +{ > + const i386_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > + > + if (tdep == nullptr || tdep->ssp_regnum < 0) > + return {}; We don't check for 'tdep == nullptr' anywhere else (for x86), so I don't think this check is needed. If you _really_ want you could gdb_assert, but I'm pretty sure you'll have crashed long before now if tdep == nullptr. > + > + CORE_ADDR ssp; > + if (regcache_raw_read_unsigned (regcache, tdep->ssp_regnum, &ssp) > + != REG_VALID) > + return {}; > + > + /* Dependent on the target in case the shadow stack pointer is > + unavailable, the ssp register can be invalid or 0x0 when shadow stack > + is supported by HW and the linux kernel but not enabled for the > + current thread. */ Just so I understand, is the 0 coming from actual inferior state? Or is the 0 creeping in from somewhere in GDB when we should be creating an unavailable value, but get it wrong? Using 0 a magic address value is something I really dislike (having worked on targets where 0 is a valid address), so they always make me uncomfortable. If this is an actual h/w thing then there's nothing we could or should do about it ... but if this is a GDB thing, then maybe we can fix that? > + if (ssp == 0x0) > + return {}; > + > + return ssp; > +} > + > +/* If shadow stack is enabled, push the address NEW_ADDR to the shadow > + stack and increment the shadow stack pointer accordingly. */ > + > +static void > +amd64_linux_shadow_stack_push (gdbarch *gdbarch, CORE_ADDR new_addr, > + regcache *regcache) > +{ > + std::optional ssp > + = amd64_linux_get_shadow_stack_pointer (gdbarch, regcache); > + if (!ssp.has_value ()) > + return; > + > + /* The shadow stack grows downwards. To push addresses to the stack, > + we need to decrement SSP. */ > + const int element_size > + = amd64_linux_shadow_stack_element_size_aligned (gdbarch); > + const CORE_ADDR new_ssp = *ssp - element_size; > + > + /* Using /proc/PID/smaps we can only check if NEW_SSP points to shadow > + stack memory. If it doesn't, we assume the stack is full. */ > + std::pair memrange; > + if (!linux_address_in_shadow_stack_mem_range (new_ssp, &memrange)) > + error (_("No space left on the shadow stack.")); > + > + /* On x86 there can be a shadow stack token at bit 63. For x32, the I don't understand this first sentence and how it relates to either the rest of the comment, or the following code. > + address size is only 32 bit. Thus, we must use ELEMENT_SIZE (and > + not gdbarch_addr_bit) to determine the width of the address to be > + written. */ > + const bfd_endian byte_order = gdbarch_byte_order (gdbarch); > + write_memory_unsigned_integer (new_ssp, element_size, byte_order, > + (ULONGEST) new_addr); > + > + i386_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > + regcache_raw_write_unsigned (regcache, tdep->ssp_regnum, new_ssp); By this point we know that tdep->ssp_regnum must be a valid regnum. But the checks for that are in a separate function, so maybe we should: gdb_assert (tdep->ssp_regnum > -1); > +} > > /* Implement shadow stack pointer unwinding. For each new shadow stack > pointer check if its address is still in the shadow stack memory range. > @@ -2059,6 +2120,8 @@ amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch, > > set_gdbarch_remove_non_address_bits_watchpoint > (gdbarch, amd64_linux_remove_non_address_bits_watchpoint); > + > + set_gdbarch_shadow_stack_push (gdbarch, amd64_linux_shadow_stack_push); > dwarf2_frame_set_init_reg (gdbarch, amd64_init_reg); > } > > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 0881ac4aee5..b5120b78426 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -27037,6 +27037,35 @@ registers > > @end itemize > > +@subsubsection Intel Control-Flow Enforcement Technology. > +@cindex Intel Control-Flow Enforcement Technology. > + > +The @dfn{Intel Control-Flow Enforcement Technology} (@acronym{Intel CET}) > +provides two capabilities to defend against ``Return-oriented Programming'' > +and ``call/jmp-oriented programming'' style control-flow attacks: > + > +@itemize @bullet > +@item Shadow Stack: > +A shadow stack is a second stack for a program. It holds the return > +addresses pushed by the call instruction. The @code{RET} instruction pops the > +return addresses from both call and shadow stack. If the return addresses from > +the two stacks do not match, the processor signals a control protection > +exception. > +@item Indirect Branch Tracking (IBT): > +When IBT is enabled, the CPU implements a state machine that tracks indirect > +@code{JMP} and @code{CALL} instructions. The state machine can be either IDLE > +or WAIT_FOR_ENDBRANCH. In WAIT_FOR_ENDBRANCH state the next instruction in > +the program stream must be an @code{ENDBR} instruction, otherwise the > +processor signals a control protection exception. If I understand it, the IBT doesn't currently have an impact on GDB, right? The inferior function being called likely starts with an `endbr` instruction, but GDB will just leave the IBT mechanism in the IDLE state, and the endbr will be interpreted as a nop. I also found this description a little too light on the details. Just having the name was enough to go and find the real docs, but I think the text could be made cleared with two additional sentences: @item Indirect Branch Tracking (IBT): When IBT is enabled, the CPU implements a state machine that tracks indirect @code{JMP} and @code{CALL} instructions. The state machine can be either IDLE or WAIT_FOR_ENDBRANCH. When a @code{JMP} or @code{CALL} is executed the state machine chages to the WAIT_FOR_ENDBRANCH state. In WAIT_FOR_ENDBRANCH state the next instruction in the program stream must be an @code{ENDBR} instruction, otherwise the processor signals a control protection exception. After executing a @code{ENDBR} instruction the state machine returns to the IDLE state. This change isn't a hard requirement, but I do think this makes the description more useful. > +@end itemize > + > +Impact on Call/Print: > +Inferior calls in @value{GDBN} reset the current PC to the beginning of the > +function that is called. No call instruction is executed, but the @code{RET} > +instruction actually is. To avoid a control protection exception due to the > +missing return address on the shadow stack, @value{GDBN} pushes the new return > +address to the shadow stack and updates the shadow stack pointer. > + > @node Alpha > @subsection Alpha > > diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp > index 17f32ce3964..622612d2f7d 100644 > --- a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp > +++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp > @@ -13,12 +13,29 @@ > # You should have received a copy of the GNU General Public License > # along with this program. If not, see . > > -# Test shadow stack enabling for frame level update and the return command. > +# Test shadow stack enabling for frame level update, the return and the > +# call commands. > +# As potential CET violations often only occur after resuming normal > +# execution, test normal program continuation after each return or call > +# commands. > > require allow_ssp_tests > > standard_testfile amd64-shadow-stack.c > > +proc restart_and_run_infcall_call2 {} { There should be a comment before each proc please. Thanks, Andrew