From 114a13af843cd5119958e453cdd35f046147e3bb Mon Sep 17 00:00:00 2001 From: Daniel Zatovic Date: Tue, 29 Nov 2022 18:25:13 +0100 Subject: [PATCH] Add support for meson build system. For now, let's keep support for both - autotools and meson. --- .gitlab/ci/compilation-various-disables.yml | 28 +- .gitlab/ci/debian.yml | 41 ++ Makefile.am | 13 + lib/crypto_backend/argon2/meson.build | 28 + lib/crypto_backend/meson.build | 38 ++ lib/meson.build | 116 ++++ man/meson.build | 261 ++++++++ man/meson_dist_convert.sh | 27 + meson.build | 687 ++++++++++++++++++++ meson_options.txt | 55 ++ po/meson.build | 7 + scripts/meson.build | 7 + src/meson.build | 77 +++ tests/fuzz/meson.build | 127 ++++ tests/meson.build | 464 +++++++++++++ tests/run-all-symbols | 6 +- tests/ssh-test-plugin | 9 + tests/systemd-test-plugin | 43 +- tokens/meson.build | 8 + tokens/ssh/meson.build | 39 ++ 20 files changed, 2067 insertions(+), 14 deletions(-) create mode 100644 lib/crypto_backend/argon2/meson.build create mode 100644 lib/crypto_backend/meson.build create mode 100644 lib/meson.build create mode 100644 man/meson.build create mode 100755 man/meson_dist_convert.sh create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 po/meson.build create mode 100644 scripts/meson.build create mode 100644 src/meson.build create mode 100644 tests/fuzz/meson.build create mode 100644 tests/meson.build create mode 100644 tokens/meson.build create mode 100644 tokens/ssh/meson.build diff --git a/.gitlab/ci/compilation-various-disables.yml b/.gitlab/ci/compilation-various-disables.yml index 1414f9e9..7bb608b2 100644 --- a/.gitlab/ci/compilation-various-disables.yml +++ b/.gitlab/ci/compilation-various-disables.yml @@ -4,18 +4,26 @@ test-gcc-disable-compiles: parallel: matrix: - DISABLE_FLAGS: [ - "--disable-keyring", - "--disable-external-tokens --disable-ssh-token", - "--disable-luks2-reencryption", - "--disable-cryptsetup --disable-veritysetup --disable-integritysetup", - "--disable-kernel_crypto", - "--disable-selinux", - "--disable-udev", - "--disable-internal-argon2", - "--disable-blkid" + "keyring", + "external-tokens ssh-token", + "luks2-reencryption", + "cryptsetup veritysetup integritysetup", + "kernel_crypto", + "udev", + "internal-argon2", + "blkid" ] + artifacts: + name: "meson-build-logs-$CI_COMMIT_REF_NAME" + paths: + - meson_builddir/meson-logs script: + - DEBIAN_FRONTEND=noninteractive apt-get -yq install meson ninja-build - export CFLAGS="-Wall -Werror" - - ./configure $DISABLE_FLAGS + - ./configure $(for i in $DISABLE_FLAGS; do echo "--disable-$i"; done) - make -j - make -j check-programs + - git checkout -f && git clean -xdf + - meson -v + - meson setup meson_builddir $(for i in $DISABLE_FLAGS; do echo "-D$i=false"; done) + - ninja -C meson_builddir diff --git a/.gitlab/ci/debian.yml b/.gitlab/ci/debian.yml index fad9d97b..de7c227b 100644 --- a/.gitlab/ci/debian.yml +++ b/.gitlab/ci/debian.yml @@ -54,3 +54,44 @@ test-main-commit-job-debian: - make -j - make -j -C tests check-programs - sudo -E make check + +# meson tests +test-mergerq-job-debian-meson: + extends: + - .debian-prep + tags: + - libvirt + - debian11 + stage: test + interruptible: true + variables: + RUN_SSH_PLUGIN_TEST: "1" + rules: + - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup" + when: never + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + script: + - sudo apt-get -y install -y -qq meson ninja-build + - meson setup build + - ninja -C build + - cd build && sudo -E meson test --verbose + +test-main-commit-job-debian-meson: + extends: + - .debian-prep + tags: + - libvirt + - debian11 + stage: test + interruptible: true + variables: + RUN_SSH_PLUGIN_TEST: "1" + rules: + - if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup" + when: never + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/ + script: + - sudo apt-get -y install -y -qq meson ninja-build + - meson setup build + - ninja -C build + - cd build && sudo -E meson test --verbose diff --git a/Makefile.am b/Makefile.am index fb7cb18f..a8028e9c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,17 @@ EXTRA_DIST = README.md COPYING.LGPL FAQ.md docs misc autogen.sh +EXTRA_DIST += meson_options.txt \ + meson.build \ + lib/crypto_backend/argon2/meson.build \ + lib/crypto_backend/meson.build \ + lib/meson.build \ + man/meson.build \ + po/meson.build \ + scripts/meson.build \ + src/meson.build \ + tests/meson.build \ + tokens/meson.build \ + tokens/ssh/meson.build + SUBDIRS = po tests tests/fuzz CLEANFILES = DISTCLEAN_TARGETS = diff --git a/lib/crypto_backend/argon2/meson.build b/lib/crypto_backend/argon2/meson.build new file mode 100644 index 00000000..bb685160 --- /dev/null +++ b/lib/crypto_backend/argon2/meson.build @@ -0,0 +1,28 @@ +libargon2_sources = files( + 'blake2/blake2b.c', + 'argon2.c', + 'core.c', + 'encoding.c', + 'thread.c', +) + +if use_internal_sse_argon2 + libargon2_sources += files( + 'opt.c', + ) +else + libargon2_sources += files( + 'ref.c', + ) +endif + +libargon2 = static_library('argon2', + libargon2_sources, + override_options : ['c_std=c89', 'optimization=3'], + build_by_default : false, + include_directories: include_directories( + 'blake2', + ), + dependencies : [ + threads, + ]) diff --git a/lib/crypto_backend/meson.build b/lib/crypto_backend/meson.build new file mode 100644 index 00000000..48655a41 --- /dev/null +++ b/lib/crypto_backend/meson.build @@ -0,0 +1,38 @@ +subdir('argon2') + +libcrypto_backend_dependencies = [ + crypto_backend_library, + clock_gettime, +] +libcrypto_backend_link_with = [] + +libcrypto_backend_sources = files( + 'argon2_generic.c', + 'base64.c', + 'cipher_check.c', + 'cipher_generic.c', + 'crc32.c', + 'crypto_cipher_kernel.c', + 'crypto_storage.c', + 'pbkdf_check.c', + 'utf8.c', +) + +crypto_backend = get_option('crypto-backend') +libcrypto_backend_sources += files('crypto_@0@.c'.format(crypto_backend)) + +if use_internal_pbkdf2 + libcrypto_backend_sources += files('pbkdf2_generic.c') +endif + +if get_option('argon-implementation') == 'internal' + libcrypto_backend_link_with += libargon2 +elif get_option('argon-implementation') == 'libargon2' + libcrypto_backend_dependencies += libargon2_external +endif + +libcrypto_backend = static_library('crypto_backend', + libcrypto_backend_sources, + include_directories: includes_lib, + dependencies: libcrypto_backend_dependencies, + link_with: libcrypto_backend_link_with) diff --git a/lib/meson.build b/lib/meson.build new file mode 100644 index 00000000..c682150d --- /dev/null +++ b/lib/meson.build @@ -0,0 +1,116 @@ +subdir('crypto_backend') +lib_build_dir = meson.current_build_dir() + +libutils_io = static_library('utils_io', + files( + 'utils_io.c', + )) + +libcryptsetup_sym_path = join_paths(meson.current_source_dir(), 'libcryptsetup.sym') +libcryptsetup_version = '12.9.0' + +libcryptsetup_deps = [ + uuid, + devmapper, + libargon2_external, + jsonc, + blkid, + dl, +] + +libcryptsetup_sources = files( + 'bitlk/bitlk.c', + 'fvault2/fvault2.c', + 'integrity/integrity.c', + 'loopaes/loopaes.c', + 'luks1/af.c', + 'luks1/keyencryption.c', + 'luks1/keymanage.c', + 'luks2/luks2_digest.c', + 'luks2/luks2_digest_pbkdf2.c', + 'luks2/luks2_disk_metadata.c', + 'luks2/luks2_json_format.c', + 'luks2/luks2_json_metadata.c', + 'luks2/luks2_keyslot.c', + 'luks2/luks2_keyslot_luks2.c', + 'luks2/luks2_keyslot_reenc.c', + 'luks2/luks2_luks1_convert.c', + 'luks2/luks2_reencrypt.c', + 'luks2/luks2_reencrypt_digest.c', + 'luks2/luks2_segment.c', + 'luks2/luks2_token.c', + 'luks2/luks2_token_keyring.c', + 'tcrypt/tcrypt.c', + 'verity/rs_decode_char.c', + 'verity/rs_encode_char.c', + 'verity/verity.c', + 'verity/verity_fec.c', + 'verity/verity_hash.c', + 'crypt_plain.c', + 'keyslot_context.c', + 'libdevmapper.c', + 'random.c', + 'setup.c', + 'utils.c', + 'utils_benchmark.c', + 'utils_blkid.c', + 'utils_crypt.c', + 'utils_device.c', + 'utils_device_locking.c', + 'utils_devpath.c', + 'utils_keyring.c', + 'utils_loop.c', + 'utils_pbkdf.c', + 'utils_safe_memory.c', + 'utils_storage_wrappers.c', + 'utils_wipe.c', + 'volumekey.c', +) + +if enable_static + libcryptsetup = static_library('cryptsetup', + libcryptsetup_sources, + dependencies: libcryptsetup_deps, + link_with: [ + libcrypto_backend, + libutils_io, + ], + install: true) +else + libcryptsetup = library('cryptsetup', + libcryptsetup_sources, + dependencies: libcryptsetup_deps, + version: libcryptsetup_version, + link_args: [ + '-Wl,--version-script=' + + libcryptsetup_sym_path, + ], + link_with: [ + libcrypto_backend, + libutils_io, + ], + install: true) +endif + +lib_tools_files = files( + 'utils_blkid.c', + 'utils_crypt.c', + 'utils_io.c', + 'utils_loop.c', +) +lib_utils_crypt_files = files( + 'utils_crypt.c', +) +lib_ssh_token_files = files( + 'utils_io.c', + 'utils_loop.c', +) + +install_headers( + 'libcryptsetup.h', +) +pkgconfig.generate( + libcryptsetup, + name: 'libcryptsetup', + version: PACKAGE_VERSION, + description: 'cryptsetup library') diff --git a/man/meson.build b/man/meson.build new file mode 100644 index 00000000..c5ec07d8 --- /dev/null +++ b/man/meson.build @@ -0,0 +1,261 @@ +fs = import('fs') + +adocfiles_common = [ + 'common_options.adoc', + 'common_footer.adoc', +] + +manpage_tuples_to_build = [] +manpage_tuples_all = [] + +# tuple with adoc file and generated aliases +cryptsetup_manpages = [ + [ + 'cryptsetup.8.adoc', + [], + ], + [ + 'cryptsetup-open.8.adoc', + [ + 'cryptsetup-create.8', + 'cryptsetup-plainOpen.8', + 'cryptsetup-luksOpen.8', + 'cryptsetup-loopaesOpen.8', + 'cryptsetup-tcryptOpen.8', + 'cryptsetup-bitlkOpen.8', + ], + ], + [ + 'cryptsetup-close.8.adoc', + [], + ], + [ + 'cryptsetup-reencrypt.8.adoc', + [], + ], + [ + 'cryptsetup-status.8.adoc', + [], + ], + [ + 'cryptsetup-resize.8.adoc', + [], + ], + [ + 'cryptsetup-refresh.8.adoc', + [], + ], + [ + 'cryptsetup-luksFormat.8.adoc', + [], + ], + [ + 'cryptsetup-luksSuspend.8.adoc', + [], + ], + [ + 'cryptsetup-luksResume.8.adoc', + [], + ], + [ + 'cryptsetup-luksAddKey.8.adoc', + [], + ], + [ + 'cryptsetup-luksRemoveKey.8.adoc', + [], + ], + [ + 'cryptsetup-luksConvertKey.8.adoc', + [], + ], + [ + 'cryptsetup-luksKillSlot.8.adoc', + [], + ], + [ + 'cryptsetup-luksChangeKey.8.adoc', + [], + ], + [ + 'cryptsetup-erase.8.adoc', + [ + 'cryptsetup-luksErase.8', + ], + ], + [ + 'cryptsetup-luksUUID.8.adoc', + [], + ], + [ + 'cryptsetup-isLuks.8.adoc', + [], + ], + [ + 'cryptsetup-luksDump.8.adoc', + [], + ], + [ + 'cryptsetup-luksHeaderBackup.8.adoc', + [], + ], + [ + 'cryptsetup-luksHeaderRestore.8.adoc', + [], + ], + [ + 'cryptsetup-token.8.adoc', + [], + ], + [ + 'cryptsetup-convert.8.adoc', + [], + ], + [ + 'cryptsetup-config.8.adoc', + [], + ], + [ + 'cryptsetup-tcryptDump.8.adoc', + [], + ], + [ + 'cryptsetup-bitlkDump.8.adoc', + [], + ], + [ + 'cryptsetup-fvault2Dump.8.adoc', + [], + ], + [ + 'cryptsetup-repair.8.adoc', + [], + ], + [ + 'cryptsetup-benchmark.8.adoc', + [], + ], +] + +veritysetup_manpages = [ + [ + 'veritysetup.8.adoc', + [], + ], +] +integritysetup_manpages = [ + [ + 'integritysetup.8.adoc', + [], + ], +] +sshplugin_manpages = [ + [ + 'cryptsetup-ssh.8.adoc', + [], + ], +] + +if get_option('cryptsetup') + manpage_tuples_to_build += cryptsetup_manpages +endif +manpage_tuples_all += cryptsetup_manpages +if get_option('veritysetup') + manpage_tuples_to_build += veritysetup_manpages +endif +manpage_tuples_all += veritysetup_manpages +if get_option('integritysetup') + manpage_tuples_to_build += integritysetup_manpages +endif +manpage_tuples_all += integritysetup_manpages +if get_option('ssh-token') + manpage_tuples_to_build += sshplugin_manpages +endif +manpage_tuples_all += sshplugin_manpages + +adocfiles_all = [] +foreach tuple : manpage_tuples_all + adocfiles_all += tuple[0] +endforeach + +if meson.version().version_compare('>=0.55') + meson.add_dist_script(find_program('meson_dist_convert.sh'), + asciidoc, meson.project_version(), adocfiles_all) +else + meson.add_dist_script('meson_dist_convert.sh', + asciidoc.path(), meson.project_version(), adocfiles_all) +endif + +prebuilt_manpages_exist = true +foreach manpage_tuple : manpage_tuples_to_build + adocfile = manpage_tuple[0] + aliases = manpage_tuple[1] + manfile = fs.replace_suffix(adocfile, '') + + prebuilt_manpages_exist = prebuilt_manpages_exist and fs.exists(manfile) + + foreach alias : aliases + prebuilt_manpages_exist = prebuilt_manpages_exist and fs.exists(alias) + endforeach +endforeach + +built_manpages = [] + +if use_asciidoc + foreach manpage_tuple : manpage_tuples_to_build + adocfile = manpage_tuple[0] + aliases = manpage_tuple[1] + + mandir = join_paths(get_option('prefix'), get_option('mandir'), 'man8') + manfile = fs.replace_suffix(adocfile, '') + + built_manpages += custom_target(manfile, + command: [ + asciidoc, + '-b', 'manpage', + '--failure-level', 'ERROR', + '-a', 'release-version=@0@'.format( + meson.project_version(), + ), + '-o', '@BASENAME@', + '@INPUT@', + '--destination-dir=@0@'.format( + meson.current_build_dir(), + ), + '--base-dir=@SOURCE_ROOT@', + ], + input: adocfile, + depend_files: adocfiles_common, + install: true, + install_dir: mandir, + output: [ + manfile, + ] + aliases, + ) + endforeach +else + # use_asciidoc == false + if prebuilt_manpages_exist + message('Using prebuilt manpages.') + foreach manpage_tuple : manpage_tuples_to_build + adocfile = manpage_tuple[0] + aliases = manpage_tuple[1] + manfile = fs.replace_suffix(adocfile, '') + + install_man(manfile) + foreach alias : aliases + install_man(alias) + endforeach + endforeach + else + warning('Neither asciidoctor nor prebuilt manual pages found. Skipping manpage installation') + endif +endif + +man = custom_target( + 'man', + output: 'man', + depends: built_manpages, + command: [ + nop_command, + ]) diff --git a/man/meson_dist_convert.sh b/man/meson_dist_convert.sh new file mode 100755 index 00000000..ebaceb69 --- /dev/null +++ b/man/meson_dist_convert.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# generates manpages from AsciiDoc files when building dist tarball +# run asciidoctor in parallel on `nproc` cores + +set -e + +[ -z "$MESON_DIST_ROOT" ] && echo "This script is meant to be run only from meson while generating dist tarball." && exit 1 + +if [ $# -lt 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +ASCIIDOCTOR="$1" +RELEASE_VERSION="$2" +shift 2 + +cd $MESON_DIST_ROOT/man +i=1 +N=$(nproc) +for adocfile in "$@" +do + $ASCIIDOCTOR -b manpage --failure-level ERROR -a release-version=$RELEASE_VERSION --base-dir=$MESON_DIST_ROOT $adocfile & + if (( $i % $N == 0 )); then wait; fi + i=$((i+1)) +done diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..bc9a9785 --- /dev/null +++ b/meson.build @@ -0,0 +1,687 @@ +project('cryptsetup', + 'c', + meson_version: '>=0.53', + version: '2.6.1-rc0') + +includes_root = include_directories('.') +includes_lib = include_directories('lib') +includes_tools = [ + includes_root, + includes_lib, +] + +warning('meson build system support for cryptsetup is considered experimental at the moment ') + +pkgconfig = import('pkgconfig') +cc = meson.get_compiler('c') +nop_command = find_program('echo') +conf = configuration_data() + +PACKAGE_VERSION = meson.project_version().split('-')[0] +conf.set_quoted('PACKAGE_VERSION', PACKAGE_VERSION) +conf.set_quoted('PACKAGE_NAME', meson.project_name()) +conf.set_quoted('PACKAGE', meson.project_name()) +conf.set('_GNU_SOURCE', true) + +default_string_options = [ + 'default-loopaes-cipher', + 'default-luks1-cipher', + 'default-luks1-hash', + 'default-luks1-mode', + 'default-luks2-external-tokens-path', + 'default-luks2-keyslot-cipher', + 'default-luks2-lock-path', + 'default-luks2-pbkdf', + 'default-plain-cipher', + 'default-plain-hash', + 'default-plain-mode', + 'default-verity-hash', +] + +default_int_options = [ + 'default-integrity-keyfile-size-maxkb', + 'default-keyfile-size-maxkb', + 'default-loopaes-keybits', + 'default-luks1-iter-time', + 'default-luks1-keybits', + 'default-luks2-iter-time', + 'default-luks2-keyslot-keybits', + 'default-luks2-lock-dir-perms', + 'default-luks2-memory-kb', + 'default-luks2-parallel-threads', + 'default-passphrase-size-max', + 'default-plain-keybits', + 'default-verity-data-block', + 'default-verity-fec-roots', + 'default-verity-hash-block', + 'default-verity-salt-size', +] + +foreach default_option : (default_string_options) + conf.set_quoted(default_option.underscorify().to_upper(), get_option(default_option)) +endforeach + +foreach default_option : (default_int_options) + conf.set(default_option.underscorify().to_upper(), get_option(default_option)) +endforeach + +sanitizer = get_option('b_sanitize') +sanitizer_enabled = sanitizer != '' and sanitizer != 'none' + +enable_static = get_option('enable-static') +if get_option('static-cryptsetup') + if not enable_static + warning('Requested static cryptsetup build, enabling static library.') + enable_static = true + endif + + conf.set10('STATIC_TOOLS', true) +endif +link_args = [] +if enable_static == true + if not sanitizer_enabled + link_args += '--static' + else + warning('Turning off statically linked binaries as they are not compatible with sanitizer build. Will keep prefering static external dependencies.') + endif +endif + +required_headers = [ + 'byteswap.h', + 'ctype.h', + 'endian.h', + 'fcntl.h', + 'inttypes.h', + 'locale.h', + 'malloc.h', + 'stdint.h', + 'sys/ioctl.h', + 'sys/mman.h', + 'sys/statvfs.h', + 'sys/sysmacros.h', + 'uchar.h', + 'unistd.h', +] +foreach header : required_headers + conf.set10('HAVE_' + header.underscorify().to_upper(), cc.has_header(header)) +endforeach + +fcntl_header = conf.get('HAVE_FCNTL_H') == true ? 'fcntl.h' : 'stdio.h' +if cc.has_header_symbol(fcntl_header, 'O_CLOEXEC') + conf.set10('HAVE_DECL_O_CLOEXEC', true) +else + message('O_CLOEXEC not provided, setting to 0') + conf.set10('O_CLOEXEC', false, + description: 'Defined to 0 if not provided') +endif + +# ========================================================================== +# AsciiDoc manual pages + +asciidoc = find_program('asciidoctor', required: false) +opt_asciidoc = get_option('asciidoc') +if opt_asciidoc.enabled() and not asciidoc.found() + error('Building man pages requires asciidoctor installed.') +endif +use_asciidoc = asciidoc.found() and not opt_asciidoc.disabled() + +# ========================================================================== +# keyring + +if get_option('keyring') + assert(cc.has_header('linux/keyctl.h'), + 'You need Linux kernel headers with kernel keyring service compiled.') + assert(cc.has_header_symbol('syscall.h', '__NR_add_key',), + 'The kernel is missing add_key syscall.') + assert(cc.has_header_symbol('syscall.h', '__NR_keyctl'), + 'The kernel is missing keyctl syscall.') + assert(cc.has_header_symbol('syscall.h', '__NR_request_key',), + 'The kernel is missing request_key syscall.') + conf.set10('KERNEL_KEYRING', true, + description: 'Enable kernel keyring service support') +endif + +if build_machine.endian() == 'big' + conf.set10('WORDS_BIGENDIAN', true) +endif + +# ========================================================================== + +uuid = dependency('uuid', + static: enable_static) +assert(cc.has_function('uuid_clear', + prefix: '#include ', dependencies: uuid), + 'You need the uuid library.') + +# ========================================================================== + +# AC_SEARCH_LIBS([clock_gettime],[rt posix4]) + +clock_gettime = [] +if not cc.has_function('clock_gettime', + prefix: '#include ') + clock_gettime = cc.find_library('rt') + + if not cc.has_function('clock_gettime', + prefix: '#include ', dependencies: clock_gettime) + clock_gettime = cc.find_library('posix4') + + if not cc.has_function('clock_gettime', + prefix: '#include ', dependencies: clock_gettime) + error('clock_gettime not found') + endif + endif +endif + +foreach function : [ + 'posix_memalign', + 'posix_fallocate', + 'explicit_bzero', +] + conf.set10('HAVE_' + function.underscorify().to_upper(), cc.has_function(function)) +endforeach + +# no need to enable large file support, as it is on be default in meson +# https://github.com/mesonbuild/meson/commit/853634a48da025c59eef70161dba0d150833f60d + +# ========================================================================== +# LUKS2 external tokens + +# dl is also required by all-symbols-test +dl = [] +if not cc.has_function('dlsym', + prefix: '#include ') + dl = cc.find_library('dl') + + if not cc.has_function('dlsym', + prefix: '#include ', dependencies: dl) + error('dlsym not found') + endif +endif +if cc.has_function('dlvsym', + dependencies: dl) + conf.set10('HAVE_DLVSYM', true) +endif + +if get_option('external-tokens') + assert(conf.has('HAVE_DLVSYM') and conf.get('HAVE_DLVSYM') == true, + 'dl library has no dlvsym function') + conf.set10('USE_EXTERNAL_TOKENS', true, + description: 'Use external tokens') +endif + +# SSH external tokens +if not get_option('external-tokens') and get_option('ssh-token') + error('Requested LUKS2 ssh-token build, but external tokens are disabled.') +endif + +if get_option('luks2-reencryption') + conf.set10('USE_LUKS2_REENCRYPTION', true, + description: 'Use LUKS2 online reencryption extension') +endif + +# ========================================================================== + +popt = cc.find_library('popt', + static: enable_static) +assert(cc.has_function('poptConfigFileToString', + dependencies: popt), + 'You need popt 1.7 or newer to compile.') + +# ========================================================================== +# FIPS extensions + +if get_option('fips') + if enable_static + error('Static build is not compatible with FIPS.') + endif + + conf.set10('ENABLE_FIPS', true, + description: 'Enable FIPS mode restrictions') +endif + +# ========================================================================== +# pwquality library (cryptsetup CLI only) + +pwquality = [] +if get_option('pwquality') + pwquality = dependency('pwquality', + version: '>= 1.0.0', + static: enable_static) + conf.set10('ENABLE_PWQUALITY', true) +endif + +# ========================================================================== +# fuzzers, it requires own static library compilation later + +if get_option('fuzz-targets') + assert(sanitizer_enabled, + 'Fuzz targets are only supported with sanitizer enabled. Please set -Db_sanitize') + add_languages('cpp') + + if get_option('fuzzing-engine') == '' + fuzzing_engine = meson.get_compiler('cpp').find_library('Fuzzer', required: false) + if fuzzing_engine.found() + add_project_arguments('-fsanitize-coverage=trace-pc-guard,trace-cmp', + language: [ 'c', 'cpp' ]) + elif cc.has_argument( '-fsanitize=fuzzer-no-link',) and cc.has_argument( '-fsanitize=fuzzer',) + message('Using -fsanitize=fuzzer engine') + fuzzing_engine = declare_dependency(link_args: ['-fsanitize=fuzzer']) + add_project_arguments('-fsanitize=fuzzer-no-link', + language: [ 'c', 'cpp' ]) + else + error('Looks like neither libFuzzer nor -fsanitize=fuzzer-no-link is supported') + endif + else + fuzzing_engine = declare_dependency(link_args: get_option('fuzzing-engine').split()) + endif + + protobuf = dependency('protobuf', + required: false) + protoc = find_program('protoc', + required: false) + if not protoc.found() + protoc = find_program('tests/fuzz/build/static_lib_deps/bin/protoc', + required: false) + endif + if not protoc.found() or not protobuf.found() + error('protoc tool and/or protobuf pkg-config dependency not found') + endif + + libprotobuf_mutator = dependency('libprotobuf-mutator', + required: false) + if not libprotobuf_mutator.found() + error('libprotobuf-mutator not found') + endif + + protoc_generator = generator(protoc, + output: [ + '@BASENAME@.pb.cc', + '@BASENAME@.pb.h', + ], + arguments: [ + '--proto_path=@CURRENT_SOURCE_DIR@', + '--cpp_out=@BUILD_DIR@', + '@INPUT@', + ]) +endif + +# ========================================================================== +# passwdqc library (cryptsetup CLI only) + +passwdqc_config = '' +use_passwdqc = false +if get_option('passwdqc') == 'true' + use_passwdqc = true +elif get_option('passwdqc') == 'false' + use_passwdqc = false +elif get_option('passwdqc').startswith('/') + use_passwdqc = true + passwdqc_config = get_option('passwdqc') +else + error('Unrecognized passwdqc parameter "@0@" (supported options are true, false or absolute path).' + .format(get_option('passwdqc'))) +endif + +passwdqc = [] +conf.set_quoted('PASSWDQC_CONFIG_FILE', passwdqc_config, + description: 'passwdqc library config file') +if use_passwdqc + conf.set10('ENABLE_PASSWDQC', true, + description: 'Enable password quality checking using passwdqc library') + #passwdqc = dependency('passwdqc', required : false) + passwdqc = cc.find_library('passwdqc', + required: false, + static: enable_static) + assert(cc.has_function('passwdqc_check', + prefix: '#include ', dependencies: passwdqc), + 'failed to find passwdqc_check from the passwdqc library') + + assert(cc.has_function('passwdqc_params_free', + prefix: '#include ', dependencies: passwdqc), + 'failed to find passwdqc_params_free from the passwdqc library') + + conf.set10('HAVE_PASSWDQC_PARAMS_FREE', cc.has_function('passwdqc_params_free', + prefix: '#include ', dependencies: passwdqc)) +endif + +if use_passwdqc and get_option('pwquality') + error('pwquality and passwdqc are mutually incompatible.') +endif + +# ========================================================================== +# libdevmapper + +devmapper = dependency('devmapper', + version: '>= 1.02.03', + required: false, + static: enable_static) +if not devmapper.found() + message('devmapper not found using pkgconf') + devmapper = cc.find_library('devmapper', + static: enable_static) + assert(cc.has_function('dm_task_set_name', + prefix: '#include ', dependencies: devmapper), + 'You need the device-mapper library.') + + assert(cc.has_function('dm_task_set_message', + prefix: '#include ', dependencies: devmapper), + 'The device-mapper library on your system is too old.') +endif + +foreach function : [ + 'dm_device_get_name', + 'dm_device_has_holders', + 'dm_device_has_mounted_fs', + 'dm_task_deferred_remove', + 'dm_task_retry_remove', + 'dm_task_secure_data', +] + has_function = cc.has_function(function, + prefix: '#include ', dependencies: devmapper) + conf.set10('HAVE_DECL_' + function.underscorify().to_upper(), has_function) +endforeach + +foreach symbol : [ + 'DM_DEVICE_GET_TARGET_VERSION', + 'DM_UDEV_DISABLE_DISK_RULES_FLAG', +] + has_symbol = cc.has_header_symbol('libdevmapper.h', symbol, + dependencies: devmapper) + conf.set10('HAVE_DECL_' + symbol.underscorify().to_upper(), has_symbol) +endforeach + +if cc.has_header_symbol('libdevmapper.h', 'DM_UDEV_DISABLE_DISK_RULES_FLAG', + dependencies: devmapper) + conf.set10('USE_UDEV', true, + description: 'Try to use udev synchronisation?') +else + warning('The device-mapper library on your system has no udev support, udev support disabled.') +endif + +# ========================================================================== +# Check for JSON-C used in LUKS2 + +jsonc = dependency('json-c', + static: enable_static) +foreach function : [ + 'json_object_object_add_ex', + 'json_object_deep_copy', +] + has_function = cc.has_function(function, + prefix: '#include ', dependencies: jsonc) + conf.set10('HAVE_DECL_' + function.underscorify().to_upper(), has_function) +endforeach + +# ========================================================================== +# Check for libssh and argp for SSH plugin + +if get_option('ssh-token') + argp = [] + + if not cc.has_function('argp_parse', prefix: '#include ', dependencies: argp) + argp = cc.find_library('argp', + static: enable_static) + endif + + libssh = dependency('libssh') + conf.set10('HAVE_DECL_SSH_SESSION_IS_KNOWN_SERVER', + cc.has_function('ssh_session_is_known_server', + prefix: '#include ', dependencies: libssh)) +endif + +# ========================================================================== +# Crypto backend configuration. + +if get_option('kernel_crypto') + assert(cc.has_header('linux/if_alg.h'), + 'You need Linux kernel headers with userspace crypto interface. (Or use --disable-kernel_crypto.') + conf.set10('ENABLE_AF_ALG', true, + description: 'Enable using of kernel userspace crypto') +endif + +crypto_backend_library = [] +use_internal_pbkdf2 = false + +if get_option('crypto-backend') == 'gcrypt' + req_version = '1.1.42' + if get_option('fips') + req_version = '1.4.5' + endif + + if get_option('gcrypt-pbkdf2').auto() + # Check if we can use gcrypt PBKDF2 (1.6.0 supports empty password) + gcrypt_with_empty_password = dependency('libgcrypt', + version: '>=1.6.1', + required: false, + static: enable_static) + if gcrypt_with_empty_password.found() + req_version = '1.6.1' + use_internal_pbkdf2 = false + else + use_internal_pbkdf2 = true + endif + else + use_internal_pbkdf2 = get_option('gcrypt-pbkdf2').disabled() + endif + + if use_internal_pbkdf2 and get_option('fips') + error('Using internal cryptsetup PBKDF2 is not compatible with FIPS.') + endif + + crypto_backend_library = dependency('libgcrypt', + version: '>=@0@'.format(req_version), + static: enable_static) + conf.set10('HAVE_DECL_GCRY_CIPHER_MODE_XTS', + cc.has_header_symbol('gcrypt.h', 'GCRY_CIPHER_MODE_XTS', + dependencies: crypto_backend_library)) + conf.set_quoted('GCRYPT_REQ_VERSION', req_version, + description: 'Requested gcrypt version') +elif get_option('crypto-backend') == 'openssl' + use_internal_pbkdf2 = false + crypto_backend_library = dependency('openssl', + version: '>=0.9.8', + static: enable_static) +elif get_option('crypto-backend') == 'nss' + if get_option('fips') + error('nss crypto backend is not supported with FIPS enabled') + endif + if enable_static + error('Static build of cryptsetup is not supported with NSS.') + endif + + warning('NSS backend does NOT provide backward compatibility (missing ripemd160 hash).') + use_internal_pbkdf2 = true + + crypto_backend_library = dependency('nss', + static: enable_static) + conf.set10('HAVE_DECL_NSS_GETVERSION', + cc.has_header_symbol('nss.h', 'NSS_GetVersion', + dependencies: crypto_backend_library)) +elif get_option('crypto-backend') == 'kernel' + if get_option('fips') + error('kernel crypto backend is not supported with FIPS enabled') + endif + use_internal_pbkdf2 = true + assert(cc.has_header('linux/if_alg.h'), + 'You need Linux kernel headers with userspace crypto interface.') +elif get_option('crypto-backend') == 'nettle' + if get_option('fips') + error('nettle crypto backend is not supported with FIPS enabled') + endif + assert(cc.has_header('nettle/sha.h'), + 'You need Nettle cryptographic library.') + conf.set10('HAVE_NETTLE_VERSION_H', cc.has_header('nettle/version.h')) + + crypto_backend_library = dependency('nettle', + static: enable_static) + use_internal_pbkdf2 = false + assert(cc.has_function('nettle_pbkdf2_hmac_sha256', + dependencies: crypto_backend_library), + 'You need Nettle library version 2.6 or more recent.') +endif +conf.set10('USE_INTERNAL_PBKDF2', use_internal_pbkdf2) + +libargon2_external = [] +threads = [] +use_internal_sse_argon2 = false +if get_option('argon-implementation') == 'internal' + warning('Argon2 bundled (slow) reference implementation will be used, please consider using system library with -Dargon-implementation=libargon2') + + if get_option('internal-sse-argon2') + use_internal_sse_argon2 = cc.links( + '''#include + __m128i testfunc(__m128i *a, __m128i *b) { + return _mm_xor_si128(_mm_loadu_si128(a), _mm_loadu_si128(b)); + } + int main(int argc, char **argv) { return 0; }''', + name: 'Argon2 SSE optimization can be used') + + if not use_internal_sse_argon2 + warning('Argon2 SSE optimization cannot be used, disabling.') + endif + endif + conf.set10('USE_INTERNAL_ARGON2', true, + description: 'Use internal Argon2.') + + threads = dependency('threads') +elif get_option('argon-implementation') == 'libargon2' + libargon2_external = dependency('libargon2', + static: enable_static) + assert(cc.has_header('argon2.h', + dependencies: libargon2_external), + 'You need libargon2 development library installed.') + assert(cc.has_header_symbol( + 'argon2.h', + 'Argon2_id', + dependencies: libargon2_external), + 'You need more recent Argon2 library with support for Argon2id.') + conf.set10('USE_INTERNAL_ARGON2', false, + description: 'Use internal Argon2.') + conf.set10('HAVE_ARGON2_H', true) +endif + +# ========================================================================== +# Link with blkid to check for other device types + +blkid = [] +if get_option('blkid') + blkid = dependency('blkid', + static: enable_static) + assert(cc.has_header('blkid/blkid.h', + dependencies: blkid), + 'You need blkid development library installed.') + + conf.set10('HAVE_BLKID', true, + description: 'Define to 1 to use blkid for detection of disk signatures.') + conf.set10('HAVE_BLKID_WIPE', + cc.has_function('blkid_do_wipe', + prefix: '#include ', dependencies: blkid), + description: 'Define to 1 to use blkid_do_wipe.') + conf.set10('HAVE_BLKID_STEP_BACK', + cc.has_function('blkid_probe_step_back', + prefix: '#include ', dependencies: blkid), + description: 'Define to 1 to use blkid_probe_step_back.') + + foreach header : [ + 'blkid_reset_probe', + 'blkid_probe_set_device', + 'blkid_probe_filter_superblocks_type', + 'blkid_do_safeprobe', + 'blkid_do_probe', + 'blkid_probe_lookup_value', + ] + assert(cc.has_function(header, + prefix: '#include ', dependencies: blkid), + 'Can not compile with blkid support, disable it by -Dblkid=false') + endforeach +endif + +# ========================================================================== +# Check compiler support for symver function attribute + +if cc.links( + '''void _test_sym(void); + + __attribute__((__symver__("sym@VERSION_4.2"))) void _test_sym(void) {} + int main(int argc, char **argv) { return 0; }''', + args: ['-O0', '-Werror' ], + name: 'for symver attribute support') + conf.set10('HAVE_ATTRIBUTE_SYMVER', true, + description: 'Define to 1 to use __attribute__((symver))') +endif + +# ========================================================================== + +if get_option('dev-random') + conf.set_quoted('DEFAULT_RNG', '/dev/random') +else + conf.set_quoted('DEFAULT_RNG', '/dev/urandom') +endif + +tmpfilesdir = get_option('tmpfilesdir') +if tmpfilesdir == '' + systemd = dependency('systemd', + method: 'pkg-config', + required: false) + if systemd.found() + tmpfilesdir = systemd.get_variable(pkgconfig: 'tmpfilesdir', default_value: '') + endif +endif + +if tmpfilesdir != '' + assert(tmpfilesdir.startswith('/',), + 'tmpfilesdir has to be an absolute path') +endif + +# ========================================================================== + +if get_option('luks_adjust_xts_keysize') + conf.set10('ENABLE_LUKS_ADJUST_XTS_KEYSIZE', true, + description: 'XTS mode - double default LUKS keysize if needed') +endif + +assert(get_option('default-luks2-lock-path').startswith('/'), + 'default-luks2-lock-path has to be an absolute path') + +luks2_external_tokens_path = get_option('default-luks2-external-tokens-path') +if luks2_external_tokens_path == 'LIBDIR/cryptsetup' + luks2_external_tokens_path = join_paths(get_option('prefix'), get_option('libdir'), 'cryptsetup') +endif +assert(luks2_external_tokens_path.startswith('/'), + 'default-luks2-external-tokens-path has to be an absolute path') +conf.set_quoted('EXTERNAL_LUKS2_TOKENS_PATH', luks2_external_tokens_path, + description: 'path to directory with LUKSv2 external token handlers (plugins)') + +if get_option('default-luks-format') == 'LUKS1' + conf.set('DEFAULT_LUKS_FORMAT', 'CRYPT_LUKS1') +elif get_option('default-luks-format') == 'LUKS2' + conf.set('DEFAULT_LUKS_FORMAT', 'CRYPT_LUKS2') +else + error('Unknown default LUKS format. Use LUKS1 or LUKS2 only.') +endif + +# ========================================================================== + +if get_option('nls') + conf.set10('ENABLE_NLS', true) + assert(find_program('gettext').found(), + 'You need gettext binary to build translations.') +endif + +# ========================================================================== + +configure_file( + output: 'config.h', + configuration: conf, +) +add_project_arguments('-include', 'config.h', + language: 'c') + +subdir('lib') +subdir('man') +subdir('po') +subdir('src') +subdir('scripts') +subdir('tokens') +subdir('tests') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..02b3610e --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,55 @@ +option('argon-implementation', type : 'combo', choices : ['none', 'internal', 'libargon2'], description : 'which implementation of Argon2 PBKDF shall be used (cryptsetup internal, external libargon2 (PHC) or disable Argon2 support)', value : 'internal') +option('asciidoc', type : 'feature', description : 'generate man pages from asciidoc', value : 'enabled') +option('blkid', type : 'boolean', description : 'use of blkid for device signature detection and wiping', value : true) +option('crypto-backend', type : 'combo', choices : ['gcrypt', 'openssl', 'nss', 'kernel', 'nettle'], description : 'crypto backend', value : 'openssl') +option('cryptsetup', type : 'boolean', description : 'cryptsetup support', value : true) +option('default-integrity-keyfile-size-maxkb', type : 'integer', description : 'maximum integritysetup keyfile size (in KiB)', value : 4) +option('default-keyfile-size-maxkb', type : 'integer', description : 'maximum keyfile size (in KiB)', value : 8192) +option('default-loopaes-cipher', type : 'string', description : 'cipher for loop-AES mode', value : 'aes') +option('default-loopaes-keybits', type : 'integer', description : 'key length in bits for loop-AES mode', value : 256) +option('default-luks1-cipher', type : 'string', description : 'cipher for LUKS1', value : 'aes') +option('default-luks1-hash', type : 'string', description : 'hash function for LUKS1 header', value : 'sha256') +option('default-luks1-iter-time', type : 'integer', description : 'PBKDF2 iteration time for LUKS1 (in ms)', value : 2000) +option('default-luks1-keybits', type : 'integer', description : 'key length in bits for LUKS1', value : 256) +option('default-luks1-mode', type : 'string', description : 'cipher mode for LUKS1', value : 'xts-plain64') +option('default-luks2-external-tokens-path', type : 'string', description : 'path to directory with LUKSv2 external token handlers (plugins)', value : 'LIBDIR/cryptsetup') +option('default-luks2-iter-time', type : 'integer', description : 'Argon2 PBKDF iteration time for LUKS2 (in ms)', value : 2000) +option('default-luks2-keyslot-cipher', type : 'string', description : 'fallback cipher for LUKS2 keyslot (if data encryption is incompatible)', value : 'aes-xts-plain64') +option('default-luks2-keyslot-keybits', type : 'integer', description : 'fallback key size for LUKS2 keyslot (if data encryption is incompatible)', value : 512) +option('default-luks2-lock-dir-perms', type : 'integer', description : 'default luks2 locking directory permissions', value : '0700') +option('default-luks2-lock-path', type : 'string', description : 'path to directory for LUKSv2 locks', value : '/run/cryptsetup') +option('default-luks2-memory-kb', type : 'integer', description : 'Argon2 PBKDF memory cost for LUKS2 (in kB)', value : 1048576) +option('default-luks2-parallel-threads', type : 'integer', description : 'Argon2 PBKDF max parallel cost for LUKS2 (if CPUs available)', value : 4) +option('default-luks2-pbkdf', type : 'string', description : 'Default PBKDF algorithm (pbkdf2 or argon2i/argon2id) for LUKS2', value : 'argon2id') +option('default-luks-format', type : 'combo', choices : ['LUKS1', 'LUKS2'], description : 'default LUKS format version', value : 'LUKS2') +option('default-passphrase-size-max', type : 'integer', description : 'maximum passphrase size (in characters)', value : 512) +option('default-plain-cipher', type : 'string', description : 'cipher for plain mode', value : 'aes') +option('default-plain-hash', type : 'string', description : 'cipher for plain mode', value : 'ripemd160') +option('default-plain-keybits', type : 'integer', description : 'key length in bits for plain mode', value : 256) +option('default-plain-mode', type : 'string', description : 'cipher mode for plain mode', value : 'cbc-essiv:sha256') +option('default-verity-data-block', type : 'integer', description : 'data block size for verity mode', value : 4096) +option('default-verity-fec-roots', type : 'integer', description : 'parity bytes for verity FEC', value : 2) +option('default-verity-hash-block', type : 'integer', description : 'hash block size for verity mode', value : 4096) +option('default-verity-hash', type : 'string', description : 'hash function for verity mode', value : 'sha256') +option('default-verity-salt-size', type : 'integer', description : 'salt size for verity mode', value : 32) +option('dev-random', type : 'boolean', description : 'use /dev/random by default for key generation (use /dev/urandom when set to false)', value : false) +option('enable-static', type : 'boolean', description : 'build static libraries', value : false) +option('external-tokens', type : 'boolean', description : 'external LUKS2 tokens', value : true) +option('fips', type : 'boolean', description : 'enable FIPS mode restrictions', value : false) +option('fuzzing-engine', type : 'string', description : 'specify LDFLAGS for linking with fuzzing engine (in OSS-Fuzz, LIB_FUZZING_ENGINE variable should be passed via this argument)') +option('fuzz-targets', type : 'boolean', description : 'enable building fuzz targets', value : false) +option('gcrypt-pbkdf2', type : 'feature', description : 'enable internal gcrypt PBKDF2', value : 'auto') +option('integritysetup', type : 'boolean', description : 'integritysetup Support', value : true) +option('internal-sse-argon2', type : 'boolean', description : 'use internal SSE implementation of Argon2 PBKDF', value : false) +option('kernel_crypto', type : 'boolean', description : 'kernel userspace crypto (no benchmark and tcrypt)', value : true) +option('keyring', type : 'boolean', description : 'kernel keyring support and builtin kernel keyring token', value : true) +option('luks2-reencryption', type : 'boolean', description : 'LUKS2 online reencryption extension', value : true) +option('luks_adjust_xts_keysize', type : 'boolean', description : 'XTS mode requires two keys, double default LUKS keysize if needed', value : true) +option('nls', type : 'boolean', description : 'use Native Language Support', value : true) +option('passwdqc', type : 'string', description : 'enable password quality checking using passwdqc library (optionally with CONFIG_PATH)', value : 'false') +option('pwquality', type : 'boolean', description : 'password quality checking using pwquality library', value : false) +option('ssh-token', type : 'boolean', description : 'LUKS2 ssh-token', value : true) +option('static-cryptsetup', type : 'boolean', description : 'enable build of static version of tools', value : false) +option('tmpfilesdir', type : 'string', description : 'override default path to directory with systemd temporary files') +option('udev', type : 'boolean', description : 'udev support', value : true) +option('veritysetup', type : 'boolean', description : 'veritysetup support', value : true) diff --git a/po/meson.build b/po/meson.build new file mode 100644 index 00000000..c61a9536 --- /dev/null +++ b/po/meson.build @@ -0,0 +1,7 @@ +if get_option('nls') + i18n = import('i18n') + i18n.gettext(meson.project_name(), + preset: 'glib', + data_dirs: '.', + install: true) +endif diff --git a/scripts/meson.build b/scripts/meson.build new file mode 100644 index 00000000..fbb94aa5 --- /dev/null +++ b/scripts/meson.build @@ -0,0 +1,7 @@ +if tmpfilesdir != '' + cryptsetup_conf = configure_file( + input: 'cryptsetup.conf.in', + output: 'cryptsetup.conf', + configuration: conf, + install_dir: tmpfilesdir) +endif diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 00000000..3fd1ff5b --- /dev/null +++ b/src/meson.build @@ -0,0 +1,77 @@ +src_build_dir = meson.current_build_dir() + +if get_option('cryptsetup') + cryptsetup_files = files( + 'cryptsetup.c', + 'utils_args.c', + 'utils_blockdev.c', + 'utils_luks.c', + 'utils_password.c', + 'utils_progress.c', + 'utils_reencrypt.c', + 'utils_reencrypt_luks1.c', + 'utils_tools.c', + ) + cryptsetup_files += lib_tools_files + cryptsetup_deps = [ + popt, + pwquality, + passwdqc, + uuid, + blkid, + ] + cryptsetup = executable('cryptsetup', + cryptsetup_files, + dependencies: cryptsetup_deps, + link_with: libcryptsetup, + link_args: link_args, + include_directories: includes_tools) +endif + +if get_option('veritysetup') + veritysetup_files = files( + 'utils_args.c', + 'utils_tools.c', + 'veritysetup.c', + ) + veritysetup_files += lib_tools_files + veritysetup_deps = [ + popt, + blkid, + ] + + veritysetup = executable('veritysetup', + veritysetup_files, + dependencies: veritysetup_deps, + link_with: libcryptsetup, + link_args: link_args, + include_directories: includes_tools) +endif + +if get_option('integritysetup') + integritysetup_files = files( + 'integritysetup.c', + 'utils_args.c', + 'utils_blockdev.c', + 'utils_progress.c', + 'utils_tools.c', + ) + integritysetup_files += lib_tools_files + integritysetup_deps = [ + popt, + uuid, + blkid, + ] + + integritysetup = executable('integritysetup', + integritysetup_files, + dependencies: integritysetup_deps, + link_with: libcryptsetup, + link_args: link_args, + include_directories: includes_tools) +endif + +src_ssh_token_files = files( + 'utils_password.c', + 'utils_tools.c', +) diff --git a/tests/fuzz/meson.build b/tests/fuzz/meson.build new file mode 100644 index 00000000..95ea3823 --- /dev/null +++ b/tests/fuzz/meson.build @@ -0,0 +1,127 @@ +if get_option('fuzz-targets') + crypt2_load_fuzz = executable('crypt2_load_fuzz', + [ + 'crypt2_load_fuzz.cc', + ], + dependencies: [ + devmapper, + fuzzing_engine, + ], + link_with: [ + libcryptsetup, + libcrypto_backend, + libutils_io, + ], + link_args: [ + link_args, + ], + include_directories: includes_tools) + + crypt2_load_ondisk_fuzz = executable('crypt2_load_ondisk_fuzz', + [ + 'crypt2_load_ondisk_fuzz.cc', + ], + dependencies: [ + devmapper, + fuzzing_engine, + ], + link_with: [ + libcryptsetup, + libcrypto_backend, + libutils_io, + ], + link_args: [ + link_args, + ], + include_directories: includes_tools) + + luks2_generated = protoc_generator.process('LUKS2.proto') + crypt2_load_proto_fuzz = executable('crypt2_load_proto_fuzz', + [ + 'crypt2_load_proto_fuzz.cc', + 'proto_to_luks2_converter.cc', + luks2_generated, + ], + dependencies: [ + devmapper, + protobuf, + libprotobuf_mutator, + fuzzing_engine, + ], + link_with: [ + libcryptsetup, + libcrypto_backend, + libutils_io, + ], + link_args: [ + link_args, + ], + include_directories: includes_tools) + + luks2_plain_json_generated = protoc_generator.process('LUKS2_plain_JSON.proto') + crypt2_load_proto_plain_fuzz = executable('crypt2_load_proto_plain_fuzz', + [ + 'crypt2_load_proto_plain_json_fuzz.cc', + 'json_proto_converter.cc', + 'plain_json_proto_to_luks2_converter.cc', + luks2_plain_json_generated, + ], + dependencies: [ + devmapper, + protobuf, + libprotobuf_mutator, + fuzzing_engine, + ], + link_with: [ + libcryptsetup, + libcrypto_backend, + libutils_io, + ], + link_args: [ + link_args, + ], + include_directories: includes_tools) + + proto_to_luks2 = executable('proto_to_luks2', + [ + 'proto_to_luks2.cc', + 'proto_to_luks2_converter.cc', + luks2_generated, + ], + dependencies: [ + devmapper, + protobuf, + libprotobuf_mutator, + ], + link_with: [ + libcryptsetup, + libcrypto_backend, + libutils_io, + ], + link_args: [ + link_args, + ], + include_directories: includes_tools) + + plain_json_proto_to_luks2 = executable('plain_json_proto_to_luks2', + [ + 'plain_json_proto_to_luks2.cc', + 'plain_json_proto_to_luks2_converter.cc', + 'json_proto_converter.cc', + luks2_plain_json_generated, + ], + dependencies: [ + devmapper, + protobuf, + libprotobuf_mutator, + ], + link_with: [ + libcryptsetup, + libcrypto_backend, + libutils_io, + ], + link_args: [ + link_args, + ], + include_directories: includes_tools) +endif diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 00000000..00f629f5 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,464 @@ +fs = import('fs') + +# copy images and generators to build directory from where tests run +test_files_to_copy = [ + 'bitlk-images.tar.xz', + 'blkid-luks2-pv.img.xz', + 'compatimage.img.xz', + 'compatimage2.img.xz', + 'compatv10image.img.xz', + 'conversion_imgs.tar.xz', + 'evil_hdr-keyslot_overlap.xz', + 'evil_hdr-luks_hdr_damage.xz', + 'evil_hdr-payload_overwrite.xz', + 'evil_hdr-small_luks_device.xz', + 'evil_hdr-stripes_payload_dmg.xz', + 'fvault2-images.tar.xz', + 'generators/generate-luks2-area-in-json-hdr-space-json0.img.sh', + 'img_fs_ext4.img.xz', + 'luks1-images.tar.xz', + 'luks2_header_requirements.tar.xz', + 'luks2_keyslot_unassigned.img.xz', + 'luks2_mda_images.tar.xz', + 'luks2_valid_hdr.img.xz', + 'tcrypt-images.tar.xz', + 'valid_header_file.xz', + 'xfs_512_block_size.img.xz', +] + +foreach file : test_files_to_copy + if meson.version().version_compare('>=0.64') + fs.copyfile(file) + else + configure_file(input: file, + output: '@PLAINNAME@', + copy: true) + endif +endforeach + +api_test = executable('api-test', + [ + 'api-test.c', + 'test_utils.c', + ], + dependencies: devmapper, + link_with: libcryptsetup, + c_args: ['-DNO_CRYPTSETUP_PATH'], + include_directories: includes_lib) + +api_test_2 = executable('api-test-2', + [ + 'api-test-2.c', + 'test_utils.c', + ], + dependencies: devmapper, + link_with: libcryptsetup, + c_args: [ + '-DNO_CRYPTSETUP_PATH', + ], + include_directories: includes_lib) + +vectors_test = executable('vectors-test', + [ + 'crypto-vectors.c', + ], + link_with: libcrypto_backend, + c_args: [ + '-DNO_CRYPTSETUP_PATH', + ], + include_directories: includes_lib) + +differ = executable('differ', + [ + 'differ.c', + ], + c_args: [ + '-Wall', + '-O2', + ]) + +unit_utils_io = executable('unit-utils-io', + [ + 'unit-utils-io.c', + ], + link_with: libutils_io, + c_args: [ + '-DNO_CRYPTSETUP_PATH', + ], + include_directories: includes_lib) + +unit_utils_crypt_test = files('unit-utils-crypt.c',) + lib_utils_crypt_files +unit_utils_crypt_test = executable('unit-utils-crypt-test-test', + unit_utils_crypt_test, + link_with: libcryptsetup, + c_args: [ + '-DNO_CRYPTSETUP_PATH', + ], + include_directories: includes_lib) + +unit_wipe = executable('unit-wipe', + [ + 'unit-wipe.c', + ], + link_with: libcryptsetup, + c_args: [ + '-DNO_CRYPTSETUP_PATH', + ], + include_directories: includes_lib) + +generate_symbols_list = find_program('generate-symbols-list') +test_symbols_list_h = custom_target('test-symbols-list.h', + output: 'test-symbols-list.h', + input: [ + libcryptsetup_sym_path, + ], + # the scripts writes the output to stdout, capture and write to output file + capture: true, + command: [ + generate_symbols_list, + '@INPUT@', + ]) +all_symbols_test = executable('all-symbols-test', + [ + 'all-symbols-test.c', + test_symbols_list_h, + ], + dependencies: dl, + link_with: libcryptsetup, + c_args: [ + '-DNO_CRYPTSETUP_PATH', + ], + include_directories: includes_lib) + +fake_token_path = shared_library('fake_token_path', + [ + 'fake_token_path.c', + ], + include_directories: includes_lib, + version: libcryptsetup_version, + link_args: [ + '-Wl,--version-script=' + + libcryptsetup_sym_path, + ], + name_prefix: '', + c_args: ['-DBUILD_DIR="@0@"'.format(tokens_ssh_build_dir)], + build_by_default: not enable_static) + +fake_systemd_tpm_path = shared_library('fake_systemd_tpm_path', + [ + 'fake_systemd_tpm_path.c', + ], + name_prefix: '', + build_by_default: not enable_static) + +tests_env = environment() +tests_env.set('CRYPTSETUP_PATH', src_build_dir) +tests_env.set('LIBCRYPTSETUP_DIR', lib_build_dir) +tests_env.set('srcdir', meson.current_source_dir()) +tests_env.set('CRYPTSETUP_TESTS_RUN_IN_MESON', '1') + +test('00modules-test', + find_program('./00modules-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + priority: 9999) +test('api-test', + api_test, + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false) +test('api-test-2', + api_test_2, + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false) +test('blockwise-compat-test', + find_program('./blockwise-compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + unit_utils_io, + ]) +test('keyring-test', + find_program('./keyring-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false) +test('vectors-test', + vectors_test, + workdir: meson.current_build_dir(), + timeout: 14400, + is_parallel: false) +test('unit-wipe-test', + find_program('./unit-wipe-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + unit_wipe, + ]) +test('unit-utils-crypt-test', + unit_utils_crypt_test, + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false) + +if not enable_static + test('run-all-symbols', + find_program('./run-all-symbols'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + all_symbols_test, + libcryptsetup, + ]) +endif + +if get_option('cryptsetup') + test('compat-args-test', + find_program('./compat-args-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + test_symbols_list_h, + ]) + test('compat-test', + find_program('./compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + differ, + ]) + test('compat-test2', + find_program('./compat-test2'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('loopaes-test', + find_program('./loopaes-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('align-test', + find_program('./align-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('align-test2', + find_program('./align-test2'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('discards-test', + find_program('./discards-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('mode-test', + find_program('./mode-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('password-hash-test', + find_program('./password-hash-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('tcrypt-compat-test', + find_program('./tcrypt-compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('luks1-compat-test', + find_program('./luks1-compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('device-test', + find_program('./device-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('keyring-compat-test', + find_program('./keyring-compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('luks2-validation-test', + find_program('./luks2-validation-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('luks2-integrity-test', + find_program('./luks2-integrity-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('bitlk-compat-test', + find_program('./bitlk-compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('fvault2-compat-test', + find_program('./fvault2-compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('reencryption-compat-test', + find_program('./reencryption-compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('luks2-reencryption-test', + find_program('./luks2-reencryption-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) + test('luks2-reencryption-mangle-test', + find_program('./luks2-reencryption-mangle-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup, + ]) +endif + +if get_option('veritysetup') + test('verity-compat-test', + find_program('verity-compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + veritysetup, + ]) +endif + +if get_option('integritysetup') + test('integrity-compat-test', + find_program('integrity-compat-test'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + integritysetup, + ]) +endif + +if get_option('ssh-token') and not enable_static + test('ssh-test-plugin', + find_program('ssh-test-plugin'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + cryptsetup_ssh, + fake_token_path, + libcryptsetup_token_ssh, + ]) +endif + +if get_option('external-tokens') and not enable_static + test('systemd-test-plugin', + find_program('systemd-test-plugin'), + workdir: meson.current_build_dir(), + env: tests_env, + timeout: 14400, + is_parallel: false, + depends: [ + fake_systemd_tpm_path, + fake_token_path, + ]) +endif + +subdir('fuzz') diff --git a/tests/run-all-symbols b/tests/run-all-symbols index 775d5bb0..58a1ba68 100755 --- a/tests/run-all-symbols +++ b/tests/run-all-symbols @@ -1,7 +1,7 @@ #!/bin/bash -DIR=../.libs -FILE=$DIR/libcryptsetup.so +[ -z "$LIBCRYPTSETUP_DIR" ] && LIBCRYPTSETUP_DIR=../.libs +FILE=$LIBCRYPTSETUP_DIR/libcryptsetup.so function fail() { @@ -15,7 +15,7 @@ function skip() exit 77 } -test -d $DIR || fail "Directory $DIR is missing." +test -d $LIBCRYPTSETUP_DIR || fail "Directory $LIBCRYPTSETUP_DIR is missing." test -f $FILE || skip "WARNING: Shared $FILE is missing, test skipped." ./all-symbols-test $FILE $@ diff --git a/tests/ssh-test-plugin b/tests/ssh-test-plugin index 5b3966e7..01590ed5 100755 --- a/tests/ssh-test-plugin +++ b/tests/ssh-test-plugin @@ -27,6 +27,15 @@ CRYPTSETUP_LIB_VALGRIND=../.libs [ -z "$srcdir" ] && srcdir="." +[ -z "$CRYPTSETUP_TESTS_RUN_IN_MESON" ] || { + # test runs on meson build + TOKEN_PATH="$CRYPTSETUP_PATH/../tests/fake_token_path.so" + [ ! -f $TOKEN_PATH ] && { echo "Please compile $TOKEN_PATH."; exit 77; } + export LD_PRELOAD=$TOKEN_PATH + + CRYPTSETUP_SSH="$CRYPTSETUP_PATH/../tokens/ssh/cryptsetup-ssh" +} + function remove_mapping() { [ -b /dev/mapper/$MAP ] && dmsetup remove --retry $MAP diff --git a/tests/systemd-test-plugin b/tests/systemd-test-plugin index 5f373244..4c64464f 100755 --- a/tests/systemd-test-plugin +++ b/tests/systemd-test-plugin @@ -61,6 +61,46 @@ CRYPTENROLL_LD_PRELOAD="" # if CRYPTSETUP_PATH is defined, we run against installed binaries, # otherwise we compile systemd tokens from source +[ ! -z "$CRYPTSETUP_TESTS_RUN_IN_MESON" ] && { + bin_check git + bin_check meson + bin_check ninja + bin_check pkgconf + + TOKEN_PATH=fake_token_path.so + [ -f $TOKEN_PATH ] || skip "Please compile $TOKEN_PATH." + INSTALL_PATH=$CRYPTSETUP_PATH/../external-tokens/install + mkdir -p $INSTALL_PATH + DESTDIR=$INSTALL_PATH meson install -C .. + PC_FILE="$(find $INSTALL_PATH -name 'libcryptsetup.pc')" + echo "INSTALL_PATH $INSTALL_PATH" + echo "PC_FILE $PC_FILE" + sed -i "s/^prefix=/prefix=${INSTALL_PATH//\//\\\/}/g" "$PC_FILE" + export PKG_CONFIG_PATH=$(dirname $PC_FILE) + + # systemd build system misses libcryptsetup.h if it is installed in non-default path + export CFLAGS="${CFLAGS:-} $(pkgconf --cflags libcryptsetup)" + + SYSTEMD_PATH=$CRYPTSETUP_PATH/../external-tokens/systemd + SYSTEMD_CRYPTENROLL=$SYSTEMD_PATH/build/systemd-cryptenroll + + mkdir -p $SYSTEMD_PATH + [ -e $SYSTEMD_PATH ] || git clone --depth=1 https://github.com/systemd/systemd.git $SYSTEMD_PATH + cd $SYSTEMD_PATH + meson -D tpm2=true -D libcryptsetup=true -D libcryptsetup-plugins=true build/ || skip "Failed to configure systemd via meson, some dependencies are probably missing." + ninja -C build/ systemd-cryptenroll libcryptsetup-token-systemd-tpm2.so || skip "Failed to build systemd." + + cd $CRYPTSETUP_PATH/../tests + cp $SYSTEMD_PATH/build/libcryptsetup-token-*.so $CRYPTSETUP_PATH/../tokens/ssh + cp $SYSTEMD_PATH/build/src/shared/*.so $CRYPTSETUP_PATH/../tests + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$CRYPTSETUP_PATH/../tests" + + export LD_PRELOAD="${LD_PRELOAD-}:$CRYPTSETUP_PATH/../tests/$TOKEN_PATH" + CRYPTENROLL_LD_PRELOAD="$CRYPTSETUP_PATH/../lib/libcryptsetup.so" + + echo "CRYPTENROLL_LD_PRELOAD $CRYPTENROLL_LD_PRELOAD" +} + [ -z "$CRYPTSETUP_PATH" ] && { bin_check git bin_check meson @@ -83,7 +123,7 @@ CRYPTENROLL_LD_PRELOAD="" SYSTEMD_CRYPTENROLL=$SYSTEMD_PATH/build/systemd-cryptenroll mkdir -p $SYSTEMD_PATH - [ "$(ls -A $SYSTEMD_PATH)" ] || git clone --depth=1 https://github.com/systemd/systemd.git $SYSTEMD_PATH + [ -e $SYSTEMD_PATH ] || git clone --depth=1 https://github.com/systemd/systemd.git $SYSTEMD_PATH cd $SYSTEMD_PATH meson -D tpm2=true -D libcryptsetup=true -D libcryptsetup-plugins=true build/ || skip "Failed to configure systemd via meson, some dependencies are probably missing." ninja -C build/ systemd-cryptenroll libcryptsetup-token-systemd-tpm2.so || skip "Failed to build systemd." @@ -116,6 +156,7 @@ CRYPTSETUP=$CRYPTSETUP_PATH/cryptsetup } FAKE_TPM_PATH="$(pwd)/fake_systemd_tpm_path.so" +[ ! -z "$CRYPTSETUP_TESTS_RUN_IN_MESON" ] && FAKE_TPM_PATH="$CRYPTSETUP_PATH/../tests/fake_systemd_tpm_path.so" [ -f $FAKE_TPM_PATH ] || skip "Please compile $FAKE_TPM_PATH." export LD_PRELOAD="$LD_PRELOAD:$FAKE_TPM_PATH" diff --git a/tokens/meson.build b/tokens/meson.build new file mode 100644 index 00000000..a772a110 --- /dev/null +++ b/tokens/meson.build @@ -0,0 +1,8 @@ +libcryptsetup_token_sym_path = join_paths(meson.current_source_dir(), 'libcryptsetup-token.sym') + +token_link_args = [ + '-Wl,--version-script=' + + libcryptsetup_token_sym_path, +] + +subdir('ssh') diff --git a/tokens/ssh/meson.build b/tokens/ssh/meson.build new file mode 100644 index 00000000..dba1d761 --- /dev/null +++ b/tokens/ssh/meson.build @@ -0,0 +1,39 @@ +tokens_ssh_build_dir = meson.current_build_dir() + +if get_option('ssh-token') + if not enable_static + libcryptsetup_token_ssh = shared_library( + 'cryptsetup-token-ssh', + [ + 'libcryptsetup-token-ssh.c', + 'ssh-utils.c', + ], + dependencies: [ + jsonc, + libssh, + ], + link_with: libcryptsetup, + link_args: token_link_args, + include_directories: includes_tools + ['..']) + endif + + cryptsetup_ssh_files = files( + 'cryptsetup-ssh.c', + 'ssh-utils.c', + ) + cryptsetup_ssh_files += lib_ssh_token_files + cryptsetup_ssh_files += src_ssh_token_files + + cryptsetup_ssh = executable('cryptsetup-ssh', + cryptsetup_ssh_files, + dependencies: [ + argp, + jsonc, + libssh, + passwdqc, + popt, + pwquality, + ], + link_with: libcryptsetup, + include_directories: includes_tools + ['..']) +endif