Bug 1794159

Summary: Annocheck fails on binary compiled with -fstack-clash-protection
Product: Red Hat Enterprise Linux 8 Reporter: Alexandra Petlanová Hájková <ahajkova>
Component: gcc-toolset-9-annobinAssignee: Nick Clifton <nickc>
Status: CLOSED ERRATA QA Contact: Martin Cermak <mcermak>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 8.2CC: ahajkova, dsmith, fweimer, jakub, mpolacek, mprchlik, nickc
Target Milestone: rcKeywords: Triaged
Target Release: 8.0   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: gcc-toolset-9-annobin-9.07-1.el8 Doc Type: No Doc Update
Doc Text:
Story Points: ---
Clone Of:
: 1803173 (view as bug list) Environment:
Last Closed: 2020-04-28 16:05:05 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 1803173, 1828797    
Attachments:
Description Flags
reproducer none

Description Alexandra Petlanová Hájková 2020-01-22 19:27:01 UTC
Created attachment 1654667 [details]
reproducer

Description of problem:
Annocheck fails on binary compiled with -fstack-clash-protection with the

Hardened: ./stat: FAIL: Parts of the binary were compiled without stack clash protection.
Hardened: ./stat: FAIL: Parts of the binary were compiled without suffcient stack protection.

Version-Release number of selected component (if applicable):
gcc-toolset-9-gcc-9.2.1-2.2.el8
gcc-toolset-9-annobin-8.79-2.el8

How reproducible:


Steps to Reproduce:
1. scl enable gcc-toolset-9 bash
2.gcc -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=z13 -mtune=z14 -fasynchronous-unwind-tables -fstack-clash-protection -Wl,-z,relro  -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld stat.c -o stat

3. annocheck ./stat -v

Actual results:
annocheck: Version 8.78.
Hardened: ./stat: binary producer gcc version 8.
Hardened: ./stat: Warning: Multiple versions of a tool were used to build this file (9 8) - using highest version.
Hardened: ./stat: FAIL: (component: main): No stack protection enabled.
Hardened: ./stat: FAIL: (component: main): Compiled without -fstack-clash-protection.
Hardened: ./stat: Warning: Multiple versions of a tool were used to build this file (8 9) - using highest version.
Hardened: ./stat: Warning: Multiple versions of a tool were used to build this file (8 9) - using highest version.
Hardened: ./stat: Warning: Multiple versions of a tool were used to build this file (8 9) - using highest version.
Hardened: ./stat: PASS: No gaps found.
Hardened: ./stat: PASS: Linked with -Wl,-z,now.
Hardened: ./stat: skip: Test for control flow protection.  (Only supported on x86 binaries).
Hardened: ./stat: PASS: One dynamic section/segment found.
Hardened: ./stat: skip: Entry point instruction is ENDBR.  (Not an x86 binary).
Hardened: ./stat: PASS: Compiled with -D_FORTIFY_SOURCE=2.
Hardened: ./stat: PASS: Compiled with -D_GLIBCXX_ASSERTIONS.
Hardened: ./stat: PASS: Linked with -Wl,-z,relro.
Hardened: ./stat: PASS: Stack not executable.
Hardened: ./stat: PASS: Compiled with sufficient optimization.
Hardened: ./stat: PASS: Compiled with PIC/PIE.
Hardened: ./stat: PASS: Compiled as a position independent binary.
Hardened: ./stat: skip: GNU Property note check.  (Only useful on x86_64 binaries).
Hardened: ./stat: PASS: DT_RPATH/DT_RUNPATH absent or rooted at /usr.
Hardened: ./stat: PASS: No RWX segments found.
Hardened: ./stat: PASS: Consistent use of the -fshort-enum option.
Hardened: ./stat: FAIL: Parts of the binary were compiled without stack clash protection.
Hardened: ./stat: FAIL: Parts of the binary were compiled without suffcient stack protection.
Hardened: ./stat: skip: Test for stack realignment support.  (Only needed on i686 binaries).
Hardened: ./stat: PASS: No text relocations found.
Hardened: ./stat: PASS: No thread cancellation problems.
Hardened: ./stat: PASS: GOT/PLT relocations are read only.

Expected results:
with gcc-8.3.1-4.5.el8, annobin-8.78-1.el8

 annocheck -v ./stat
annocheck: Version 8.78.
Hardened: ./stat: binary producer gcc version 8.
Hardened: ./stat: PASS: No gaps found.
Hardened: ./stat: PASS: Linked with -Wl,-z,now.
Hardened: ./stat: skip: Test for control flow protection.  (Only supported on x86 binaries).
Hardened: ./stat: PASS: One dynamic section/segment found.
Hardened: ./stat: skip: Entry point instruction is ENDBR.  (Not an x86 binary).
Hardened: ./stat: PASS: Compiled with -D_FORTIFY_SOURCE=2.
Hardened: ./stat: PASS: Compiled with -D_GLIBCXX_ASSERTIONS.
Hardened: ./stat: PASS: Linked with -Wl,-z,relro.
Hardened: ./stat: PASS: Stack not executable.
Hardened: ./stat: PASS: Compiled with sufficient optimization.
Hardened: ./stat: PASS: Compiled with PIC/PIE.
Hardened: ./stat: PASS: Compiled as a position independent binary.
Hardened: ./stat: skip: GNU Property note check.  (Only useful on x86_64 binaries).
Hardened: ./stat: PASS: DT_RPATH/DT_RUNPATH absent or rooted at /usr.
Hardened: ./stat: PASS: No RWX segments found.
Hardened: ./stat: PASS: Consistent use of the -fshort-enum option.
Hardened: ./stat: PASS: Compiled with -fstack-clash-protection.
Hardened: ./stat: PASS: Compiled with sufficient stack protection.
Hardened: ./stat: skip: Test for stack realignment support.  (Only needed on i686 binaries).
Hardened: ./stat: PASS: No text relocations found.
Hardened: ./stat: PASS: No thread cancellation problems.
Hardened: ./stat: PASS: GOT/PLT relocations are read only.
Hardened: ./stat: PASS.

Comment 1 Marek Polacek 2020-02-10 20:30:31 UTC
Doesn't look like a gcc problem, at least the generated assembly is the same system RHEL 8 gcc v. GTS 9 gcc:

          .globl  main
          .type   main, @function                                                                         
  main:
  .LFB40:
          .cfi_startproc
          subq    $8, %rsp
          .cfi_def_cfa_offset 16
          movq    stat64@GOTPCREL(%rip), %rcx
          movl    $1, %edi
          xorl    %eax, %eax
          movq    stat@GOTPCREL(%rip), %rdx                                                               
          leaq    .LC0(%rip), %rsi
          call    __printf_chk@PLT                                                                        
          xorl    %eax, %eax                  
          addq    $8, %rsp
          .cfi_def_cfa_offset 8
          ret
          .cfi_endproc                                                                                    
  .LFE40: 
          .size   main, .-main

but the .gnu.build.attributes sections created by the annobin plugin differ:

@@ -57,7 +48,7 @@
        .dc.l 15
        .dc.l 0
        .dc.l 0x100
-       .asciz "GA+stack_clash"
+       .asciz "GA!stack_clash"
        .dc.b 0 
        .popsection
 
@@ -111,7 +102,7 @@
        .dc.l 22
        .dc.l 0
        .dc.l 0x100
-       .asciz "GA+omit_frame_pointer"
+       .asciz "GA!omit_frame_pointer"
        .dc.b 0, 0 
        .popsection

Comment 2 Marek Polacek 2020-02-10 20:32:57 UTC
plugin/annobin.cc has 

static void 
record_stack_clash_note (const char * start, const char * end, int type, const char * sec_name)
{
  char buffer [128];
  unsigned len = sprintf (buffer, "GA%cstack_clash",
                          flag_stack_clash_protection ? BOOL_T : BOOL_F);

  annobin_output_static_note (buffer, len + 1, true, "bool: -fstack-clash-protection status",
                              start, end, type, sec_name);
}

so it just looks at flag_stack_clash_protection to determine if the stack-clash protection is on.

This works fine with gcc 9.2.1 from Fedora.

Nick, any ideas?

Comment 3 Jakub Jelinek 2020-02-10 20:37:14 UTC
fstack-clash-protection
Common Report Var(flag_stack_clash_protection) Optimization

So, like many other options, it is a per-function flag rather than per-TU.

Comment 4 Nick Clifton 2020-02-11 13:15:01 UTC
> Nick, any ideas?

There appears to be a discrepancy in the versions of gcc used.  The report shows gcc-9.2.1 being used but the annocheck output reports
 "binary producer gcc version 8".  But this may be because the crt0.o file was built with gcc-8 and this was the first object file encountered by annocheck when it was examining the binary.

Is the binary that is being tested - stat - part of glibc ?  I seem to recall that the stat program was special in some way, but that could just be me mis-remembering.

Is the problem build architecture agnostic ?  I ask because the report appears to imply that the build was for the s390x (the -march=z13 option) but Marek's tests look like they are for the x86_64.

Anyway, I am going to see if I can reproduce the problem locally and investigate further.

Comment 5 Nick Clifton 2020-02-11 13:34:45 UTC
(In reply to Nick Clifton from comment #4)

> There appears to be a discrepancy in the versions of gcc used.  The report
> shows gcc-9.2.1 being used but the annocheck output reports
>  "binary producer gcc version 8". 

Doh!  Just noticed this in the output:

  Warning: Multiple versions of a tool were used to build this file (9 8) - using highest version.

So that answers that question.

Comment 6 Nick Clifton 2020-02-11 13:46:50 UTC
(In reply to Jakub Jelinek from comment #3)

> So, like many other options, it is a per-function flag rather than per-TU.

Right - but this also means that there is a global setting for this flag, which can be overridden on a per-function basis.
The annobin plugin knows about this.  So it records:

 global_stack_clash_option = flag_stack_clash_protection;

during startup and then for every function it checks to see if it has changed:

 if (force
      || global_stack_clash_option != flag_stack_clash_protection)
    {
      annobin_inform (INFORM_VERBOSE, "Recording stack clash protection status of %d for %s",
		      flag_stack_clash_protection, func_name);

      record_stack_clash_note (start_sym, end_sym, FUNC, sec_name);

Comment 7 Nick Clifton 2020-02-11 13:53:36 UTC
(In reply to Nick Clifton from comment #4)
 
> Is the binary that is being tested - stat - part of glibc ?  

Forget that - I have just seen that stat.c is attached to this BZ.  Doh.

Comment 8 Nick Clifton 2020-02-11 14:01:24 UTC
Ok - I can now reproduce the problem with gcc-toolset-9 for RHEL-8.2.
Interestingly the problem does not exist with gcc-toolset-9 for RHEL-8.1.

My best guess at the moment is a discrepancy between the annobin plugin built for gcc-toolset-9 for RHEL-8.2 and the gcc that is part of gcc-toolset-9 for RHEL 8.2.  (There is code in the plugin that is meant to detect this kind of discrepancy, but maybe it has failed).
Investigating...

Comment 9 Nick Clifton 2020-02-11 14:59:35 UTC
Yes - this is a discrepancy problem.  A rebuilt version of the annobin plugin does not have the bug.

All we need to do now is work out how to rebuild annobin for gcc-toolset-9 for RHEL-8.2.0.

Comment 13 Nick Clifton 2020-02-17 08:59:37 UTC
Fixed in gcc-toolset-9-annobin-9.07-1.el8

Comment 19 errata-xmlrpc 2020-04-28 16:05:05 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2020:1754