mbox series

[v4,00/15] x86: Add support for Clang CFI

Message ID 20210930180531.1190642-1-samitolvanen@google.com (mailing list archive)
Headers show
Series x86: Add support for Clang CFI | expand

Message

Sami Tolvanen Sept. 30, 2021, 6:05 p.m. UTC
This series adds support for Clang's Control-Flow Integrity (CFI)
checking to x86_64. With CFI, the compiler injects a runtime
check before each indirect function call to ensure the target is
a valid function with the correct static type. This restricts
possible call targets and makes it more difficult for an attacker
to exploit bugs that allow the modification of stored function
pointers. For more details, see:

  https://clang.llvm.org/docs/ControlFlowIntegrity.html

Note that v4 is based on tip/master. The first two patches contain
objtool support for CFI, the remaining patches change function
declarations to use opaque types, fix type mismatch issues that
confuse the compiler, and disable CFI where it can't be used.

You can also pull this series from

  https://github.com/samitolvanen/linux.git x86-cfi-v4

---
Changes in v4:
- Dropped the extable patch after the code was refactored in -tip.

- Switched to __section() instead of open-coding the attribute.

- Added an explicit ifdef for filtering out CC_FLAGS_CFI in
  purgatory for readability.

- Added a comment to arch_cfi_jump_reloc_offset() in objtool.

Changes in v3:
- Dropped Clang requirement to >= 13 after the missing compiler
  fix was backported there.

- Added DEFINE_CFI_IMMEDIATE_RETURN_STUB to address the issue
  with tp_stub_func in kernel/tracepoint.c.

- Renamed asm_func_t to asm_func_ptr.

- Changed extable handlers to use __cficanonical instead of
  disabling CFI for fixup_exception.

Changes in v2:
- Dropped the first objtool patch as the warnings were fixed in
  separate patches.

- Changed fix_cfi_relocs() in objtool to not rely on jump table
  symbols, and to return an error if it can't find a relocation.

- Fixed a build issue with ASM_STACK_FRAME_NON_STANDARD().

- Dropped workarounds for inline assembly references to
  address-taken static functions with CFI as this was fixed in
  the compiler.

- Changed the C declarations of non-callable functions to use
  opaque types and dropped the function_nocfi() patches.

- Changed ARCH_SUPPORTS_CFI_CLANG to depend on Clang >=14 for
  the compiler fixes.


Kees Cook (1):
  x86, relocs: Ignore __typeid__ relocations

Sami Tolvanen (14):
  objtool: Add CONFIG_CFI_CLANG support
  objtool: Add ASM_STACK_FRAME_NON_STANDARD
  linkage: Add DECLARE_ASM_FUNC_SYMBOL
  cfi: Add DEFINE_CFI_IMMEDIATE_RETURN_STUB
  tracepoint: Exclude tp_stub_func from CFI checking
  ftrace: Use an opaque type for functions not callable from C
  lkdtm: Disable UNSET_SMEP with CFI
  lkdtm: Use an opaque type for lkdtm_rodata_do_nothing
  x86: Use an opaque type for functions not callable from C
  x86/purgatory: Disable CFI
  x86, module: Ignore __typeid__ relocations
  x86, cpu: Use LTO for cpu.c with CFI
  x86, kprobes: Fix optprobe_template_func type mismatch
  x86, build: Allow CONFIG_CFI_CLANG to be selected

 arch/x86/Kconfig                      |  1 +
 arch/x86/include/asm/ftrace.h         |  2 +-
 arch/x86/include/asm/idtentry.h       | 10 +++---
 arch/x86/include/asm/page_64.h        |  7 ++--
 arch/x86/include/asm/paravirt_types.h |  3 +-
 arch/x86/include/asm/processor.h      |  2 +-
 arch/x86/include/asm/proto.h          | 25 ++++++-------
 arch/x86/include/asm/uaccess_64.h     |  9 ++---
 arch/x86/kernel/alternative.c         |  2 +-
 arch/x86/kernel/ftrace.c              |  2 +-
 arch/x86/kernel/kprobes/opt.c         |  4 +--
 arch/x86/kernel/module.c              |  4 +++
 arch/x86/kernel/paravirt.c            |  4 +--
 arch/x86/kvm/emulate.c                |  4 +--
 arch/x86/kvm/kvm_emulate.h            |  9 ++---
 arch/x86/power/Makefile               |  2 ++
 arch/x86/purgatory/Makefile           |  4 +++
 arch/x86/tools/relocs.c               |  7 ++++
 arch/x86/xen/enlighten_pv.c           |  6 ++--
 arch/x86/xen/xen-ops.h                | 10 +++---
 drivers/misc/lkdtm/bugs.c             |  2 +-
 drivers/misc/lkdtm/lkdtm.h            |  2 +-
 drivers/misc/lkdtm/perms.c            |  2 +-
 drivers/misc/lkdtm/rodata.c           |  2 +-
 include/asm-generic/vmlinux.lds.h     | 11 ++++++
 include/linux/cfi.h                   | 13 +++++++
 include/linux/ftrace.h                |  7 ++--
 include/linux/linkage.h               | 13 +++++++
 include/linux/objtool.h               |  6 ++++
 kernel/cfi.c                          | 24 ++++++++++++-
 kernel/tracepoint.c                   |  5 +--
 tools/include/linux/objtool.h         |  6 ++++
 tools/objtool/arch/x86/decode.c       | 17 +++++++++
 tools/objtool/elf.c                   | 51 +++++++++++++++++++++++++++
 tools/objtool/include/objtool/arch.h  |  3 ++
 tools/objtool/include/objtool/elf.h   |  2 +-
 36 files changed, 217 insertions(+), 66 deletions(-)


base-commit: d4bfebd9ef497ee0afb498f6028a5074a6ccf307

Comments

Nick Desaulniers Sept. 30, 2021, 6:38 p.m. UTC | #1
On Thu, Sep 30, 2021 at 11:05 AM Sami Tolvanen <samitolvanen@google.com> wrote:
>
> This series adds support for Clang's Control-Flow Integrity (CFI)
> checking to x86_64. With CFI, the compiler injects a runtime
> check before each indirect function call to ensure the target is
> a valid function with the correct static type. This restricts
> possible call targets and makes it more difficult for an attacker
> to exploit bugs that allow the modification of stored function
> pointers. For more details, see:
>
>   https://clang.llvm.org/docs/ControlFlowIntegrity.html
>
> Note that v4 is based on tip/master. The first two patches contain
> objtool support for CFI, the remaining patches change function
> declarations to use opaque types, fix type mismatch issues that
> confuse the compiler, and disable CFI where it can't be used.
>
> You can also pull this series from
>
>   https://github.com/samitolvanen/linux.git x86-cfi-v4

I tested this series with near ToT clang with CONFIG_LTO_CLANG_THIN=y
and our small buildroot-based userspace image in QEMU, then again with
CONFIG_LTO_CLANG_FULL=y. No new warnings from objtool, everything
seemed fine.  FWIW,

Tested-by: Nick Desaulniers <ndesaulniers@google.com>

>
> ---
> Changes in v4:
> - Dropped the extable patch after the code was refactored in -tip.
>
> - Switched to __section() instead of open-coding the attribute.
>
> - Added an explicit ifdef for filtering out CC_FLAGS_CFI in
>   purgatory for readability.
>
> - Added a comment to arch_cfi_jump_reloc_offset() in objtool.
>
> Changes in v3:
> - Dropped Clang requirement to >= 13 after the missing compiler
>   fix was backported there.
>
> - Added DEFINE_CFI_IMMEDIATE_RETURN_STUB to address the issue
>   with tp_stub_func in kernel/tracepoint.c.
>
> - Renamed asm_func_t to asm_func_ptr.
>
> - Changed extable handlers to use __cficanonical instead of
>   disabling CFI for fixup_exception.
>
> Changes in v2:
> - Dropped the first objtool patch as the warnings were fixed in
>   separate patches.
>
> - Changed fix_cfi_relocs() in objtool to not rely on jump table
>   symbols, and to return an error if it can't find a relocation.
>
> - Fixed a build issue with ASM_STACK_FRAME_NON_STANDARD().
>
> - Dropped workarounds for inline assembly references to
>   address-taken static functions with CFI as this was fixed in
>   the compiler.
>
> - Changed the C declarations of non-callable functions to use
>   opaque types and dropped the function_nocfi() patches.
>
> - Changed ARCH_SUPPORTS_CFI_CLANG to depend on Clang >=14 for
>   the compiler fixes.
>
>
> Kees Cook (1):
>   x86, relocs: Ignore __typeid__ relocations
>
> Sami Tolvanen (14):
>   objtool: Add CONFIG_CFI_CLANG support
>   objtool: Add ASM_STACK_FRAME_NON_STANDARD
>   linkage: Add DECLARE_ASM_FUNC_SYMBOL
>   cfi: Add DEFINE_CFI_IMMEDIATE_RETURN_STUB
>   tracepoint: Exclude tp_stub_func from CFI checking
>   ftrace: Use an opaque type for functions not callable from C
>   lkdtm: Disable UNSET_SMEP with CFI
>   lkdtm: Use an opaque type for lkdtm_rodata_do_nothing
>   x86: Use an opaque type for functions not callable from C
>   x86/purgatory: Disable CFI
>   x86, module: Ignore __typeid__ relocations
>   x86, cpu: Use LTO for cpu.c with CFI
>   x86, kprobes: Fix optprobe_template_func type mismatch
>   x86, build: Allow CONFIG_CFI_CLANG to be selected
>
>  arch/x86/Kconfig                      |  1 +
>  arch/x86/include/asm/ftrace.h         |  2 +-
>  arch/x86/include/asm/idtentry.h       | 10 +++---
>  arch/x86/include/asm/page_64.h        |  7 ++--
>  arch/x86/include/asm/paravirt_types.h |  3 +-
>  arch/x86/include/asm/processor.h      |  2 +-
>  arch/x86/include/asm/proto.h          | 25 ++++++-------
>  arch/x86/include/asm/uaccess_64.h     |  9 ++---
>  arch/x86/kernel/alternative.c         |  2 +-
>  arch/x86/kernel/ftrace.c              |  2 +-
>  arch/x86/kernel/kprobes/opt.c         |  4 +--
>  arch/x86/kernel/module.c              |  4 +++
>  arch/x86/kernel/paravirt.c            |  4 +--
>  arch/x86/kvm/emulate.c                |  4 +--
>  arch/x86/kvm/kvm_emulate.h            |  9 ++---
>  arch/x86/power/Makefile               |  2 ++
>  arch/x86/purgatory/Makefile           |  4 +++
>  arch/x86/tools/relocs.c               |  7 ++++
>  arch/x86/xen/enlighten_pv.c           |  6 ++--
>  arch/x86/xen/xen-ops.h                | 10 +++---
>  drivers/misc/lkdtm/bugs.c             |  2 +-
>  drivers/misc/lkdtm/lkdtm.h            |  2 +-
>  drivers/misc/lkdtm/perms.c            |  2 +-
>  drivers/misc/lkdtm/rodata.c           |  2 +-
>  include/asm-generic/vmlinux.lds.h     | 11 ++++++
>  include/linux/cfi.h                   | 13 +++++++
>  include/linux/ftrace.h                |  7 ++--
>  include/linux/linkage.h               | 13 +++++++
>  include/linux/objtool.h               |  6 ++++
>  kernel/cfi.c                          | 24 ++++++++++++-
>  kernel/tracepoint.c                   |  5 +--
>  tools/include/linux/objtool.h         |  6 ++++
>  tools/objtool/arch/x86/decode.c       | 17 +++++++++
>  tools/objtool/elf.c                   | 51 +++++++++++++++++++++++++++
>  tools/objtool/include/objtool/arch.h  |  3 ++
>  tools/objtool/include/objtool/elf.h   |  2 +-
>  36 files changed, 217 insertions(+), 66 deletions(-)
>
>
> base-commit: d4bfebd9ef497ee0afb498f6028a5074a6ccf307
> --
> 2.33.0.800.g4c38ced690-goog
>
Josh Poimboeuf Oct. 5, 2021, 8:36 p.m. UTC | #2
On Thu, Sep 30, 2021 at 11:05:16AM -0700, Sami Tolvanen wrote:
> This series adds support for Clang's Control-Flow Integrity (CFI)
> checking to x86_64. With CFI, the compiler injects a runtime
> check before each indirect function call to ensure the target is
> a valid function with the correct static type. This restricts
> possible call targets and makes it more difficult for an attacker
> to exploit bugs that allow the modification of stored function
> pointers. For more details, see:
> 
>   https://clang.llvm.org/docs/ControlFlowIntegrity.html
> 
> Note that v4 is based on tip/master. The first two patches contain
> objtool support for CFI, the remaining patches change function
> declarations to use opaque types, fix type mismatch issues that
> confuse the compiler, and disable CFI where it can't be used.
> 
> You can also pull this series from
> 
>   https://github.com/samitolvanen/linux.git x86-cfi-v4

Does this work for indirect calls made from alternatives?

I'm also wondering whether this works on CONFIG_RETPOLINE systems which
disable retpolines at runtime, combined with Peter's patch to use
objtool to replace retpoline thunk calls with indirect branches:

  9bc0bb50727c ("objtool/x86: Rewrite retpoline thunk calls")

Since presumably objtool runs after the CFI stuff is inserted.
Sami Tolvanen Oct. 5, 2021, 9:52 p.m. UTC | #3
On Tue, Oct 5, 2021 at 1:37 PM Josh Poimboeuf <jpoimboe@redhat.com> wrote:
>
> On Thu, Sep 30, 2021 at 11:05:16AM -0700, Sami Tolvanen wrote:
> > This series adds support for Clang's Control-Flow Integrity (CFI)
> > checking to x86_64. With CFI, the compiler injects a runtime
> > check before each indirect function call to ensure the target is
> > a valid function with the correct static type. This restricts
> > possible call targets and makes it more difficult for an attacker
> > to exploit bugs that allow the modification of stored function
> > pointers. For more details, see:
> >
> >   https://clang.llvm.org/docs/ControlFlowIntegrity.html
> >
> > Note that v4 is based on tip/master. The first two patches contain
> > objtool support for CFI, the remaining patches change function
> > declarations to use opaque types, fix type mismatch issues that
> > confuse the compiler, and disable CFI where it can't be used.
> >
> > You can also pull this series from
> >
> >   https://github.com/samitolvanen/linux.git x86-cfi-v4
>
> Does this work for indirect calls made from alternatives?

It works in the sense that indirect calls made from alternatives won't
trip CFI. The compiler doesn't instrument inline assembly.

> I'm also wondering whether this works on CONFIG_RETPOLINE systems which
> disable retpolines at runtime, combined with Peter's patch to use
> objtool to replace retpoline thunk calls with indirect branches:
>
>   9bc0bb50727c ("objtool/x86: Rewrite retpoline thunk calls")
>
> Since presumably objtool runs after the CFI stuff is inserted.

The indirect call checking is before the retpoline thunk call, so
replacing the call with an indirect call isn't a problem.

Sami
Josh Poimboeuf Oct. 6, 2021, 2:42 a.m. UTC | #4
On Tue, Oct 05, 2021 at 02:52:46PM -0700, Sami Tolvanen wrote:
> On Tue, Oct 5, 2021 at 1:37 PM Josh Poimboeuf <jpoimboe@redhat.com> wrote:
> >
> > On Thu, Sep 30, 2021 at 11:05:16AM -0700, Sami Tolvanen wrote:
> > > This series adds support for Clang's Control-Flow Integrity (CFI)
> > > checking to x86_64. With CFI, the compiler injects a runtime
> > > check before each indirect function call to ensure the target is
> > > a valid function with the correct static type. This restricts
> > > possible call targets and makes it more difficult for an attacker
> > > to exploit bugs that allow the modification of stored function
> > > pointers. For more details, see:
> > >
> > >   https://clang.llvm.org/docs/ControlFlowIntegrity.html
> > >
> > > Note that v4 is based on tip/master. The first two patches contain
> > > objtool support for CFI, the remaining patches change function
> > > declarations to use opaque types, fix type mismatch issues that
> > > confuse the compiler, and disable CFI where it can't be used.
> > >
> > > You can also pull this series from
> > >
> > >   https://github.com/samitolvanen/linux.git x86-cfi-v4
> >
> > Does this work for indirect calls made from alternatives?
> 
> It works in the sense that indirect calls made from alternatives won't
> trip CFI. The compiler doesn't instrument inline assembly.
> 
> > I'm also wondering whether this works on CONFIG_RETPOLINE systems which
> > disable retpolines at runtime, combined with Peter's patch to use
> > objtool to replace retpoline thunk calls with indirect branches:
> >
> >   9bc0bb50727c ("objtool/x86: Rewrite retpoline thunk calls")
> >
> > Since presumably objtool runs after the CFI stuff is inserted.
> 
> The indirect call checking is before the retpoline thunk call, so
> replacing the call with an indirect call isn't a problem.

Ah right.  I managed to forget how this worked and was thinking this
intercepted the indirect call rather than the function pointer.