From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id sSBGLsviWWi5VxsAWB0awg (envelope-from ) for ; Mon, 23 Jun 2025 19:27:07 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=mv8MSXfY; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id AE0C81E11C; Mon, 23 Jun 2025 19:27:07 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.8 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_SBL_CSS,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 7D1621E0C2 for ; Mon, 23 Jun 2025 19:27:06 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DE5973845BFB for ; Mon, 23 Jun 2025 23:27:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DE5973845BFB Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=mv8MSXfY Received: from mail-pl1-x62f.google.com (mail-pl1-x62f.google.com [IPv6:2607:f8b0:4864:20::62f]) by sourceware.org (Postfix) with ESMTPS id 3DD06385EC17 for ; Mon, 23 Jun 2025 23:26:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3DD06385EC17 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 3DD06385EC17 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::62f ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750721191; cv=none; b=WQvT9aCk8vgnyJdMIfYH4/y69Si4lDE/cBd9PC1VEhhoYiX+QX80e2uIhEXnZrqmL2DxX2l8y2nhCOhNajBgjpnjBW70GgqD80X3sDVV89yjVBUzlseP3J9rdO4TN7QrjsyNs44zG7NeyuAZK0biTyXn/bk4b86QwK4bmnHngN4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750721191; c=relaxed/simple; bh=4DXNI49Hrr62Mih6m3oECUEKOeJNYYJrQ1HBMqrjozI=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=eLY/7WJ3GDDivQA2PaZy8Vr5ydt8cUGNBAKe+WVr8pQUBx5DrhZWvmJjtfW8qlSWSc0MQwGNLd9/BFwSpqB+/5q+Zlgn0G+8FSB8vjiE+IsSOj16N5+YetpKLABWo9pdEzTMZaLAelOjW0i6mTHxs3XzuUs1rklLWoIRjz+46H4= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3DD06385EC17 Received: by mail-pl1-x62f.google.com with SMTP id d9443c01a7336-2349f096605so71656615ad.3 for ; Mon, 23 Jun 2025 16:26:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1750721190; x=1751325990; darn=sourceware.org; h=content-transfer-encoding:mime-version:message-id:date:user-agent :references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=FQiy0Tl9xDflym0yo85qkJl7KRT3wMDKiEkNnzmeN5Q=; b=mv8MSXfYA/INedbc2gq2OblZQX0tXdrtNK6cvVSk6MQfvXs23LqNjo5dwFPC2rDRJI oe1j6rxNlDMMju8/rYZzArUI7Tn1QpKM/OCHfM5GqESyRgbVzx/0G/yQz61IKskvGMi3 Hgt7KpUfJjZnf5iwJnrVSOMBm1lHJnS56Bj6rAx+r/DYYNZ/Fkw/XFvq9Vis98ZL+vf4 BqBYYA6zZ9dlLqatib66Sht49u5xBLTXcQTlSTqDnPYAUpCKYfNc76irAOwG7FXDtmZc XkP7h7gPOsFWvPgib+lLifRpqh1+shKolE4JyCpAS0ADyEJrvLGlmm+43ezcRKocDW0U AE7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750721190; x=1751325990; h=content-transfer-encoding:mime-version:message-id:date:user-agent :references:in-reply-to:subject:cc:to:from:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=FQiy0Tl9xDflym0yo85qkJl7KRT3wMDKiEkNnzmeN5Q=; b=bb0/VIVwbRnYBvjUuCDECBgcaKffIRYuUB1DseSrKsrduRjlTvwIBPxf1zhHS69WMI XXCAIqm9tH784otbIFjyAQkNbWSRC3ycqqvRRVteAmgDmHx27xI/k2UUdwTsbYU+mcmL WUR8DJeHl+P0wZjNRrhCQ0yojnF/q9W6jMLwXqRrSZWHZfIiWarI926271PbLyM6w8iw YSJl86md/Kp5HcCUKpYMw7zHChyuTNhuw/F1t3vd5nPuh/lPgBHRW424i13LGWf9t/o3 UQclNf2mFdcuSdubmhju5XYzsJEp+LvlGTjuOoU5LRaD2tXOtAvt7nXj75VNISduIYWK hqyQ== X-Forwarded-Encrypted: i=1; AJvYcCVOsbTQVdkyTNisiz6fc1JZ63M32T2WZo51CDVUIXqU6Y2hcanypZyWxoczw4CdfGZ2w4tVMlp8CYt/0w==@sourceware.org X-Gm-Message-State: AOJu0YwzFGUZfA9Q5e/uwywwrlwaI+cxbgr3th8PLNuqN9pTRdw6/6Yk 8Tcg+3PmDHjivM5iSd8K0aJDjNFsEyDivXtG3/7IBn2ovGlUU+0mvtKjANRi8bjdqdY= X-Gm-Gg: ASbGncskbpKGZouZ23V4+TdTmwoIvfgfhJBVVvSta9l1rfy98XDD25KzPVPqHcsenGH vmVLqX9diFaPAE0hp+sm82PJDjJNx2Y9WSfUVJbwPozgdkcOpSXRslwH9oz8G3m1Nej49mSycWf VYq7e4/HaO08hnT4oiAQlomzYcuwfhUrDhlniy1qU6gioXyyox5aq8r+IJH481jVZFNLhWvlO01 cDF0JGQFijCkKPResjqxQHrb4iU7X2wEd+/OCXp6B+QIxeiTHp3jbc8JPRUhRO6QPNkYE/LGiTz Fo1dCVwy4uke27Q9xLKce3GkkmE51p71bsd2hS7uVSCj3eL87erI47uRyspPPuczffyHN0E= X-Google-Smtp-Source: AGHT+IHuP0wcgCt+8YRUftUIpiystJwFCgE06Ekz7VMft9KsxLiH8jhSsw0DzhUsK2X2xf+YTkGEKQ== X-Received: by 2002:a17:902:e5c9:b0:234:bca7:2921 with SMTP id d9443c01a7336-237d991f9cbmr243829225ad.33.1750721190070; Mon, 23 Jun 2025 16:26:30 -0700 (PDT) Received: from localhost ([2804:14d:7e39:88d6:5227:c206:be23:3ef]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-237d8393043sm95871735ad.3.2025.06.23.16.26.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Jun 2025 16:26:29 -0700 (PDT) From: Thiago Jung Bauermann To: "Schimpe, Christina" Cc: Luis Machado , "gdb-patches@sourceware.org" , "eliz@gnu.org" Subject: Re: [PATCH v4 07/11] gdb: Handle shadow stack pointer register unwinding for amd64 linux. In-Reply-To: (Christina Schimpe's message of "Mon, 23 Jun 2025 14:55:13 +0000") References: <20250617121147.1956686-1-christina.schimpe@intel.com> <20250617121147.1956686-8-christina.schimpe@intel.com> <871prfp4rk.fsf@linaro.org> User-Agent: mu4e 1.12.11; emacs 30.1 Date: Mon, 23 Jun 2025 20:26:26 -0300 Message-ID: <877c12vy3h.fsf@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable 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 Hello Christina, "Schimpe, Christina" writes: >> -----Original Message----- >> From: Thiago Jung Bauermann >> Sent: Friday, June 20, 2025 3:43 AM >> To: Luis Machado >> Cc: Schimpe, Christina ; gdb- >> patches@sourceware.org; eliz@gnu.org >> Subject: Re: [PATCH v4 07/11] gdb: Handle shadow stack pointer register >> unwinding for amd64 linux. >>=20 >> Luis Machado writes: >>=20 >> > On 6/17/25 13:11, Christina Schimpe wrote: >> >> + Using /proc/PID/smaps we can only check if the current shadow >> >> + stack pointer SSP points to shadow stack memory. Only if this is >> >> + the case a valid previous shadow stack pointer can be >> >> + calculated. */ >> >> + std::pair range; >> >> + if (linux_address_in_shadow_stack_mem_range (ssp, &range)) >> >> + { >> >> + /* The shadow stack grows downwards. To compute the previous >> >> + shadow stack pointer, we need to increment SSP. */ >> >> + CORE_ADDR new_ssp >> >> + =3D ssp + amd64_linux_shadow_stack_element_size_aligned >> >> +(gdbarch); >> >> + >> >> + /* If NEW_SSP points to the end of or before (<=3D) the current >> >> + shadow stack memory range we consider NEW_SSP as valid (but >> >> + empty). */ >> > >> > I couldn't quite understand the difference between the empty case and >> > the unavailable case. But maybe I just don't fully understand the feat= ure. >> > >> > Would it be possible to make the comment a bit more clear? >>=20 >> I understood it to mean that if new_ssp =3D=3D range.second, then it poi= nts to >> the top of the stack and there aren't any elements. >>=20 >> Whereas if new_ssp points outside of the shadow stack area, then it's >> garbage and we failed to unwind it, hence the unavailable value. >>=20 >> Christina, please correct me if I'm wrong. >>=20 >> But now looking at this again, I think there's an off-by-one error: >> range.second is the first address outside of the memory range, so the >> comparison needs to be strictly less than. And the shadow stack will be >> empty if new_ssp =3D=3D range.second - 1 (there's no need to check for t= hat, >> though). >>=20 >> >> + if (new_ssp <=3D range.second) >> >> + return frame_unwind_got_address (this_frame, regnum, new_ssp); >> >> + } >> >> + } >> >> + >> >> + /* Return a value which is marked as unavailable in case we could = not >> >> + calculate a valid previous shadow stack pointer. */ >> >> + value *retval >> >> + =3D value::allocate_register (get_next_frame_sentinel_okay (this= _frame), >> >> + regnum, register_type (gdbarch, regnum)); >> >> + retval->mark_bytes_unavailable (0, retval->type ()->length ()); >> >> + return retval; >> >> +} > > Hi Thiago,=20 > >> Whereas if new_ssp points outside of the shadow stack area, then it's >> garbage and we failed to unwind it, hence the unavailable value. > > Yes, this is how it should be. =F0=9F=98=8A > > But I think the current implementation should be correct. > I wrote a small testprogram, which enables shadow stack manually using AR= CH_PRCTL in enable_ssp: > > ~~~ > > int call () > { > return 0; > } > > int enable_ssp () > { > int ret; > if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) { > printf("[FAIL]\tEnabling shadow stack failed\n"); > return 1; > } > > ret =3D call (); // stop in enable_ssp > > if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) { > ret =3D 1; > printf("[FAIL]\tDisabling shadow stack failed\n"); > } > return ret; > } > > int main () > { > return enable_ssp (); > } > > ~~~ > > If we stop in enable_ssp, ("ret =3D call ()"), we have the scenario that = shadow stack is enabled, > but no call instruction has been executed yet. > So we'll have an empty shadow stack, but SSP is valid and pointing to the= end address > (=3D=3Drange.second) of the shadow stack address space: Thanks for the program. I see that Intel and AArch64 behave differently in this respect. I believe that this is because on AArch64, a new stack contains an initial value of 0 at the top. From the Linux kernel documentation=C2=B9: When a stack is allocated by enabling GCS or during thread creation then the top 8 bytes of the stack will be initialised to 0 and GCSPR_EL0 will be set to point to the address of this 0 value, this can be used to detect the top of the stack. > ~~~ > (gdb) r > Starting program: /tmp/main=20 > [Thread debugging using libthread_db enabled] > Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". > > Breakpoint 1, enable_ssp () at main.c:52 > 52 ret =3D call (); // stop in enable_ssp > (gdb) p $pl3_ssp > $1 =3D (void *) 0x7ffff7c00000 > (gdb) info proc mappings > process 94192 > Mapped address spaces: > > Start Addr End Addr Size Offset = Perms File=20 > [...] > 0x0000555555558000 0x0000555555559000 0x1000 0x3000 = rw-p /tmp/main=20 > 0x00007ffff7400000 0x00007ffff7c00000 0x800000 0x0 = rw-p=20=20=20 > [...] On AArch64 the GCSPR is within the GCS memory range: (gdb) r Starting program: /home/bauermann/tmp/test-gcs [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1". Breakpoint 1, enable_gcspr () at test-gcs.c:63 =E2=9A=A0 warning: Source file is more recent than executable. 63 ret =3D call (); // stop in enable_ssp (gdb) p $gcspr $1 =3D (void *) 0xfffff7bffff8 (gdb) info proc mappings process 3228 Mapped address spaces: Start Addr End Addr Size Offset = Perms File =E2=8B=AE 0x0000fffff7800000 0x0000fffff7c00000 0x400000 0x0 = rw-p > ~~~ > > Checking the unwinding we see that one frame above SSP becomes unavailabl= e: > ~~~ > (gdb) up > #1 0x00005555555551d4 in main () at main.c:63 > 63 return enable_ssp (); > (gdb) p $pl3_ssp > $3 =3D > (gdb) down > #0 enable_ssp () at main.c:52 > 52 ret =3D call (); // stop in enable_ssp > (gdb) p $pl3_ssp > $4 =3D (void *) 0x7ffff7c00000 What I get on AArch64. The last command shows the zeroed entry at the top of the stack. (gdb) up #1 0x0000aaaaaaaa0900 in main () at test-gcs.c:77 77 return enable_gcspr (); (gdb) p $gcspr $2 =3D (gdb) down #0 enable_gcspr () at test-gcs.c:63 63 ret =3D call (); // stop in enable_ssp (gdb) p $gcspr $3 =3D (void *) 0xfffff7bffff8 (gdb) x/xg $gcspr 0xfffff7bffff8: 0x0000000000000000 > ~~~ > > Or unwinding from call: > ~~~ > Breakpoint 1, call () at main.c:41 > 41 return 0; > (gdb) p $pl3_ssp > $1 =3D (void *) 0x7ffff7bffff8 > (gdb) up > #1 0x000055555555518a in enable_ssp () at main.c:52 > 52 ret =3D call (); // stop in enable_ssp > (gdb) p $pl3_ssp > $2 =3D (void *) 0x7ffff7c00000 > (gdb) up > #2 0x00005555555551d4 in main () at main.c:63 > 63 return enable_ssp (); > (gdb) p $pl3_ssp > $3 =3D > (gdb) down > #1 0x000055555555518a in enable_ssp () at main.c:52 > 52 ret =3D call (); // stop in enable_ssp > (gdb) p $pl3_ssp > $4 =3D (void *) 0x7ffff7c00000 > (gdb) down=20 > #0 call () at main.c:41 > 41 return 0; > (gdb) p $pl3_ssp > $5 =3D (void *) 0x7ffff7bffff8 In this example the GCSPR is also always within the GCS range. And you can see the zeroed entry at the top as well: Breakpoint 2, call () at test-gcs.c:50 50 return 0; (gdb) p $gcspr $4 =3D (void *) 0xfffff7bffff0 (gdb) x/xg $gcspr 0xfffff7bffff0: 0x0000aaaaaaaa08a4 (gdb) x/2xg $gcspr 0xfffff7bffff0: 0x0000aaaaaaaa08a4 0x0000000000000000 (gdb) up #1 0x0000aaaaaaaa08a4 in enable_gcspr () at test-gcs.c:63 63 ret =3D call (); // stop in enable_ssp (gdb) p $gcspr $5 =3D (void *) 0xfffff7bffff8 (gdb) x/xg $gcspr 0xfffff7bffff8: 0x0000000000000000 (gdb) up #2 0x0000aaaaaaaa0900 in main () at test-gcs.c:77 77 return enable_gcspr (); (gdb) p $gcspr $6 =3D (gdb) down #1 0x0000aaaaaaaa08a4 in enable_gcspr () at test-gcs.c:63 63 ret =3D call (); // stop in enable_ssp (gdb) p $gcspr $7 =3D (void *) 0xfffff7bffff8 (gdb) down #0 call () at test-gcs.c:50 50 return 0; (gdb) p $gcspr $8 =3D (void *) 0xfffff7bffff0 > ~~~ > > So the check > > "if (new_ssp <=3D range.second)" > > seems correct to me. This is a subtle difference between our systems. Thanks for the example and the explanation. It was very helpful. --=20 Thiago =C2=B9 https://www.kernel.org/doc/html/latest/arch/arm64/gcs.html#allocatio= n-of-guarded-control-stacks