From f6bd6587a3b2b42a72ed337cf77a4e16ef72fc0f Mon Sep 17 00:00:00 2001 From: xiongzhou4 Date: Tue, 10 Oct 2023 19:52:56 +0800 Subject: [PATCH] Backport patches to fix CVE-2023-4039. Upstream: https://gcc.gnu.org/git/?p=gcc.git;a=shortlog;h=refs/vendors/ARM/heads/CVE-2023-4039/gcc-7 --- Backport-check-function-bodies-support.patch | 211 +++++++++++++ ...dd-bytes_below_hard_fp-to-frame-info.patch | 166 +++++++++++ ...andle-frames-with-no-saved-registers.patch | 40 +++ ...smash-canary-protect-saved-registers.patch | 281 ++++++++++++++++++ ...ard_fp_offset-to-bytes_above_hard_fp.patch | 141 +++++++++ ...-locals_offset-to-bytes_above_locals.patch | 104 +++++++ aarch64-Tweak-frame_size-comment.patch | 37 +++ gcc.spec | 19 +- 8 files changed, 998 insertions(+), 1 deletion(-) create mode 100644 Backport-check-function-bodies-support.patch create mode 100644 aarch64-Add-bytes_below_hard_fp-to-frame-info.patch create mode 100644 aarch64-Explicitly-handle-frames-with-no-saved-registers.patch create mode 100644 aarch64-Make-stack-smash-canary-protect-saved-registers.patch create mode 100644 aarch64-Rename-hard_fp_offset-to-bytes_above_hard_fp.patch create mode 100644 aarch64-Rename-locals_offset-to-bytes_above_locals.patch create mode 100644 aarch64-Tweak-frame_size-comment.patch diff --git a/Backport-check-function-bodies-support.patch b/Backport-check-function-bodies-support.patch new file mode 100644 index 0000000..1e00a1a --- /dev/null +++ b/Backport-check-function-bodies-support.patch @@ -0,0 +1,211 @@ +From 69c18301a2dea6dd686d4351ba3c095490707d16 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford +Date: Tue, 15 Aug 2023 19:05:30 +0100 +Subject: [PATCH] Backport check-function-bodies support + +--- + gcc/testsuite/lib/scanasm.exp | 191 ++++++++++++++++++++++++++++++++++ + 1 file changed, 191 insertions(+) + +diff --git a/gcc/testsuite/lib/scanasm.exp b/gcc/testsuite/lib/scanasm.exp +index bab23e8e165..1103f86c602 100644 +--- a/gcc/testsuite/lib/scanasm.exp ++++ b/gcc/testsuite/lib/scanasm.exp +@@ -514,3 +514,194 @@ proc scan-lto-assembler { args } { + verbose "output_file: $output_file" + dg-scan "scan-assembler" 1 $testcase $output_file $args + } ++ ++# Read assembly file FILENAME and store a mapping from function names ++# to function bodies in array RESULT. FILENAME has already been uploaded ++# locally where necessary and is known to exist. ++ ++proc parse_function_bodies { filename result } { ++ upvar $result up_result ++ ++ # Regexp for the start of a function definition (name in \1). ++ set label {^([a-zA-Z_]\S+):$} ++ ++ # Regexp for the end of a function definition. ++ set terminator {^\s*\.size} ++ ++ # Regexp for lines that aren't interesting. ++ set fluff {^\s*(?:\.|//|@|$)} ++ ++ set fd [open $filename r] ++ set in_function 0 ++ while { [gets $fd line] >= 0 } { ++ if { [regexp $label $line dummy function_name] } { ++ set in_function 1 ++ set function_body "" ++ } elseif { $in_function } { ++ if { [regexp $terminator $line] } { ++ set up_result($function_name) $function_body ++ set in_function 0 ++ } elseif { ![regexp $fluff $line] } { ++ append function_body $line "\n" ++ } ++ } ++ } ++ close $fd ++} ++ ++# FUNCTIONS is an array that maps function names to function bodies. ++# Return true if it contains a definition of function NAME and if ++# that definition matches BODY_REGEXP. ++ ++proc check_function_body { functions name body_regexp } { ++ upvar $functions up_functions ++ ++ if { ![info exists up_functions($name)] } { ++ return 0 ++ } ++ set fn_res [regexp "^$body_regexp\$" $up_functions($name)] ++ if { !$fn_res } { ++ verbose -log "body: $body_regexp" ++ verbose -log "against: $up_functions($name)" ++ } ++ return $fn_res ++} ++ ++# Check the implementations of functions against expected output. Used as: ++# ++# { dg-do { check-function-bodies PREFIX TERMINATOR[ OPTION[ SELECTOR]] } } ++# ++# See sourcebuild.texi for details. ++ ++proc check-function-bodies { args } { ++ if { [llength $args] < 2 } { ++ error "too few arguments to check-function-bodies" ++ } ++ if { [llength $args] > 4 } { ++ error "too many arguments to check-function-bodies" ++ } ++ ++ if { [llength $args] >= 3 } { ++ set required_flags [lindex $args 2] ++ ++ upvar 2 dg-extra-tool-flags extra_tool_flags ++ set flags $extra_tool_flags ++ ++ global torture_current_flags ++ if { [info exists torture_current_flags] } { ++ append flags " " $torture_current_flags ++ } ++ foreach required_flag $required_flags { ++ switch -- $required_flag { ++ target - ++ xfail { ++ error "misplaced $required_flag in check-function-bodies" ++ } ++ } ++ } ++ foreach required_flag $required_flags { ++ if { ![regexp " $required_flag " $flags] } { ++ return ++ } ++ } ++ } ++ ++ set xfail_all 0 ++ if { [llength $args] >= 4 } { ++ switch [dg-process-target [lindex $args 3]] { ++ "S" { } ++ "N" { return } ++ "F" { set xfail_all 1 } ++ "P" { } ++ } ++ } ++ ++ set testcase [testname-for-summary] ++ # The name might include a list of options; extract the file name. ++ set filename [lindex $testcase 0] ++ ++ global srcdir ++ set input_filename "$srcdir/$filename" ++ set output_filename "[file rootname [file tail $filename]].s" ++ ++ set prefix [lindex $args 0] ++ set prefix_len [string length $prefix] ++ set terminator [lindex $args 1] ++ if { [string equal $terminator ""] } { ++ set terminator "*/" ++ } ++ set terminator_len [string length $terminator] ++ ++ set have_bodies 0 ++ if { [is_remote host] } { ++ remote_upload host "$filename" ++ } ++ if { [file exists $output_filename] } { ++ parse_function_bodies $output_filename functions ++ set have_bodies 1 ++ } else { ++ verbose -log "$testcase: output file does not exist" ++ } ++ ++ set count 0 ++ set function_regexp "" ++ set label {^(\S+):$} ++ ++ set lineno 1 ++ set fd [open $input_filename r] ++ set in_function 0 ++ while { [gets $fd line] >= 0 } { ++ if { [string equal -length $prefix_len $line $prefix] } { ++ set line [string trim [string range $line $prefix_len end]] ++ if { !$in_function } { ++ if { [regexp "^(.*?\\S)\\s+{(.*)}\$" $line dummy \ ++ line selector] } { ++ set selector [dg-process-target $selector] ++ } else { ++ set selector "P" ++ } ++ if { ![regexp $label $line dummy function_name] } { ++ close $fd ++ error "check-function-bodies: line $lineno does not have a function label" ++ } ++ set in_function 1 ++ set function_regexp "" ++ } elseif { [string equal $line "("] } { ++ append function_regexp "(?:" ++ } elseif { [string equal $line "|"] } { ++ append function_regexp "|" ++ } elseif { [string equal $line ")"] } { ++ append function_regexp ")" ++ } elseif { [string equal $line "..."] } { ++ append function_regexp ".*" ++ } else { ++ append function_regexp "\t" $line "\n" ++ } ++ } elseif { [string equal -length $terminator_len $line $terminator] } { ++ if { ![string equal $selector "N"] } { ++ if { $xfail_all || [string equal $selector "F"] } { ++ setup_xfail "*-*-*" ++ } ++ set testname "$testcase check-function-bodies $function_name" ++ if { !$have_bodies } { ++ unresolved $testname ++ } elseif { [check_function_body functions $function_name \ ++ $function_regexp] } { ++ pass $testname ++ } else { ++ fail $testname ++ } ++ } ++ set in_function 0 ++ incr count ++ } ++ incr lineno ++ } ++ close $fd ++ if { $in_function } { ++ error "check-function-bodies: missing \"$terminator\"" ++ } ++ if { $count == 0 } { ++ error "check-function-bodies: no matches found" ++ } ++} +-- +2.39.3 + diff --git a/aarch64-Add-bytes_below_hard_fp-to-frame-info.patch b/aarch64-Add-bytes_below_hard_fp-to-frame-info.patch new file mode 100644 index 0000000..fb02e7e --- /dev/null +++ b/aarch64-Add-bytes_below_hard_fp-to-frame-info.patch @@ -0,0 +1,166 @@ +From e97c93de7ceadad75774f897424a50ece3215129 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford +Date: Fri, 16 Jun 2023 16:55:12 +0100 +Subject: [PATCH] aarch64: Add bytes_below_hard_fp to frame info + +The frame layout code currently hard-codes the assumption that +the number of bytes below the saved registers is equal to the +size of the outgoing arguments. This patch abstracts that +value into a new field of aarch64_frame. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::bytes_below_hard_fp): New + field. + * config/aarch64/aarch64.c (aarch64_layout_frame): Initialize it, + and use it instead of crtl->outgoing_args_size. + (aarch64_get_separate_components): Use bytes_below_hard_fp instead + of outgoing_args_size. + (aarch64_process_components): Likewise. +--- + gcc/config/aarch64/aarch64.c | 40 +++++++++++++++++++++--------------- + gcc/config/aarch64/aarch64.h | 6 +++++- + 2 files changed, 28 insertions(+), 18 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index bb4f6020e5d..12df8bb783c 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -2826,6 +2826,8 @@ aarch64_layout_frame (void) + last_fp_reg = regno; + } + ++ cfun->machine->frame.bytes_below_hard_fp = crtl->outgoing_args_size; ++ + if (frame_pointer_needed) + { + /* FP and LR are placed in the linkage record. */ +@@ -2885,7 +2887,7 @@ aarch64_layout_frame (void) + + cfun->machine->frame.frame_size + = ROUND_UP (cfun->machine->frame.hard_fp_offset +- + crtl->outgoing_args_size, ++ + cfun->machine->frame.bytes_below_hard_fp, + STACK_BOUNDARY / BITS_PER_UNIT); + + cfun->machine->frame.locals_offset = cfun->machine->frame.saved_varargs_size; +@@ -2904,32 +2906,33 @@ aarch64_layout_frame (void) + if (cfun->machine->frame.saved_regs_size == 0) + cfun->machine->frame.initial_adjust = cfun->machine->frame.frame_size; + else if (cfun->machine->frame.frame_size < max_push_offset +- && crtl->outgoing_args_size == 0) ++ && cfun->machine->frame.bytes_below_hard_fp == 0) + { +- /* Simple, small frame with no outgoing arguments: ++ /* Simple, small frame with no data below the saved registers. + stp reg1, reg2, [sp, -frame_size]! + stp reg3, reg4, [sp, 16] */ + cfun->machine->frame.callee_adjust = cfun->machine->frame.frame_size; + } +- else if ((crtl->outgoing_args_size ++ else if ((cfun->machine->frame.bytes_below_hard_fp + + cfun->machine->frame.saved_regs_size < 512) + && !(cfun->calls_alloca + && cfun->machine->frame.hard_fp_offset < max_push_offset)) + { +- /* Frame with small outgoing arguments: ++ /* Frame with small area below the saved registers: + sub sp, sp, frame_size +- stp reg1, reg2, [sp, outgoing_args_size] +- stp reg3, reg4, [sp, outgoing_args_size + 16] */ ++ stp reg1, reg2, [sp, bytes_below_hard_fp] ++ stp reg3, reg4, [sp, bytes_below_hard_fp + 16] */ + cfun->machine->frame.initial_adjust = cfun->machine->frame.frame_size; + cfun->machine->frame.callee_offset + = cfun->machine->frame.frame_size - cfun->machine->frame.hard_fp_offset; + } + else if (cfun->machine->frame.hard_fp_offset < max_push_offset) + { +- /* Frame with large outgoing arguments but a small local area: ++ /* Frame with large area below the saved registers, but with a ++ small area above: + stp reg1, reg2, [sp, -hard_fp_offset]! + stp reg3, reg4, [sp, 16] +- sub sp, sp, outgoing_args_size */ ++ sub sp, sp, bytes_below_hard_fp */ + cfun->machine->frame.callee_adjust = cfun->machine->frame.hard_fp_offset; + cfun->machine->frame.final_adjust + = cfun->machine->frame.frame_size - cfun->machine->frame.callee_adjust; +@@ -2945,17 +2948,19 @@ aarch64_layout_frame (void) + cfun->machine->frame.callee_adjust = varargs_and_saved_regs_size; + cfun->machine->frame.final_adjust + = cfun->machine->frame.frame_size - cfun->machine->frame.callee_adjust; ++ cfun->machine->frame.bytes_below_hard_fp ++ = cfun->machine->frame.final_adjust; + cfun->machine->frame.hard_fp_offset = cfun->machine->frame.callee_adjust; + cfun->machine->frame.locals_offset = cfun->machine->frame.hard_fp_offset; + } + else + { +- /* Frame with large local area and outgoing arguments using frame pointer: ++ /* General case: + sub sp, sp, hard_fp_offset + stp x29, x30, [sp, 0] + add x29, sp, 0 + stp reg3, reg4, [sp, 16] +- sub sp, sp, outgoing_args_size */ ++ sub sp, sp, bytes_below_hard_fp */ + cfun->machine->frame.initial_adjust = cfun->machine->frame.hard_fp_offset; + cfun->machine->frame.final_adjust + = cfun->machine->frame.frame_size - cfun->machine->frame.initial_adjust; +@@ -3313,9 +3318,11 @@ aarch64_get_separate_components (void) + if (aarch64_register_saved_on_entry (regno)) + { + HOST_WIDE_INT offset = cfun->machine->frame.reg_offset[regno]; ++ ++ /* Get the offset relative to the register we'll use. */ + if (!frame_pointer_needed) +- offset += cfun->machine->frame.frame_size +- - cfun->machine->frame.hard_fp_offset; ++ offset += cfun->machine->frame.bytes_below_hard_fp; ++ + /* Check that we can access the stack slot of the register with one + direct load with no adjustments needed. */ + if (offset_12bit_unsigned_scaled_p (DImode, offset)) +@@ -3418,8 +3425,8 @@ aarch64_process_components (sbitmap components, bool prologue_p) + rtx reg = gen_rtx_REG (mode, regno); + HOST_WIDE_INT offset = cfun->machine->frame.reg_offset[regno]; + if (!frame_pointer_needed) +- offset += cfun->machine->frame.frame_size +- - cfun->machine->frame.hard_fp_offset; ++ offset += cfun->machine->frame.bytes_below_hard_fp; ++ + rtx addr = plus_constant (Pmode, ptr_reg, offset); + rtx mem = gen_frame_mem (mode, addr); + +@@ -3460,8 +3467,7 @@ aarch64_process_components (sbitmap components, bool prologue_p) + /* REGNO2 can be saved/restored in a pair with REGNO. */ + rtx reg2 = gen_rtx_REG (mode, regno2); + if (!frame_pointer_needed) +- offset2 += cfun->machine->frame.frame_size +- - cfun->machine->frame.hard_fp_offset; ++ offset2 += cfun->machine->frame.bytes_below_hard_fp; + rtx addr2 = plus_constant (Pmode, ptr_reg, offset2); + rtx mem2 = gen_frame_mem (mode, addr2); + rtx set2 = prologue_p ? gen_rtx_SET (mem2, reg2) +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index ddf833ebfe8..6dc6ef2b989 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -558,9 +558,13 @@ struct GTY (()) aarch64_frame + HOST_WIDE_INT saved_varargs_size; + + /* The size of the saved callee-save int/FP registers. */ +- + HOST_WIDE_INT saved_regs_size; + ++ /* The number of bytes between the bottom of the static frame (the bottom ++ of the outgoing arguments) and the hard frame pointer. This value is ++ always a multiple of STACK_BOUNDARY. */ ++ HOST_WIDE_INT bytes_below_hard_fp; ++ + /* Offset from the base of the frame (incomming SP) to the + top of the locals area. This value is always a multiple of + STACK_BOUNDARY. */ +-- +2.39.3 + diff --git a/aarch64-Explicitly-handle-frames-with-no-saved-registers.patch b/aarch64-Explicitly-handle-frames-with-no-saved-registers.patch new file mode 100644 index 0000000..401ff49 --- /dev/null +++ b/aarch64-Explicitly-handle-frames-with-no-saved-registers.patch @@ -0,0 +1,40 @@ +From 04553281f42e5c4340d554a93d1a73006365d8fb Mon Sep 17 00:00:00 2001 +From: Richard Sandiford +Date: Fri, 16 Jun 2023 17:00:51 +0100 +Subject: [PATCH] aarch64: Explicitly handle frames with no saved registers + +If a frame has no saved registers, it can be allocated in one go. +There is no need to treat the areas below and above the saved +registers as separate. + +This is a no-op as thing stand, since a leaf function will have +no outgoing arguments, and so all the frame will be above where +the saved registers normally go. + +gcc/ + * config/aarch64/aarch64.c (aarch64_layout_frame): Explicitly + allocate the frame in one go if there are no saved registers. +--- + gcc/config/aarch64/aarch64.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 4e94be3b0b4..bb4f6020e5d 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -2901,8 +2901,10 @@ aarch64_layout_frame (void) + else if (cfun->machine->frame.wb_candidate1 != INVALID_REGNUM) + max_push_offset = 256; + +- if (cfun->machine->frame.frame_size < max_push_offset +- && crtl->outgoing_args_size == 0) ++ if (cfun->machine->frame.saved_regs_size == 0) ++ cfun->machine->frame.initial_adjust = cfun->machine->frame.frame_size; ++ else if (cfun->machine->frame.frame_size < max_push_offset ++ && crtl->outgoing_args_size == 0) + { + /* Simple, small frame with no outgoing arguments: + stp reg1, reg2, [sp, -frame_size]! +-- +2.39.3 + diff --git a/aarch64-Make-stack-smash-canary-protect-saved-registers.patch b/aarch64-Make-stack-smash-canary-protect-saved-registers.patch new file mode 100644 index 0000000..bc022cc --- /dev/null +++ b/aarch64-Make-stack-smash-canary-protect-saved-registers.patch @@ -0,0 +1,281 @@ +From c2c772172f0478315ab94386ebf9963efd36eb75 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford +Date: Thu, 15 Jun 2023 19:16:52 +0100 +Subject: [PATCH] aarch64: Make stack smash canary protect saved registers + +AArch64 normally puts the saved registers near the bottom of the frame, +immediately above any dynamic allocations. But this means that a +stack-smash attack on those dynamic allocations could overwrite the +saved registers without needing to reach as far as the stack smash +canary. + +The same thing could also happen for variable-sized arguments that are +passed by value, since those are allocated before a call and popped on +return. + +This patch avoids that by putting the locals (and thus the canary) below +the saved registers when stack smash protection is active. + +The patch fixes CVE-2023-4039. + +gcc/ + * config/aarch64/aarch64.c (aarch64_save_regs_above_locals_p): + New function. + (aarch64_layout_frame): Use it to decide whether locals should + go above or below the saved registers. + (aarch64_expand_prologue): Update stack layout comment. + Emit a stack tie after the final adjustment. + +gcc/testsuite/ + * gcc.target/aarch64/stack-protector-8.c: New test. + * gcc.target/aarch64/stack-protector-9.c: Likewise. +--- + gcc/config/aarch64/aarch64.c | 45 +++++++++- + .../gcc.target/aarch64/stack-protector-8.c | 86 +++++++++++++++++++ + .../gcc.target/aarch64/stack-protector-9.c | 33 +++++++ + 3 files changed, 161 insertions(+), 3 deletions(-) + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-protector-8.c + create mode 100644 gcc/testsuite/gcc.target/aarch64/stack-protector-9.c + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index e3c36abb1e3..8708b4fe4ea 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -2780,6 +2780,20 @@ aarch64_frame_pointer_required (void) + return false; + } + ++/* Return true if the current function should save registers above ++ the locals area, rather than below it. */ ++ ++static bool ++aarch64_save_regs_above_locals_p () ++{ ++ /* When using stack smash protection, make sure that the canary slot ++ comes between the locals and the saved registers. Otherwise, ++ it would be possible for a carefully sized smash attack to change ++ the saved registers (particularly LR and FP) without reaching the ++ canary. */ ++ return crtl->stack_protect_guard; ++} ++ + /* Mark the registers that need to be saved by the callee and calculate + the size of the callee-saved registers area and frame record (both FP + and LR may be omitted). */ +@@ -2828,6 +2842,16 @@ aarch64_layout_frame (void) + + cfun->machine->frame.bytes_below_hard_fp = crtl->outgoing_args_size; + ++ bool regs_at_top_p = aarch64_save_regs_above_locals_p (); ++ ++ if (regs_at_top_p) ++ { ++ cfun->machine->frame.bytes_below_hard_fp += get_frame_size (); ++ cfun->machine->frame.bytes_below_hard_fp ++ = ROUND_UP (cfun->machine->frame.bytes_below_hard_fp, ++ STACK_BOUNDARY / BITS_PER_UNIT); ++ } ++ + if (frame_pointer_needed) + { + /* FP and LR are placed in the linkage record. */ +@@ -2881,8 +2905,11 @@ aarch64_layout_frame (void) + HOST_WIDE_INT varargs_and_saved_regs_size + = offset + cfun->machine->frame.saved_varargs_size; + ++ cfun->machine->frame.bytes_above_hard_fp = varargs_and_saved_regs_size; ++ if (!regs_at_top_p) ++ cfun->machine->frame.bytes_above_hard_fp += get_frame_size (); + cfun->machine->frame.bytes_above_hard_fp +- = ROUND_UP (varargs_and_saved_regs_size + get_frame_size (), ++ = ROUND_UP (cfun->machine->frame.bytes_above_hard_fp, + STACK_BOUNDARY / BITS_PER_UNIT); + + cfun->machine->frame.frame_size +@@ -2892,6 +2919,9 @@ aarch64_layout_frame (void) + + cfun->machine->frame.bytes_above_locals + = cfun->machine->frame.saved_varargs_size; ++ if (regs_at_top_p) ++ cfun->machine->frame.bytes_above_locals ++ += cfun->machine->frame.saved_regs_size; + + cfun->machine->frame.initial_adjust = 0; + cfun->machine->frame.final_adjust = 0; +@@ -3537,10 +3567,10 @@ aarch64_set_handled_components (sbitmap components) + | for register varargs | + | | + +-------------------------------+ +- | local variables | <-- frame_pointer_rtx ++ | local variables (1) | <-- frame_pointer_rtx + | | + +-------------------------------+ +- | padding0 | \ ++ | padding (1) | \ + +-------------------------------+ | + | callee-saved registers | | frame.saved_regs_size + +-------------------------------+ | +@@ -3548,6 +3578,10 @@ aarch64_set_handled_components (sbitmap components) + +-------------------------------+ | + | FP' | / <- hard_frame_pointer_rtx (aligned) + +-------------------------------+ ++ | local variables (2) | ++ +-------------------------------+ ++ | padding (2) | ++ +-------------------------------+ + | dynamic allocation | + +-------------------------------+ + | padding | +@@ -3557,6 +3591,9 @@ aarch64_set_handled_components (sbitmap components) + +-------------------------------+ + | | <-- stack_pointer_rtx (aligned) + ++ The regions marked (1) and (2) are mutually exclusive. (2) is used ++ when aarch64_save_regs_above_locals_p is true. ++ + Dynamic stack allocations via alloca() decrease stack_pointer_rtx + but leave frame_pointer_rtx and hard_frame_pointer_rtx + unchanged. */ +@@ -3626,6 +3663,8 @@ aarch64_expand_prologue (void) + aarch64_save_callee_saves (DFmode, callee_offset, V0_REGNUM, V31_REGNUM, + callee_adjust != 0 || frame_pointer_needed); + aarch64_sub_sp (IP1_REGNUM, final_adjust, !frame_pointer_needed); ++ if (frame_pointer_needed && final_adjust != 0) ++ emit_insn (gen_stack_tie (stack_pointer_rtx, hard_frame_pointer_rtx)); + } + + /* Return TRUE if we can use a simple_return insn. +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-protector-8.c b/gcc/testsuite/gcc.target/aarch64/stack-protector-8.c +new file mode 100644 +index 00000000000..2575abbec73 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-protector-8.c +@@ -0,0 +1,86 @@ ++/* { dg-options " -O -fstack-protector-strong" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++void g(void *); ++ ++/* ++** test1: ++** sub sp, sp, #304 ++** stp x29, x30, \[sp, #?272\] ++** add x29, sp, #?272 ++** str (x[0-9]+), \[sp, #?288\] ++** ... ++** ldr (x[0-9]+), \[\1\] ++** str \2, \[(?:sp, #?264|x29, #?-8)\] ++** mov \2, *0 ++** ( ++** add x0, sp, #?8 ++** | ++** sub x0, x29, #?264 ++** ) ++** bl g ++** ... ++** ldr x[0-9]+, \[\1\] ++** ... ++** ( ++** bne .* ++** | ++** cbnz .* ++** ) ++** ... ++** ldr \1, \[sp, #?288\] ++** ldp x29, x30, \[sp, #?272\] ++** add sp, sp, #?304 ++** ret ++** bl __stack_chk_fail ++*/ ++int test1() { ++ int y[0x40]; ++ g(y); ++ return 1; ++} ++ ++/* ++** test2: ++** stp x29, x30, \[sp, #?-32\]! ++** ( ++** mov x29, sp ++** | ++** add x29, sp, #?0 ++** ) ++** str (x[0-9]+), \[sp, #?16\] ++** sub sp, sp, #1040 ++** ... ++** ldr (x[0-9]+), \[\1\] ++** str \2, \[(?:sp, #?1032|x29, #?-8)\] ++** mov \2, *0 ++** ( ++** add x0, sp, #?8 ++** | ++** sub x0, x29, #?1032 ++** ) ++** bl g ++** ... ++** ldr x[0-9]+, \[\1\] ++** ... ++** ( ++** bne .* ++** | ++** cbnz .* ++** ) ++** ... ++** ( ++** add sp, sp, #?1040 ++** | ++** add sp, x29, #?0 ++** ) ++** ldr \1, \[sp, #?16\] ++** ldp x29, x30, \[sp\], #?32 ++** ret ++** bl __stack_chk_fail ++*/ ++int test2() { ++ int y[0x100]; ++ g(y); ++ return 1; ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-protector-9.c b/gcc/testsuite/gcc.target/aarch64/stack-protector-9.c +new file mode 100644 +index 00000000000..1d267343806 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/stack-protector-9.c +@@ -0,0 +1,33 @@ ++/* { dg-options "-O2 -mcpu=cortex-a73 -fstack-protector-all" } */ ++/* { dg-final { check-function-bodies "**" "" } } */ ++ ++/* ++** main: ++** ... ++** stp x29, x30, \[sp, #?-[0-9]+\]! ++** ... ++** sub sp, sp, #[0-9]+ ++** ... ++** str x[0-9]+, \[x29, #?-8\] ++** ... ++*/ ++int f(const char *); ++void g(void *); ++int main(int argc, char* argv[]) ++{ ++ int a; ++ int b; ++ char c[2+f(argv[1])]; ++ int d[0x100]; ++ char y; ++ ++ y=42; a=4; b=10; ++ c[0] = 'h'; c[1] = '\0'; ++ ++ c[f(argv[2])] = '\0'; ++ ++ __builtin_printf("%d %d\n%s\n", a, b, c); ++ g(d); ++ ++ return 0; ++} +-- +2.39.3 + diff --git a/aarch64-Rename-hard_fp_offset-to-bytes_above_hard_fp.patch b/aarch64-Rename-hard_fp_offset-to-bytes_above_hard_fp.patch new file mode 100644 index 0000000..2d444db --- /dev/null +++ b/aarch64-Rename-hard_fp_offset-to-bytes_above_hard_fp.patch @@ -0,0 +1,141 @@ +From da0132a4cd2eb26ecaff20578bf2753b20014223 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford +Date: Tue, 27 Jun 2023 11:28:11 +0100 +Subject: [PATCH] aarch64: Rename hard_fp_offset to bytes_above_hard_fp +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +Similarly to the previous locals_offset patch, hard_fp_offset +was described as: + + /* Offset from the base of the frame (incomming SP) to the + hard_frame_pointer. This value is always a multiple of + STACK_BOUNDARY. */ + poly_int64 hard_fp_offset; + +which again took an “upside-down” view: higher offsets meant lower +addresses. This patch renames the field to bytes_above_hard_fp instead. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::hard_fp_offset): Rename + to... + (aarch64_frame::bytes_above_hard_fp): ...this. + * config/aarch64/aarch64.c (aarch64_layout_frame) + (aarch64_expand_prologue): Update accordingly. + (aarch64_initial_elimination_offset): Likewise. +--- + gcc/config/aarch64/aarch64.c | 29 ++++++++++++++++------------- + gcc/config/aarch64/aarch64.h | 6 +++--- + 2 files changed, 19 insertions(+), 16 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 27dd3b7a62b..e3c36abb1e3 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -2881,12 +2881,12 @@ aarch64_layout_frame (void) + HOST_WIDE_INT varargs_and_saved_regs_size + = offset + cfun->machine->frame.saved_varargs_size; + +- cfun->machine->frame.hard_fp_offset ++ cfun->machine->frame.bytes_above_hard_fp + = ROUND_UP (varargs_and_saved_regs_size + get_frame_size (), + STACK_BOUNDARY / BITS_PER_UNIT); + + cfun->machine->frame.frame_size +- = ROUND_UP (cfun->machine->frame.hard_fp_offset ++ = ROUND_UP (cfun->machine->frame.bytes_above_hard_fp + + cfun->machine->frame.bytes_below_hard_fp, + STACK_BOUNDARY / BITS_PER_UNIT); + +@@ -2917,7 +2917,7 @@ aarch64_layout_frame (void) + else if ((cfun->machine->frame.bytes_below_hard_fp + + cfun->machine->frame.saved_regs_size < 512) + && !(cfun->calls_alloca +- && cfun->machine->frame.hard_fp_offset < max_push_offset)) ++ && cfun->machine->frame.bytes_above_hard_fp < max_push_offset)) + { + /* Frame with small area below the saved registers: + sub sp, sp, frame_size +@@ -2925,16 +2925,17 @@ aarch64_layout_frame (void) + stp reg3, reg4, [sp, bytes_below_hard_fp + 16] */ + cfun->machine->frame.initial_adjust = cfun->machine->frame.frame_size; + cfun->machine->frame.callee_offset +- = cfun->machine->frame.frame_size - cfun->machine->frame.hard_fp_offset; ++ = cfun->machine->frame.frame_size - cfun->machine->frame.bytes_above_hard_fp; + } +- else if (cfun->machine->frame.hard_fp_offset < max_push_offset) ++ else if (cfun->machine->frame.bytes_above_hard_fp < max_push_offset) + { + /* Frame with large area below the saved registers, but with a + small area above: +- stp reg1, reg2, [sp, -hard_fp_offset]! ++ stp reg1, reg2, [sp, -bytes_above_hard_fp]! + stp reg3, reg4, [sp, 16] + sub sp, sp, bytes_below_hard_fp */ +- cfun->machine->frame.callee_adjust = cfun->machine->frame.hard_fp_offset; ++ cfun->machine->frame.callee_adjust ++ = cfun->machine->frame.bytes_above_hard_fp; + cfun->machine->frame.final_adjust + = cfun->machine->frame.frame_size - cfun->machine->frame.callee_adjust; + } +@@ -2951,19 +2952,21 @@ aarch64_layout_frame (void) + = cfun->machine->frame.frame_size - cfun->machine->frame.callee_adjust; + cfun->machine->frame.bytes_below_hard_fp + = cfun->machine->frame.final_adjust; +- cfun->machine->frame.hard_fp_offset = cfun->machine->frame.callee_adjust; ++ cfun->machine->frame.bytes_above_hard_fp ++ = cfun->machine->frame.callee_adjust; + cfun->machine->frame.bytes_above_locals +- = cfun->machine->frame.hard_fp_offset; ++ = cfun->machine->frame.bytes_above_hard_fp; + } + else + { + /* General case: +- sub sp, sp, hard_fp_offset ++ sub sp, sp, bytes_above_hard_fp + stp x29, x30, [sp, 0] + add x29, sp, 0 + stp reg3, reg4, [sp, 16] + sub sp, sp, bytes_below_hard_fp */ +- cfun->machine->frame.initial_adjust = cfun->machine->frame.hard_fp_offset; ++ cfun->machine->frame.initial_adjust ++ = cfun->machine->frame.bytes_above_hard_fp; + cfun->machine->frame.final_adjust + = cfun->machine->frame.frame_size - cfun->machine->frame.initial_adjust; + } +@@ -5651,10 +5654,10 @@ aarch64_initial_elimination_offset (unsigned from, unsigned to) + if (to == HARD_FRAME_POINTER_REGNUM) + { + if (from == ARG_POINTER_REGNUM) +- return cfun->machine->frame.hard_fp_offset; ++ return cfun->machine->frame.bytes_above_hard_fp; + + if (from == FRAME_POINTER_REGNUM) +- return cfun->machine->frame.hard_fp_offset ++ return cfun->machine->frame.bytes_above_hard_fp + - cfun->machine->frame.bytes_above_locals; + } + +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 79af237ada6..35ba9681e03 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -570,10 +570,10 @@ struct GTY (()) aarch64_frame + STACK_BOUNDARY. */ + HOST_WIDE_INT bytes_above_locals; + +- /* Offset from the base of the frame (incomming SP) to the +- hard_frame_pointer. This value is always a multiple of ++ /* The number of bytes between the hard_frame_pointer and the top of ++ the frame (the incomming SP). This value is always a multiple of + STACK_BOUNDARY. */ +- HOST_WIDE_INT hard_fp_offset; ++ HOST_WIDE_INT bytes_above_hard_fp; + + /* The size of the frame. This value is the offset from base of the + * frame (incomming SP) to the stack_pointer. This value is always +-- +2.39.3 + diff --git a/aarch64-Rename-locals_offset-to-bytes_above_locals.patch b/aarch64-Rename-locals_offset-to-bytes_above_locals.patch new file mode 100644 index 0000000..5ccd558 --- /dev/null +++ b/aarch64-Rename-locals_offset-to-bytes_above_locals.patch @@ -0,0 +1,104 @@ +From e628f34ef3a7db3a75aa146b3e75099a9c431d20 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford +Date: Tue, 27 Jun 2023 11:25:40 +0100 +Subject: [PATCH] aarch64: Rename locals_offset to bytes_above_locals +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +locals_offset was described as: + + /* Offset from the base of the frame (incomming SP) to the + top of the locals area. This value is always a multiple of + STACK_BOUNDARY. */ + +This is implicitly an “upside down” view of the frame: the incoming +SP is at offset 0, and anything N bytes below the incoming SP is at +offset N (rather than -N). + +However, reg_offset instead uses a “right way up” view; that is, +it views offsets in address terms. Something above X is at a +positive offset from X and something below X is at a negative +offset from X. + +Also, even on FRAME_GROWS_DOWNWARD targets like AArch64, +target-independent code views offsets in address terms too: +locals are allocated at negative offsets to virtual_stack_vars. + +It seems confusing to have *_offset fields of the same structure +using different polarities like this. This patch tries to avoid +that by renaming locals_offset to bytes_above_locals. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::locals_offset): Rename to... + (aarch64_frame::bytes_above_locals): ...this. + * config/aarch64/aarch64.c (aarch64_layout_frame) + (aarch64_initial_elimination_offset): Update accordingly. +--- + gcc/config/aarch64/aarch64.c | 12 +++++++----- + gcc/config/aarch64/aarch64.h | 6 +++--- + 2 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c +index 12df8bb783c..27dd3b7a62b 100644 +--- a/gcc/config/aarch64/aarch64.c ++++ b/gcc/config/aarch64/aarch64.c +@@ -2890,7 +2890,8 @@ aarch64_layout_frame (void) + + cfun->machine->frame.bytes_below_hard_fp, + STACK_BOUNDARY / BITS_PER_UNIT); + +- cfun->machine->frame.locals_offset = cfun->machine->frame.saved_varargs_size; ++ cfun->machine->frame.bytes_above_locals ++ = cfun->machine->frame.saved_varargs_size; + + cfun->machine->frame.initial_adjust = 0; + cfun->machine->frame.final_adjust = 0; +@@ -2951,7 +2952,8 @@ aarch64_layout_frame (void) + cfun->machine->frame.bytes_below_hard_fp + = cfun->machine->frame.final_adjust; + cfun->machine->frame.hard_fp_offset = cfun->machine->frame.callee_adjust; +- cfun->machine->frame.locals_offset = cfun->machine->frame.hard_fp_offset; ++ cfun->machine->frame.bytes_above_locals ++ = cfun->machine->frame.hard_fp_offset; + } + else + { +@@ -5653,14 +5655,14 @@ aarch64_initial_elimination_offset (unsigned from, unsigned to) + + if (from == FRAME_POINTER_REGNUM) + return cfun->machine->frame.hard_fp_offset +- - cfun->machine->frame.locals_offset; ++ - cfun->machine->frame.bytes_above_locals; + } + + if (to == STACK_POINTER_REGNUM) + { + if (from == FRAME_POINTER_REGNUM) +- return cfun->machine->frame.frame_size +- - cfun->machine->frame.locals_offset; ++ return cfun->machine->frame.frame_size ++ - cfun->machine->frame.bytes_above_locals; + } + + return cfun->machine->frame.frame_size; +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 6dc6ef2b989..79af237ada6 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -565,10 +565,10 @@ struct GTY (()) aarch64_frame + always a multiple of STACK_BOUNDARY. */ + HOST_WIDE_INT bytes_below_hard_fp; + +- /* Offset from the base of the frame (incomming SP) to the +- top of the locals area. This value is always a multiple of ++ /* The number of bytes between the top of the locals area and the top ++ of the frame (the incomming SP). This value is always a multiple of + STACK_BOUNDARY. */ +- HOST_WIDE_INT locals_offset; ++ HOST_WIDE_INT bytes_above_locals; + + /* Offset from the base of the frame (incomming SP) to the + hard_frame_pointer. This value is always a multiple of +-- +2.39.3 + diff --git a/aarch64-Tweak-frame_size-comment.patch b/aarch64-Tweak-frame_size-comment.patch new file mode 100644 index 0000000..d184ccf --- /dev/null +++ b/aarch64-Tweak-frame_size-comment.patch @@ -0,0 +1,37 @@ +From 19776fcf06856ceff521f99a1ceddaf113cf0d09 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford +Date: Thu, 22 Jun 2023 22:26:30 +0100 +Subject: [PATCH] aarch64: Tweak frame_size comment +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf8 +Content-Transfer-Encoding: 8bit + +This patch fixes another case in which a value was described with +an “upside-down” view. + +gcc/ + * config/aarch64/aarch64.h (aarch64_frame::frame_size): Tweak comment. +--- + gcc/config/aarch64/aarch64.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 35ba9681e03..19b7082187a 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -575,9 +575,9 @@ struct GTY (()) aarch64_frame + STACK_BOUNDARY. */ + HOST_WIDE_INT bytes_above_hard_fp; + +- /* The size of the frame. This value is the offset from base of the +- * frame (incomming SP) to the stack_pointer. This value is always +- * a multiple of STACK_BOUNDARY. */ ++ /* The size of the frame, i.e. the number of bytes between the bottom ++ of the outgoing arguments and the incoming SP. This value is always ++ a multiple of STACK_BOUNDARY. */ + HOST_WIDE_INT frame_size; + + /* The size of the initial stack adjustment before saving callee-saves. */ +-- +2.39.3 + diff --git a/gcc.spec b/gcc.spec index 158c612..6b43b70 100644 --- a/gcc.spec +++ b/gcc.spec @@ -41,7 +41,7 @@ Version: 7.3.0 # number 2020033101 meaning the openEuler 20.03 release date plus 01 to # replace DATE and will never change it in the future. %global openEulerDATE 2020033101 -Release: %{openEulerDATE}.51 +Release: %{openEulerDATE}.52 License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ with exceptions and LGPLv2+ and BSD Group: Development/Languages #Source0: hcc-aarch64-linux-release.tar.bz2 @@ -98,6 +98,13 @@ Patch41: PR-c-83227-C-17-ICE-with-init-list-derived.patch Patch42: Remove-_GLIBCXX_USE_INT128-autoconf-macro.patch Patch43: Add-bolt-linker-plugin.patch Patch44: Enable-BOLT-linker-plugin-on-aarch64.patch +Patch45: aarch64-Explicitly-handle-frames-with-no-saved-registers.patch +Patch46: aarch64-Add-bytes_below_hard_fp-to-frame-info.patch +Patch47: aarch64-Rename-locals_offset-to-bytes_above_locals.patch +Patch48: aarch64-Rename-hard_fp_offset-to-bytes_above_hard_fp.patch +Patch49: aarch64-Tweak-frame_size-comment.patch +Patch50: Backport-check-function-bodies-support.patch +Patch51: aarch64-Make-stack-smash-canary-protect-saved-registers.patch #AutoReqProv: off AutoReq: true @@ -586,6 +593,13 @@ package or when debugging this package. %patch42 -p1 %patch43 -p1 %patch44 -p1 +%patch45 -p1 +%patch46 -p1 +%patch47 -p1 +%patch48 -p1 +%patch49 -p1 +%patch50 -p1 +%patch51 -p1 %if 0%{?_enable_debug_packages} cat > split-debuginfo.sh <<\EOF @@ -3346,6 +3360,9 @@ fi %changelog +* Tue Oct 10 2023 Xiong Zhou -7.3.0-2020033101.52 +- Fix CVE-2023-4039. + * Sat Nov 19 2022 liyancheng <412998149@qq.com> - 7.3.0-2020033101.51 - gcc.spec: Update libstdc++ requires. -- Gitee