https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128409

            Bug ID: 128409
           Summary: ix86_expand_epilogue tests flag_cf_protection as a
                    boolean instead of checking CF_RETURN bit
           Product: gcc
           Version: 16.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: target
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ubizjak at gmail dot com
  Target Milestone: ---

flag_cf_protection is a bitmask (enum cf_protection_level in flag-types.h), not
a boolean.  Besides the feature bits CF_BRANCH and CF_RETURN, it can carry the
bookkeeping bits CF_SET and CF_CHECK.

Some places in the i386 backend still use it "naked", so any nonzero value is
treated as if the shadow stack (CF_RETURN) were enabled, including values with
only CF_BRANCH, CF_SET or CF_CHECK set.

In gcc/config/i386/i386.cc (ix86_expand_epilogue):

  pro_epilogue_adjust_stack (stack_pointer_rtx, sa,
                             const0_rtx, style,
                             flag_cf_protection);

and

  /* In case of return from EH a simple return cannot be used
     as a return address will be compared with a shadow stack
     return address.  Use indirect jump instead.  */
  if (style == 2 && flag_cf_protection)

With e.g. -fcf-protection=branch (IBT only, no shadow stack), the EH-return
epilogue still takes the indirect-jump path and passes set_cfa as if the shadow
stack were enabled, even though nothing compares the return address against a
shadow stack.

Testcase:

--cut here--
void
foo (long offset, void *handler)
{
  __builtin_eh_return (offset, handler);
}
--cut here--

gcc -O2 -fcf-protection=branch (even -fcf-protection=check):

foo:
        .cfi_startproc
        endbr64
        pushq   %rdx
        .cfi_def_cfa_offset 16
        .cfi_offset 1, -16
        movq    %rdi, %rcx
        pushq   %rax
        .cfi_def_cfa_offset 24
        .cfi_offset 0, -24
        movq    %rsi, 16(%rsp,%rdi)
        movq    (%rsp), %rax
        movq    8(%rsp), %rdx
        leaq    16(%rsp,%rcx), %rsp
        .cfi_def_cfa_offset 8
        popq    %rcx
        .cfi_register 16, 2
        .cfi_def_cfa_offset 0
        jmp     *%rcx
        .cfi_endproc

Without -fcf-protection=return, a plain ret should be used, as in the no-CET
case. The indirect jump should only be used when CF_RETURN is set.

Reply via email to