configure,meson: support Control-Flow Integrity

This patch adds a flag to enable/disable control flow integrity checks
on indirect function calls.
This feature only allows indirect function calls at runtime to functions
with compatible signatures.

This feature is only provided by LLVM/Clang, and depends on link-time
optimization which is currently supported only with LLVM/Clang >= 6.0

We also add an option to enable a debugging version of cfi, with verbose
output in case of a CFI violation.

CFI on indirect function calls does not support calls to functions in
shared libraries (since they were not known at compile time), and such
calls are forbidden. QEMU relies on dlopen/dlsym when using modules,
so we make modules incompatible with CFI.

All the checks are performed in meson.build. configure is only used to
forward the flags to meson

Signed-off-by: Daniele Buono <dbuono@linux.vnet.ibm.com>
Message-Id: <20201204230615.2392-5-dbuono@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Daniele Buono 2020-12-04 18:06:14 -05:00 committed by Paolo Bonzini
parent 24496fe851
commit 9e62ba48ea
3 changed files with 68 additions and 2 deletions

22
configure vendored
View File

@ -411,6 +411,8 @@ coroutine=""
coroutine_pool="$default_feature"
debug_stack_usage="no"
crypto_afalg="no"
cfi="false"
cfi_debug="false"
seccomp="$default_feature"
glusterfs="$default_feature"
glusterfs_xlator_opt="no"
@ -1195,6 +1197,16 @@ for opt do
;;
--disable-safe-stack) safe_stack="no"
;;
--enable-cfi)
cfi="true";
lto="true";
;;
--disable-cfi) cfi="false"
;;
--enable-cfi-debug) cfi_debug="true"
;;
--disable-cfi-debug) cfi_debug="false"
;;
--disable-curses) curses="disabled"
;;
--enable-curses) curses="enabled"
@ -1788,7 +1800,13 @@ disabled with --disable-FEATURE, default is enabled if available
sparse sparse checker
safe-stack SafeStack Stack Smash Protection. Depends on
clang/llvm >= 3.7 and requires coroutine backend ucontext.
cfi Enable Control-Flow Integrity for indirect function calls.
In case of a cfi violation, QEMU is terminated with SIGILL
Depends on lto and is incompatible with modules
Automatically enables Link-Time Optimization (lto)
cfi-debug In case of a cfi violation, a message containing the line that
triggered the error is written to stderr. After the error,
QEMU is still terminated with SIGILL
gnutls GNUTLS cryptography support
nettle nettle cryptography support
gcrypt libgcrypt cryptography support
@ -6971,7 +6989,7 @@ NINJA=$ninja $meson setup \
-Db_pie=$(if test "$pie" = yes; then echo true; else echo false; fi) \
${staticpic:+-Db_staticpic=$staticpic} \
-Db_coverage=$(if test "$gcov" = yes; then echo true; else echo false; fi) \
-Db_lto=$lto \
-Db_lto=$lto -Dcfi=$cfi -Dcfi_debug=$cfi_debug \
-Dmalloc=$malloc -Dmalloc_trim=$malloc_trim -Dsparse=$sparse \
-Dkvm=$kvm -Dhax=$hax -Dwhpx=$whpx -Dhvf=$hvf \
-Dxen=$xen -Dxen_pci_passthrough=$xen_pci_passthrough -Dtcg=$tcg \

View File

@ -773,6 +773,7 @@ elif get_option('vhost_user_blk_server').disabled() or not have_system
have_vhost_user_blk_server = false
endif
if get_option('fuse').disabled() and get_option('fuse_lseek').enabled()
error('Cannot enable fuse-lseek while fuse is disabled')
endif
@ -795,6 +796,46 @@ if not get_option('fuse_lseek').disabled()
endif
endif
if get_option('cfi')
cfi_flags=[]
# Check for dependency on LTO
if not get_option('b_lto')
error('Selected Control-Flow Integrity but LTO is disabled')
endif
if config_host.has_key('CONFIG_MODULES')
error('Selected Control-Flow Integrity is not compatible with modules')
endif
# Check for cfi flags. CFI requires LTO so we can't use
# get_supported_arguments, but need a more complex "compiles" which allows
# custom arguments
if cc.compiles('int main () { return 0; }', name: '-fsanitize=cfi-icall',
args: ['-flto', '-fsanitize=cfi-icall'] )
cfi_flags += '-fsanitize=cfi-icall'
else
error('-fsanitize=cfi-icall is not supported by the compiler')
endif
if cc.compiles('int main () { return 0; }',
name: '-fsanitize-cfi-icall-generalize-pointers',
args: ['-flto', '-fsanitize=cfi-icall',
'-fsanitize-cfi-icall-generalize-pointers'] )
cfi_flags += '-fsanitize-cfi-icall-generalize-pointers'
else
error('-fsanitize-cfi-icall-generalize-pointers is not supported by the compiler')
endif
if get_option('cfi_debug')
if cc.compiles('int main () { return 0; }',
name: '-fno-sanitize-trap=cfi-icall',
args: ['-flto', '-fsanitize=cfi-icall',
'-fno-sanitize-trap=cfi-icall'] )
cfi_flags += '-fno-sanitize-trap=cfi-icall'
else
error('-fno-sanitize-trap=cfi-icall is not supported by the compiler')
endif
endif
add_project_arguments(cfi_flags, native: false, language: ['c', 'cpp', 'objc'])
add_project_link_arguments(cfi_flags, native: false, language: ['c', 'cpp', 'objc'])
endif
#################
# config-host.h #
#################
@ -831,6 +872,7 @@ config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
config_host_data.set('CONFIG_STATX', has_statx)
config_host_data.set('CONFIG_FUSE', fuse.found())
config_host_data.set('CONFIG_FUSE_LSEEK', fuse_lseek.found())
config_host_data.set('CONFIG_CFI', get_option('cfi'))
config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0])
config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1])
@ -2195,6 +2237,8 @@ if targetos == 'windows'
summary_info += {'QGA MSI support': config_host.has_key('CONFIG_QGA_MSI')}
endif
summary_info += {'seccomp support': config_host.has_key('CONFIG_SECCOMP')}
summary_info += {'CFI support': get_option('cfi')}
summary_info += {'CFI debug support': get_option('cfi_debug')}
summary_info += {'coroutine backend': config_host['CONFIG_COROUTINE_BACKEND']}
summary_info += {'coroutine pool': config_host['CONFIG_COROUTINE_POOL'] == '1'}
summary_info += {'debug stack usage': config_host.has_key('CONFIG_DEBUG_STACK_USAGE')}

View File

@ -35,6 +35,10 @@ option('xen_pci_passthrough', type: 'feature', value: 'auto',
description: 'Xen PCI passthrough support')
option('tcg', type: 'feature', value: 'auto',
description: 'TCG support')
option('cfi', type: 'boolean', value: 'false',
description: 'Control-Flow Integrity (CFI)')
option('cfi_debug', type: 'boolean', value: 'false',
description: 'Verbose errors in case of CFI violation')
option('cocoa', type : 'feature', value : 'auto',
description: 'Cocoa user interface (macOS only)')