From: Daniel King <dmk...@adacore.com> This unit performed integer to address conversions to calculate stack addresses which, on a CHERI target, result in an invalid capability that triggers a capability tag fault when dereferenced during stack filling. This patch updates the unit to preserve addresses (capabilities) during the calculations.
The method used to determine the stack base address is also updated to CHERI. The current method tries to get the stack base from the compiler info for the current task. If no info is found, then as a fallback it estimates the base by taking the address of a variable on the stack. This address is then derived to calculate the range of addresses to fill the stack. This fallback does not work on CHERI since taking the 'Address of a stack variable will result in a capability with bounds restricted to that object and attempting to write outside those bounds triggers a capability bounds fault. Instead, we add a new function Get_Stack_Base which, on CHERI, gets the exact stack base from the upper bound of the capability stack pointer (CSP) register. On non-CHERI platforms, Get_Stack_Base returns the stack base from the compiler info, resulting in the same behaviour as before on those platforms. gcc/ada/ChangeLog: * Makefile.rtl (LIBGNAT_TARGET_PAIRS): New unit s-tsgsba__cheri.adb for morello-freebsd. * libgnarl/s-tassta.adb (Get_Stack_Base): New function. * libgnarl/s-tsgsba__cheri.adb: New file for CHERI targets. * libgnarl/s-tsgsba.adb: New default file for non-CHERI targets. * libgnat/s-stausa.adb (Fill_Stack, Compute_Result): Port to CHERI. * libgnat/s-stausa.ads (Initialize_Analyzer, Stack_Analyzer): Port to CHERI. Tested on x86_64-pc-linux-gnu, committed on master. --- gcc/ada/Makefile.rtl | 1 + gcc/ada/libgnarl/s-tassta.adb | 18 ++++++++-- gcc/ada/libgnarl/s-tsgsba.adb | 40 +++++++++++++++++++++++ gcc/ada/libgnarl/s-tsgsba__cheri.adb | 49 ++++++++++++++++++++++++++++ gcc/ada/libgnat/s-stausa.adb | 41 ++++++++++++----------- gcc/ada/libgnat/s-stausa.ads | 8 ++--- 6 files changed, 130 insertions(+), 27 deletions(-) create mode 100644 gcc/ada/libgnarl/s-tsgsba.adb create mode 100644 gcc/ada/libgnarl/s-tsgsba__cheri.adb diff --git a/gcc/ada/Makefile.rtl b/gcc/ada/Makefile.rtl index 8f925fce9e0..50e683aa80a 100644 --- a/gcc/ada/Makefile.rtl +++ b/gcc/ada/Makefile.rtl @@ -1854,6 +1854,7 @@ ifeq ($(strip $(filter-out %aarch64 freebsd%,$(target_cpu) $(target_os))),) LIBGNAT_TARGET_PAIRS += \ s-intman.adb<libgnarl/s-intman__cheribsd.adb \ s-osinte.ads<libgnarl/s-osinte__cheribsd.ads \ + s-tsgsba.adb<libgnarl/s-tsgsba__cheri.adb \ s-secsta.adb<libgnat/s-secsta__cheri.adb EXTRA_GNATRTL_NONTASKING_OBJS += i-cheri.o i-cheri-exceptions.o diff --git a/gcc/ada/libgnarl/s-tassta.adb b/gcc/ada/libgnarl/s-tassta.adb index b1eb842ea60..98ee15b4baf 100644 --- a/gcc/ada/libgnarl/s-tassta.adb +++ b/gcc/ada/libgnarl/s-tassta.adb @@ -133,6 +133,11 @@ package body System.Tasking.Stages is -- Different code is used at master completion, in Terminate_Dependents, -- due to a need for tighter synchronization with the master. + function Get_Stack_Base (Self_ID : Task_Id) return System.Address; + -- Get the stack base of Self. + -- + -- If the stack base cannot be determined, then Null_Address is returned. + ---------------------- -- Abort_Dependents -- ---------------------- @@ -1113,7 +1118,7 @@ package body System.Tasking.Stages is -- Address of the base of the stack begin - Stack_Base := Self_ID.Common.Compiler_Data.Pri_Stack_Info.Base; + Stack_Base := Get_Stack_Base (Self_ID); if Stack_Base = Null_Address then @@ -1139,7 +1144,7 @@ package body System.Tasking.Stages is (Self_ID.Common.Analyzer, Self_ID.Common.Task_Image (1 .. Self_ID.Common.Task_Image_Len), Natural (Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size), - SSE.To_Integer (Stack_Base), + Stack_Base, Pattern_Size); STPO.Unlock_RTS; Fill_Stack (Self_ID.Common.Analyzer); @@ -1966,6 +1971,15 @@ package body System.Tasking.Stages is System.Task_Primitives.Operations.Finalize_TCB (T); end Vulnerable_Free_Task; + -------------------- + -- Get_Stack_Base -- + -------------------- + + -- Get_Stack_Base is architecture-specific + + function Get_Stack_Base (Self_ID : Task_Id) return System.Address + is separate; + -- Package elaboration code begin diff --git a/gcc/ada/libgnarl/s-tsgsba.adb b/gcc/ada/libgnarl/s-tsgsba.adb new file mode 100644 index 00000000000..450513db132 --- /dev/null +++ b/gcc/ada/libgnarl/s-tsgsba.adb @@ -0,0 +1,40 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS -- +-- -- +-- S Y S T E M . T A S K I N G . S T A G E S . G E T _ S T A C K _ B A S E -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 1992-2025, Free Software Foundation, Inc. -- +-- -- +-- GNARL is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- <http://www.gnu.org/licenses/>. -- +-- -- +-- GNARL was developed by the GNARL team at Florida State University. -- +-- Extensive contributions were provided by Ada Core Technologies, Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This is the default version for most platforms which tries to get the +-- stack base from the compiler info. It returns Null_Address if the stack +-- base is not available. + +separate (System.Tasking.Stages) +function Get_Stack_Base (Self_ID : Task_Id) return System.Address is +begin + return Self_ID.Common.Compiler_Data.Pri_Stack_Info.Base; +end Get_Stack_Base; diff --git a/gcc/ada/libgnarl/s-tsgsba__cheri.adb b/gcc/ada/libgnarl/s-tsgsba__cheri.adb new file mode 100644 index 00000000000..5c1783675b4 --- /dev/null +++ b/gcc/ada/libgnarl/s-tsgsba__cheri.adb @@ -0,0 +1,49 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS -- +-- -- +-- S Y S T E M . T A S K I N G . S T A G E S . G E T _ S T A C K _ B A S E -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 1992-2025, Free Software Foundation, Inc. -- +-- -- +-- GNARL is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- <http://www.gnu.org/licenses/>. -- +-- -- +-- GNARL was developed by the GNARL team at Florida State University. -- +-- Extensive contributions were provided by Ada Core Technologies, Inc. -- +-- -- +------------------------------------------------------------------------------ +with Interfaces.CHERI; + +-- This is the version for CHERI targets where we can derive the stack base +-- from the upper bound of the capability stack pointer (CSP). + +separate (System.Tasking.Stages) +function Get_Stack_Base (Self_ID : Task_Id) return System.Address is + pragma Unreferenced (Self_ID); + + use type SSE.Integer_Address; + + CSP : constant System.Address := Interfaces.CHERI.Get_CSP; +begin + return Interfaces.CHERI.Capability_With_Address + (Cap => CSP, + Addr => Interfaces.CHERI.Get_Base (CSP) + + SSE.Integer_Address + (Interfaces.CHERI.Get_Length (CSP))); +end Get_Stack_Base; diff --git a/gcc/ada/libgnat/s-stausa.adb b/gcc/ada/libgnat/s-stausa.adb index 6bdbc4342f1..cbecc0bb20e 100644 --- a/gcc/ada/libgnat/s-stausa.adb +++ b/gcc/ada/libgnat/s-stausa.adb @@ -188,7 +188,8 @@ package body System.Stack_Usage is -- allocated byte on the stack. begin if Parameters.Stack_Grows_Down then - if Analyzer.Stack_Base - Stack_Address (Analyzer.Pattern_Size) > + if To_Stack_Address (Analyzer.Stack_Base) - + Stack_Address (Analyzer.Pattern_Size) > To_Stack_Address (Current_Stack_Level'Address) - Guard then -- No room for a pattern @@ -198,22 +199,22 @@ package body System.Stack_Usage is end if; Analyzer.Pattern_Limit := - Analyzer.Stack_Base - Stack_Address (Analyzer.Pattern_Size); + Analyzer.Stack_Base - Storage_Offset (Analyzer.Pattern_Size); - if Analyzer.Stack_Base > + if To_Stack_Address (Analyzer.Stack_Base) > To_Stack_Address (Current_Stack_Level'Address) - Guard then -- Reduce pattern size to prevent local frame overwrite Analyzer.Pattern_Size := Integer (To_Stack_Address (Current_Stack_Level'Address) - Guard - - Analyzer.Pattern_Limit); + - To_Stack_Address (Analyzer.Pattern_Limit)); end if; - Analyzer.Pattern_Overlay_Address := - To_Address (Analyzer.Pattern_Limit); + Analyzer.Pattern_Overlay_Address := Analyzer.Pattern_Limit; else - if Analyzer.Stack_Base + Stack_Address (Analyzer.Pattern_Size) < + if To_Stack_Address (Analyzer.Stack_Base) + + Stack_Address (Analyzer.Pattern_Size) < To_Stack_Address (Current_Stack_Level'Address) + Guard then -- No room for a pattern @@ -223,22 +224,21 @@ package body System.Stack_Usage is end if; Analyzer.Pattern_Limit := - Analyzer.Stack_Base + Stack_Address (Analyzer.Pattern_Size); + Analyzer.Stack_Base + Storage_Offset (Analyzer.Pattern_Size); - if Analyzer.Stack_Base < + if To_Stack_Address (Analyzer.Stack_Base) < To_Stack_Address (Current_Stack_Level'Address) + Guard then -- Reduce pattern size to prevent local frame overwrite Analyzer.Pattern_Size := Integer - (Analyzer.Pattern_Limit - + (To_Stack_Address (Analyzer.Pattern_Limit) - (To_Stack_Address (Current_Stack_Level'Address) + Guard)); end if; Analyzer.Pattern_Overlay_Address := - To_Address (Analyzer.Pattern_Limit - - Stack_Address (Analyzer.Pattern_Size)); + Analyzer.Pattern_Limit - Storage_Offset (Analyzer.Pattern_Size); end if; -- Declare and fill the pattern buffer @@ -270,7 +270,7 @@ package body System.Stack_Usage is (Analyzer : in out Stack_Analyzer; Task_Name : String; Stack_Size : Natural; - Stack_Base : Stack_Address; + Stack_Base : System.Address; Pattern_Size : Natural; Pattern : Interfaces.Unsigned_32 := 16#DEAD_BEEF#) is @@ -332,10 +332,10 @@ package body System.Stack_Usage is if Parameters.Stack_Grows_Down then Analyzer.Topmost_Touched_Mark := - Analyzer.Pattern_Limit + Stack_Address (Analyzer.Pattern_Size); + Analyzer.Pattern_Limit + Storage_Offset (Analyzer.Pattern_Size); else Analyzer.Topmost_Touched_Mark := - Analyzer.Pattern_Limit - Stack_Address (Analyzer.Pattern_Size); + Analyzer.Pattern_Limit - Storage_Offset (Analyzer.Pattern_Size); end if; if Analyzer.Pattern_Size = 0 then @@ -349,8 +349,7 @@ package body System.Stack_Usage is if System.Parameters.Stack_Grows_Down then for J in Stack'Range loop if Stack (J) /= Analyzer.Pattern then - Analyzer.Topmost_Touched_Mark := - To_Stack_Address (Stack (J)'Address); + Analyzer.Topmost_Touched_Mark := Stack (J)'Address; exit; end if; end loop; @@ -358,8 +357,7 @@ package body System.Stack_Usage is else for J in reverse Stack'Range loop if Stack (J) /= Analyzer.Pattern then - Analyzer.Topmost_Touched_Mark := - To_Stack_Address (Stack (J)'Address); + Analyzer.Topmost_Touched_Mark := Stack (J)'Address; exit; end if; end loop; @@ -514,8 +512,9 @@ package body System.Stack_Usage is Result.Value := Analyzer.Stack_Size; else - Result.Value := Stack_Size (Analyzer.Topmost_Touched_Mark, - Analyzer.Stack_Base); + Result.Value := + Stack_Size (To_Stack_Address (Analyzer.Topmost_Touched_Mark), + To_Stack_Address (Analyzer.Stack_Base)); end if; if Analyzer.Result_Id in Result_Array'Range then diff --git a/gcc/ada/libgnat/s-stausa.ads b/gcc/ada/libgnat/s-stausa.ads index c67b1240ac4..36cebd7cde0 100644 --- a/gcc/ada/libgnat/s-stausa.ads +++ b/gcc/ada/libgnat/s-stausa.ads @@ -230,7 +230,7 @@ package System.Stack_Usage is (Analyzer : in out Stack_Analyzer; Task_Name : String; Stack_Size : Natural; - Stack_Base : Stack_Address; + Stack_Base : System.Address; Pattern_Size : Natural; Pattern : Interfaces.Unsigned_32 := 16#DEAD_BEEF#); -- Should be called before any use of a Stack_Analyzer, to initialize it. @@ -287,7 +287,7 @@ private Task_Name : String (1 .. Task_Name_Length); -- Name of the task - Stack_Base : Stack_Address; + Stack_Base : System.Address; -- Address of the base of the stack, as given by the caller of -- Initialize_Analyzer. @@ -300,10 +300,10 @@ private Pattern : Pattern_Type; -- Pattern used to recognize untouched memory - Pattern_Limit : Stack_Address; + Pattern_Limit : System.Address; -- Bound of the pattern area farthest to the base - Topmost_Touched_Mark : Stack_Address; + Topmost_Touched_Mark : System.Address; -- Topmost address of the pattern area whose value it is pointing -- at has been modified during execution. If the systematic error are -- compensated, it is the topmost value of the stack pointer during -- 2.43.0