mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-08 01:10:03 +01:00
Compare commits
17 Commits
v2.8.1
...
coverity_s
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83a7310ca2 | ||
|
|
441802773f | ||
|
|
cc66b1fa52 | ||
|
|
a0d5d2bf5e | ||
|
|
61dbb69319 | ||
|
|
32b33541a8 | ||
|
|
346db2e42a | ||
|
|
0d07e80077 | ||
|
|
dc2251b88d | ||
|
|
a8e8e39007 | ||
|
|
bcef385346 | ||
|
|
9810c6fb2f | ||
|
|
4d98add260 | ||
|
|
0eaaa4553e | ||
|
|
3a8feb8be7 | ||
|
|
2b9523a1ef | ||
|
|
68d4749d8a |
@@ -10,7 +10,6 @@ include:
|
||||
- local: .gitlab/ci/debian.yml
|
||||
- local: .gitlab/ci/fedora.yml
|
||||
- local: .gitlab/ci/fedora-opal.yml
|
||||
- local: .gitlab/ci/rhel.yml
|
||||
- local: .gitlab/ci/centos.yml
|
||||
# - local: .gitlab/ci/annocheck.yml
|
||||
- local: .gitlab/ci/csmock.yml
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
.centos-openssl-backend:
|
||||
variables:
|
||||
DISTRO: cryptsetup-centos-stream-9
|
||||
extends:
|
||||
- .fail_if_coredump_generated
|
||||
before_script:
|
||||
@@ -29,6 +27,7 @@ test-main-commit-centos-stream9:
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-centos-stream-9
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
RUN_KEYRING_TRUSTED_TEST: "1"
|
||||
rules:
|
||||
@@ -51,6 +50,53 @@ test-mergerq-centos-stream9:
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-centos-stream-9
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
RUN_KEYRING_TRUSTED_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
script:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
test-main-commit-centos-stream10:
|
||||
extends:
|
||||
- .centos-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- cryptsetup-centos-stream-10
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-centos-stream-10
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
RUN_KEYRING_TRUSTED_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
test-mergerq-centos-stream10:
|
||||
extends:
|
||||
- .centos-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- cryptsetup-centos-stream-10
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-centos-stream-10
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
RUN_KEYRING_TRUSTED_TEST: "1"
|
||||
rules:
|
||||
|
||||
@@ -1,157 +0,0 @@
|
||||
.rhel-openssl-backend:
|
||||
extends:
|
||||
- .fail_if_coredump_generated
|
||||
before_script:
|
||||
- >
|
||||
sudo yum -y -q install
|
||||
autoconf automake device-mapper-devel gcc gettext-devel json-c-devel
|
||||
libblkid-devel libpwquality-devel libselinux-devel libssh-devel libtool
|
||||
libuuid-devel make popt-devel libsepol-devel nc openssh-clients passwd
|
||||
pkgconfig sharutils sshpass tar uuid-devel vim-common device-mapper
|
||||
expect gettext git jq keyutils openssl-devel openssl gem
|
||||
- sudo gem install asciidoctor
|
||||
- sudo -E git clean -xdf
|
||||
- ./autogen.sh
|
||||
- ./configure --enable-fips --enable-pwquality --with-crypto_backend=openssl --enable-asciidoc
|
||||
|
||||
# non-FIPS jobs
|
||||
|
||||
test-main-commit-rhel8:
|
||||
extends:
|
||||
- .rhel-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- cryptsetup-rhel-8
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-rhel-8
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
test-main-commit-rhel9:
|
||||
extends:
|
||||
- .rhel-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- cryptsetup-rhel-9
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-rhel-9
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
test-main-commit-rhel10:
|
||||
extends:
|
||||
- .rhel-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- cryptsetup-rhel-10
|
||||
stage: test
|
||||
interruptible: true
|
||||
allow_failure: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-rhel-10
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
# FIPS jobs
|
||||
|
||||
test-main-commit-rhel8-fips:
|
||||
extends:
|
||||
- .rhel-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- cryptsetup-rhel-8-fips
|
||||
stage: test
|
||||
interruptible: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-rhel-8-fips
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- grep -q fips=1 /proc/cmdline || exit 1
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
test-main-commit-rhel9-fips:
|
||||
extends:
|
||||
- .rhel-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- cryptsetup-rhel-9-fips
|
||||
stage: test
|
||||
interruptible: true
|
||||
allow_failure: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-rhel-9-fips
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- grep -q fips=1 /proc/cmdline || exit 1
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
|
||||
test-main-commit-rhel10-fips:
|
||||
extends:
|
||||
- .rhel-openssl-backend
|
||||
tags:
|
||||
- libvirt
|
||||
- cryptsetup-rhel-10-fips
|
||||
stage: test
|
||||
interruptible: true
|
||||
allow_failure: true
|
||||
variables:
|
||||
DISTRO: cryptsetup-rhel-10-fips
|
||||
RUN_SSH_PLUGIN_TEST: "1"
|
||||
rules:
|
||||
- if: $RUN_SYSTEMD_PLUGIN_TEST != null
|
||||
when: never
|
||||
- if: $CI_PROJECT_PATH != "cryptsetup/cryptsetup"
|
||||
when: never
|
||||
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_BRANCH =~ /v2\..\.x$/
|
||||
script:
|
||||
- grep -q fips=1 /proc/cmdline || exit 1
|
||||
- make -j
|
||||
- make -j -C tests check-programs
|
||||
- sudo -E make check
|
||||
21
configure.ac
21
configure.ac
@@ -680,6 +680,27 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
])
|
||||
CFLAGS=$saved_CFLAGS
|
||||
|
||||
dnl Force compiler to use zero_call_used_regs("used") to check for the function attribute support.
|
||||
dnl Otherwise the compiler may falsely advertise it with __has_attribute operator, even though
|
||||
dnl it does not implement it on some archs.
|
||||
AC_MSG_CHECKING([for zero_call_used_regs(user)])
|
||||
saved_CFLAGS=$CFLAGS
|
||||
CFLAGS="-O0 -Werror"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||
void _test_function(void);
|
||||
__attribute__((zero_call_used_regs("used"))) void _test_function(void) {
|
||||
volatile int *i; volatile int j = 0; if (j) *i = 0;
|
||||
}
|
||||
]],
|
||||
[[ _test_function() ]]
|
||||
)],[
|
||||
AC_DEFINE([HAVE_ATTRIBUTE_ZEROCALLUSEDREGS], 1, [Define to 1 to use __attribute__((zero_call_used_regs("used")))])
|
||||
AC_MSG_RESULT([yes])
|
||||
], [
|
||||
AC_MSG_RESULT([no])
|
||||
])
|
||||
CFLAGS=$saved_CFLAGS
|
||||
|
||||
AC_MSG_CHECKING([for systemd tmpfiles config directory])
|
||||
if test "x$prefix" != "xNONE"; then
|
||||
saved_PKG_CONFIG=$PKG_CONFIG
|
||||
|
||||
@@ -111,6 +111,7 @@ struct bitlk_superblock {
|
||||
struct bitlk_fve_metadata {
|
||||
/* FVE metadata block header */
|
||||
uint8_t signature[8];
|
||||
/* size of this block (in 16-byte units) */
|
||||
uint16_t fve_size;
|
||||
uint16_t fve_version;
|
||||
uint16_t curr_state;
|
||||
@@ -132,6 +133,32 @@ struct bitlk_fve_metadata {
|
||||
uint64_t creation_time;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct bitlk_validation_hash {
|
||||
uint16_t size;
|
||||
uint16_t role;
|
||||
uint16_t type;
|
||||
uint16_t flags;
|
||||
/* likely a hash type code, anything other than 0x2005 isn't supported */
|
||||
uint16_t hash_type;
|
||||
uint16_t unknown1;
|
||||
/* SHA-256 */
|
||||
uint8_t hash[32];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct bitlk_fve_metadata_validation {
|
||||
/* FVE metadata validation block header */
|
||||
uint16_t validation_size;
|
||||
uint16_t validation_version;
|
||||
uint32_t fve_crc32;
|
||||
/* this is a single nested structure's header defined here for simplicity */
|
||||
uint16_t nested_struct_size;
|
||||
uint16_t nested_struct_role;
|
||||
uint16_t nested_struct_type;
|
||||
uint16_t nested_struct_flags;
|
||||
/* datum containing a similar nested structure (encrypted using VMK) with hash (SHA256) */
|
||||
uint8_t nested_struct_data[BITLK_VALIDATION_VMK_DATA_SIZE];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct bitlk_entry_header_block {
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
@@ -361,6 +388,54 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool check_fve_metadata(struct bitlk_fve_metadata *fve)
|
||||
{
|
||||
if (memcmp(fve->signature, BITLK_SIGNATURE, sizeof(fve->signature)) || le16_to_cpu(fve->fve_version) != 2 ||
|
||||
(fve->fve_size << 4) > BITLK_FVE_METADATA_SIZE)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool check_fve_metadata_validation(struct bitlk_fve_metadata_validation *validation)
|
||||
{
|
||||
/* only check if there is room for CRC-32, the actual size must be larger */
|
||||
if (le16_to_cpu(validation->validation_size) < 8 || le16_to_cpu(validation->validation_version > 2))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_fve_metadata_validation(struct bitlk_metadata *params, struct bitlk_fve_metadata_validation *validation)
|
||||
{
|
||||
/* extra checks for a nested structure (MAC) and BITLK FVE metadata */
|
||||
|
||||
if (le16_to_cpu(validation->validation_size) < sizeof(struct bitlk_fve_metadata_validation))
|
||||
return false;
|
||||
|
||||
if (le16_to_cpu(validation->nested_struct_size != BITLK_VALIDATION_VMK_HEADER_SIZE + BITLK_VALIDATION_VMK_DATA_SIZE) ||
|
||||
le16_to_cpu(validation->nested_struct_role) != 0 ||
|
||||
le16_to_cpu(validation->nested_struct_type) != 5)
|
||||
return false;
|
||||
|
||||
/* nonce */
|
||||
memcpy(params->validation->nonce,
|
||||
validation->nested_struct_data,
|
||||
BITLK_NONCE_SIZE);
|
||||
|
||||
/* MAC tag */
|
||||
memcpy(params->validation->mac_tag,
|
||||
validation->nested_struct_data + BITLK_NONCE_SIZE,
|
||||
BITLK_VMK_MAC_TAG_SIZE);
|
||||
|
||||
/* AES-CCM encrypted datum with SHA256 hash */
|
||||
memcpy(params->validation->enc_datum,
|
||||
validation->nested_struct_data + BITLK_NONCE_SIZE + BITLK_VMK_MAC_TAG_SIZE,
|
||||
BITLK_VALIDATION_VMK_DATA_SIZE - BITLK_NONCE_SIZE - BITLK_VMK_MAC_TAG_SIZE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BITLK_bitlk_fvek_free(struct bitlk_fvek *fvek)
|
||||
{
|
||||
if (!fvek)
|
||||
@@ -391,6 +466,7 @@ void BITLK_bitlk_metadata_free(struct bitlk_metadata *metadata)
|
||||
|
||||
free(metadata->guid);
|
||||
free(metadata->description);
|
||||
free(metadata->validation);
|
||||
BITLK_bitlk_vmk_free(metadata->vmks);
|
||||
BITLK_bitlk_fvek_free(metadata->fvek);
|
||||
}
|
||||
@@ -402,20 +478,25 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
struct bitlk_signature sig = {};
|
||||
struct bitlk_superblock sb = {};
|
||||
struct bitlk_fve_metadata fve = {};
|
||||
struct bitlk_fve_metadata_validation validation = {};
|
||||
struct bitlk_entry_vmk entry_vmk = {};
|
||||
uint8_t *fve_entries = NULL;
|
||||
uint8_t *fve_validated_block = NULL;
|
||||
size_t fve_entries_size = 0;
|
||||
uint32_t fve_metadata_size = 0;
|
||||
uint32_t fve_size_real = 0;
|
||||
int fve_offset = 0;
|
||||
char guid_buf[UUID_STR_LEN] = {0};
|
||||
uint16_t entry_size = 0;
|
||||
uint16_t entry_type = 0;
|
||||
int i = 0;
|
||||
int r = 0;
|
||||
int valid_fve_metadata_idx = -1;
|
||||
int start = 0;
|
||||
size_t key_size = 0;
|
||||
const char *key = NULL;
|
||||
char *description = NULL;
|
||||
struct crypt_hash *hash;
|
||||
|
||||
struct bitlk_vmk *vmk = NULL;
|
||||
struct bitlk_vmk *vmk_p = params->vmks;
|
||||
@@ -490,15 +571,80 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
for (i = 0; i < 3; i++)
|
||||
params->metadata_offset[i] = le64_to_cpu(sb.fve_offset[i]);
|
||||
|
||||
log_dbg(cd, "Reading BITLK FVE metadata of size %zu on device %s, offset %" PRIu64 ".",
|
||||
sizeof(fve), device_path(device), params->metadata_offset[0]);
|
||||
fve_validated_block = malloc(BITLK_FVE_METADATA_SIZE);
|
||||
if (fve_validated_block == NULL) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* read FVE metadata from the first metadata area */
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), &fve, sizeof(fve), params->metadata_offset[0]) != sizeof(fve) ||
|
||||
memcmp(fve.signature, BITLK_SIGNATURE, sizeof(fve.signature)) ||
|
||||
le16_to_cpu(fve.fve_version) != 2) {
|
||||
log_err(cd, _("Failed to read BITLK FVE metadata from %s."), device_path(device));
|
||||
for (i = 0; i < 3; i++) {
|
||||
/* iterate over FVE metadata copies and pick the valid one */
|
||||
log_dbg(cd, "Reading BITLK FVE metadata copy #%d of size %zu on device %s, offset %" PRIu64 ".",
|
||||
i, sizeof(fve), device_path(device), params->metadata_offset[i]);
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), &fve, sizeof(fve), params->metadata_offset[i]) != sizeof(fve) ||
|
||||
!check_fve_metadata(&fve) ||
|
||||
(fve_size_real = le16_to_cpu(fve.fve_size) << 4, read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), &validation, sizeof(validation), params->metadata_offset[i] + fve_size_real) != sizeof(validation)) ||
|
||||
!check_fve_metadata_validation(&validation) ||
|
||||
/* double-fetch is here, but we aren't validating MAC */
|
||||
read_lseek_blockwise(devfd, device_block_size(cd, device), device_alignment(device), fve_validated_block, fve_size_real,
|
||||
params->metadata_offset[i]) != fve_size_real ||
|
||||
(crypt_crc32(~0, fve_validated_block, fve_size_real) ^ ~0) != le32_to_cpu(validation.fve_crc32)) {
|
||||
/* found an invalid FVE metadata copy, log and skip */
|
||||
log_dbg(cd, _("Failed to read or validate BITLK FVE metadata copy #%d from %s."), i, device_path(device));
|
||||
} else {
|
||||
/* found a valid FVE metadata copy, use it */
|
||||
valid_fve_metadata_idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_fve_metadata_idx < 0) {
|
||||
/* all FVE metadata copies are invalid, fail */
|
||||
log_err(cd, _("Failed to read and validate BITLK FVE metadata from %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* check that a valid FVE metadata block is in its expected location */
|
||||
if (params->metadata_offset[valid_fve_metadata_idx] != le64_to_cpu(fve.fve_offset[valid_fve_metadata_idx])) {
|
||||
log_err(cd, _("Failed to validate the location of BITLK FVE metadata from %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* update offsets from a valid FVE metadata copy */
|
||||
for (i = 0; i < 3; i++)
|
||||
params->metadata_offset[i] = le64_to_cpu(fve.fve_offset[i]);
|
||||
|
||||
/* check that the FVE metadata hasn't changed between reads, because we are preparing for the MAC check */
|
||||
if (memcmp(&fve, fve_validated_block, sizeof(fve)) != 0) {
|
||||
log_err(cd, _("BITLK FVE metadata changed between reads from %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
crypt_backend_memzero(¶ms->sha256_fve, 32);
|
||||
if (crypt_hash_init(&hash, "sha256")) {
|
||||
log_err(cd, _("Failed to hash BITLK FVE metadata read from %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
crypt_hash_write(hash, (const char *)fve_validated_block, fve_size_real);
|
||||
crypt_hash_final(hash, (char *)¶ms->sha256_fve, 32);
|
||||
crypt_hash_destroy(hash);
|
||||
|
||||
/* do some extended checks against FVE metadata, but not including MAC verification */
|
||||
params->validation = malloc(sizeof(struct bitlk_validation));
|
||||
if (!params->validation) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!parse_fve_metadata_validation(params, &validation)) {
|
||||
log_err(cd, _("Failed to parse BITLK FVE validation metadata from %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -583,17 +729,18 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
}
|
||||
memset(fve_entries, 0, fve_entries_size);
|
||||
|
||||
log_dbg(cd, "Reading BITLK FVE metadata entries of size %zu on device %s, offset %" PRIu64 ".",
|
||||
fve_entries_size, device_path(device), params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN);
|
||||
log_dbg(cd, "Getting BITLK FVE metadata entries of size %zu on device %s, offset %" PRIu64 ".",
|
||||
fve_entries_size, device_path(device), params->metadata_offset[valid_fve_metadata_idx] + BITLK_FVE_METADATA_HEADERS_LEN);
|
||||
|
||||
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
|
||||
device_alignment(device), fve_entries, fve_entries_size,
|
||||
params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN) != (ssize_t)fve_entries_size) {
|
||||
log_err(cd, _("Failed to read BITLK metadata entries from %s."), device_path(device));
|
||||
if (BITLK_FVE_METADATA_HEADERS_LEN + fve_entries_size > fve_size_real) {
|
||||
log_err(cd, _("Failed to check BITLK metadata entries previously read from %s."), device_path(device));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* fetch these entries from validated buffer to avoid double-fetch */
|
||||
memcpy(fve_entries, fve_validated_block + BITLK_FVE_METADATA_HEADERS_LEN, fve_entries_size);
|
||||
|
||||
while ((fve_entries_size - start) >= (sizeof(entry_size) + sizeof(entry_type))) {
|
||||
|
||||
/* size of this entry */
|
||||
@@ -716,6 +863,8 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
|
||||
}
|
||||
out:
|
||||
free(fve_entries);
|
||||
free(fve_validated_block);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -1110,6 +1259,7 @@ int BITLK_get_volume_key(struct crypt_device *cd,
|
||||
struct volume_key *open_vmk_key = NULL;
|
||||
struct volume_key *vmk_dec_key = NULL;
|
||||
struct volume_key *recovery_key = NULL;
|
||||
struct bitlk_validation_hash dec_hash = {};
|
||||
const struct bitlk_vmk *next_vmk = NULL;
|
||||
|
||||
next_vmk = params->vmks;
|
||||
@@ -1172,6 +1322,36 @@ int BITLK_get_volume_key(struct crypt_device *cd,
|
||||
}
|
||||
crypt_free_volume_key(vmk_dec_key);
|
||||
|
||||
log_dbg(cd, "Trying to decrypt validation metadata using VMK.");
|
||||
r = crypt_bitlk_decrypt_key(crypt_volume_key_get_key(open_vmk_key),
|
||||
crypt_volume_key_length(open_vmk_key),
|
||||
(const char*)params->validation->enc_datum,
|
||||
(char *)&dec_hash,
|
||||
BITLK_VALIDATION_VMK_DATA_SIZE - BITLK_NONCE_SIZE - BITLK_VMK_MAC_TAG_SIZE,
|
||||
(const char*)params->validation->nonce, BITLK_NONCE_SIZE,
|
||||
(const char*)params->validation->mac_tag, BITLK_VMK_MAC_TAG_SIZE);
|
||||
if (r < 0) {
|
||||
log_dbg(cd, "Failed to decrypt validation metadata using VMK.");
|
||||
crypt_free_volume_key(open_vmk_key);
|
||||
if (r == -ENOTSUP)
|
||||
return r;
|
||||
break;
|
||||
}
|
||||
|
||||
/* now, do the MAC validation */
|
||||
if (le16_to_cpu(dec_hash.role) != 0 ||le16_to_cpu(dec_hash.type) != 1 ||
|
||||
(le16_to_cpu(dec_hash.hash_type) != 0x2005)) {
|
||||
log_dbg(cd, "Failed to parse decrypted validation metadata.");
|
||||
crypt_free_volume_key(open_vmk_key);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (memcmp(dec_hash.hash, params->sha256_fve, sizeof(dec_hash.hash)) != 0) {
|
||||
log_dbg(cd, "Failed MAC validation of BITLK FVE metadata.");
|
||||
crypt_free_volume_key(open_vmk_key);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = decrypt_key(cd, open_fvek_key, params->fvek->vk, open_vmk_key,
|
||||
params->fvek->mac_tag, BITLK_VMK_MAC_TAG_SIZE,
|
||||
params->fvek->nonce, BITLK_NONCE_SIZE, true);
|
||||
|
||||
@@ -21,6 +21,8 @@ struct volume_key;
|
||||
#define BITLK_NONCE_SIZE 12
|
||||
#define BITLK_SALT_SIZE 16
|
||||
#define BITLK_VMK_MAC_TAG_SIZE 16
|
||||
#define BITLK_VALIDATION_VMK_HEADER_SIZE 8
|
||||
#define BITLK_VALIDATION_VMK_DATA_SIZE 72
|
||||
|
||||
#define BITLK_STATE_NORMAL 0x0004
|
||||
|
||||
@@ -85,6 +87,13 @@ struct bitlk_fvek {
|
||||
struct volume_key *vk;
|
||||
};
|
||||
|
||||
struct bitlk_validation {
|
||||
uint8_t mac_tag[BITLK_VMK_MAC_TAG_SIZE];
|
||||
uint8_t nonce[BITLK_NONCE_SIZE];
|
||||
/* technically, this is not "VMK", but some sources call it this way */
|
||||
uint8_t enc_datum[BITLK_VALIDATION_VMK_DATA_SIZE];
|
||||
};
|
||||
|
||||
struct bitlk_metadata {
|
||||
uint16_t sector_size;
|
||||
uint64_t volume_size;
|
||||
@@ -101,8 +110,10 @@ struct bitlk_metadata {
|
||||
uint32_t metadata_version;
|
||||
uint64_t volume_header_offset;
|
||||
uint64_t volume_header_size;
|
||||
const char *sha256_fve[32];
|
||||
struct bitlk_vmk *vmks;
|
||||
struct bitlk_fvek *fvek;
|
||||
struct bitlk_validation *validation;
|
||||
};
|
||||
|
||||
int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params);
|
||||
|
||||
@@ -9,11 +9,9 @@
|
||||
|
||||
#define ATTR_NOINLINE __attribute__ ((noinline))
|
||||
#define ATTR_ZERO_REGS
|
||||
#if defined __has_attribute
|
||||
# if __has_attribute (zero_call_used_regs)
|
||||
#if HAVE_ATTRIBUTE_ZEROCALLUSEDREGS
|
||||
# undef ATTR_ZERO_REGS
|
||||
# define ATTR_ZERO_REGS __attribute__ ((zero_call_used_regs("used")))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Workaround for https://github.com/google/sanitizers/issues/1507 */
|
||||
|
||||
@@ -58,6 +58,12 @@ typedef enum OpalStatus {
|
||||
_OPAL_STATUS_MAX = 0x13,
|
||||
} OpalStatus;
|
||||
|
||||
/*
|
||||
* Also defined in TCG Core spec Section 5.1.5 but
|
||||
* do not inflate the opal_status_table below
|
||||
*/
|
||||
#define OPAL_STATUS_FAIL 0x3f
|
||||
|
||||
static const char* const opal_status_table[_OPAL_STATUS_MAX] = {
|
||||
[OPAL_STATUS_SUCCESS] = "success",
|
||||
[OPAL_STATUS_NOT_AUTHORIZED] = "not authorized",
|
||||
@@ -85,9 +91,9 @@ static const char *opal_status_to_string(int t)
|
||||
if (t < 0)
|
||||
return strerror(-t);
|
||||
|
||||
/* Fail, as defined by specification */
|
||||
if (t == 0x3f)
|
||||
return "unknown failure";
|
||||
/* This will be checked upon 'Reactivate' method */
|
||||
if (t == OPAL_STATUS_FAIL)
|
||||
return "FAIL status";
|
||||
|
||||
if (t >= _OPAL_STATUS_MAX)
|
||||
return "unknown error";
|
||||
@@ -396,6 +402,182 @@ static int opal_enabled(struct crypt_device *cd, struct device *dev)
|
||||
return opal_query_status(cd, dev, OPAL_FL_LOCKING_ENABLED);
|
||||
}
|
||||
|
||||
static int opal_activate_lsp(struct crypt_device *cd, int fd,
|
||||
const void *admin_key, size_t admin_key_len)
|
||||
{
|
||||
int r;
|
||||
struct opal_lr_act *activate = crypt_safe_alloc(sizeof(*activate));
|
||||
|
||||
if (!activate)
|
||||
return -ENOMEM;
|
||||
|
||||
*activate = (struct opal_lr_act) {
|
||||
.key = {
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
/* useless but due to kernel bug it requires (num_lrs > 0 && num_lrs <= 9) */
|
||||
.num_lrs = 1,
|
||||
};
|
||||
crypt_safe_memcpy(activate->key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_TAKE_OWNERSHIP, &activate->key);
|
||||
if (r < 0) {
|
||||
r = -ENOTSUP;
|
||||
log_dbg(cd, "OPAL not supported on this kernel version, refusing.");
|
||||
goto out;
|
||||
}
|
||||
if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ {
|
||||
r = -EPERM;
|
||||
log_dbg(cd, "Failed to take ownership of OPAL device '%s': permission denied",
|
||||
crypt_get_device_name(cd));
|
||||
goto out;
|
||||
}
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to take ownership of OPAL device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_LSP, activate);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to activate OPAL device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
}
|
||||
out:
|
||||
crypt_safe_free(activate);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int opal_reuse_active_lsp(struct crypt_device *cd, int fd,
|
||||
uint32_t segment_number,
|
||||
const void *admin_key, size_t admin_key_len)
|
||||
{
|
||||
int r;
|
||||
struct opal_session_info *user_session = crypt_safe_alloc(sizeof(*user_session));
|
||||
|
||||
if (!user_session)
|
||||
return -ENOMEM;
|
||||
|
||||
*user_session = (struct opal_session_info) {
|
||||
.who = OPAL_ADMIN1, /* irrelevant in SUM */
|
||||
.opal_key = {
|
||||
.lr = segment_number,
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
};
|
||||
|
||||
/* If it is already enabled, wipe the locking range first */
|
||||
crypt_safe_memcpy(user_session->opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
crypt_safe_free(user_session);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int opal_setup_range(struct crypt_device *cd, int fd, uint32_t segment_number,
|
||||
uint64_t range_start_blocks, uint64_t range_length_blocks,
|
||||
const void *admin_key, size_t admin_key_len)
|
||||
{
|
||||
int r;
|
||||
struct opal_user_lr_setup *setup = crypt_safe_alloc(sizeof(*setup));
|
||||
|
||||
if (!setup)
|
||||
return -ENOMEM;
|
||||
|
||||
*setup = (struct opal_user_lr_setup) {
|
||||
.range_start = range_start_blocks,
|
||||
.range_length = range_length_blocks,
|
||||
/* Some drives do not enable Locking Ranges on setup. This have some
|
||||
* interesting consequences: Lock command called later below will pass,
|
||||
* but locking range will _not_ be locked at all.
|
||||
*/
|
||||
.RLE = 1,
|
||||
.WLE = 1,
|
||||
.session = {
|
||||
.who = OPAL_ADMIN1,
|
||||
.opal_key = {
|
||||
.key_len = admin_key_len,
|
||||
.lr = segment_number,
|
||||
},
|
||||
},
|
||||
};
|
||||
crypt_safe_memcpy(setup->session.opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to setup locking range of length %llu at offset %llu on OPAL device '%s': %s",
|
||||
setup->range_length, setup->range_start, crypt_get_device_name(cd),
|
||||
opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
}
|
||||
|
||||
crypt_safe_free(setup);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int opal_setup_user(struct crypt_device *cd, int fd, uint32_t segment_number,
|
||||
const void *admin_key, size_t admin_key_len)
|
||||
{
|
||||
int r;
|
||||
struct opal_lock_unlock *user_add_to_lr = crypt_safe_alloc(sizeof(*user_add_to_lr));
|
||||
|
||||
if (!user_add_to_lr)
|
||||
return -ENOMEM;
|
||||
|
||||
*user_add_to_lr = (struct opal_lock_unlock) {
|
||||
.session = {
|
||||
.who = segment_number + 1,
|
||||
.opal_key = {
|
||||
.lr = segment_number,
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
},
|
||||
.l_state = OPAL_RO,
|
||||
};
|
||||
|
||||
crypt_safe_memcpy(user_add_to_lr->session.opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_USR, &user_add_to_lr->session);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to activate OPAL user on device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to add OPAL user to locking range %u (RO) on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
user_add_to_lr->l_state = OPAL_RW;
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to add OPAL user to locking range %u (RW) on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
}
|
||||
out:
|
||||
crypt_safe_free(user_add_to_lr);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* requires opal lock */
|
||||
int opal_setup_ranges(struct crypt_device *cd,
|
||||
struct device *dev,
|
||||
@@ -407,11 +589,8 @@ int opal_setup_ranges(struct crypt_device *cd,
|
||||
const void *admin_key,
|
||||
size_t admin_key_len)
|
||||
{
|
||||
struct opal_lr_act *activate = NULL;
|
||||
struct opal_session_info *user_session = NULL;
|
||||
struct opal_lock_unlock *user_add_to_lr = NULL, *lock = NULL;
|
||||
struct opal_lock_unlock *lock = NULL;
|
||||
struct opal_new_pw *new_pw = NULL;
|
||||
struct opal_user_lr_setup *setup = NULL;
|
||||
int r, fd;
|
||||
|
||||
assert(cd);
|
||||
@@ -437,130 +616,16 @@ int opal_setup_ranges(struct crypt_device *cd,
|
||||
return r;
|
||||
|
||||
/* If OPAL has never been enabled, we need to take ownership and do basic setup first */
|
||||
if (r == 0) {
|
||||
activate = crypt_safe_alloc(sizeof(struct opal_lr_act));
|
||||
if (!activate) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*activate = (struct opal_lr_act) {
|
||||
.key = {
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
.num_lrs = 8,
|
||||
/* A max of 9 segments are supported, enable them all as there's no reason not to
|
||||
* (0 is whole-volume)
|
||||
*/
|
||||
.lr = { 1, 2, 3, 4, 5, 6, 7, 8 },
|
||||
};
|
||||
crypt_safe_memcpy(activate->key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_TAKE_OWNERSHIP, &activate->key);
|
||||
if (r < 0) {
|
||||
r = -ENOTSUP;
|
||||
log_dbg(cd, "OPAL not supported on this kernel version, refusing.");
|
||||
goto out;
|
||||
}
|
||||
if (r == OPAL_STATUS_NOT_AUTHORIZED) /* We'll try again with a different key. */ {
|
||||
r = -EPERM;
|
||||
log_dbg(cd, "Failed to take ownership of OPAL device '%s': permission denied",
|
||||
crypt_get_device_name(cd));
|
||||
goto out;
|
||||
}
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to take ownership of OPAL device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_LSP, activate);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to activate OPAL device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
/* If it is already enabled, wipe the locking range first */
|
||||
user_session = crypt_safe_alloc(sizeof(struct opal_session_info));
|
||||
if (!user_session) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*user_session = (struct opal_session_info) {
|
||||
.who = OPAL_ADMIN1,
|
||||
.opal_key = {
|
||||
.lr = segment_number,
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
};
|
||||
crypt_safe_memcpy(user_session->opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_SECURE_ERASE_LR, user_session);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to reset (secure erase) OPAL locking range %u on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
crypt_safe_free(user_session);
|
||||
|
||||
user_session = crypt_safe_alloc(sizeof(struct opal_session_info));
|
||||
if (!user_session) {
|
||||
r = -ENOMEM;
|
||||
if (r == 0)
|
||||
r = opal_activate_lsp(cd, fd, admin_key, admin_key_len);
|
||||
else
|
||||
r = opal_reuse_active_lsp(cd, fd, segment_number, admin_key, admin_key_len);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
*user_session = (struct opal_session_info) {
|
||||
.who = segment_number + 1,
|
||||
.opal_key = {
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
};
|
||||
crypt_safe_memcpy(user_session->opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ACTIVATE_USR, user_session);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to activate OPAL user on device '%s': %s",
|
||||
crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
r = opal_setup_user(cd, fd, segment_number, admin_key, admin_key_len);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
user_add_to_lr = crypt_safe_alloc(sizeof(struct opal_lock_unlock));
|
||||
if (!user_add_to_lr) {
|
||||
r = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
*user_add_to_lr = (struct opal_lock_unlock) {
|
||||
.session = {
|
||||
.who = segment_number + 1,
|
||||
.opal_key = {
|
||||
.lr = segment_number,
|
||||
.key_len = admin_key_len,
|
||||
},
|
||||
},
|
||||
.l_state = OPAL_RO,
|
||||
};
|
||||
crypt_safe_memcpy(user_add_to_lr->session.opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to add OPAL user to locking range %u (RO) on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
user_add_to_lr->l_state = OPAL_RW;
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_ADD_USR_TO_LR, user_add_to_lr);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to add OPAL user to locking range %u (RW) on device '%s': %s",
|
||||
segment_number, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_pw = crypt_safe_alloc(sizeof(struct opal_new_pw));
|
||||
if (!new_pw) {
|
||||
@@ -595,37 +660,10 @@ int opal_setup_ranges(struct crypt_device *cd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
setup = crypt_safe_alloc(sizeof(struct opal_user_lr_setup));
|
||||
if (!setup) {
|
||||
r = -ENOMEM;
|
||||
r = opal_setup_range(cd, fd, segment_number, range_start_blocks, range_length_blocks,
|
||||
admin_key, admin_key_len);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
*setup = (struct opal_user_lr_setup) {
|
||||
.range_start = range_start_blocks,
|
||||
.range_length = range_length_blocks,
|
||||
/* Some drives do not enable Locking Ranges on setup. This have some
|
||||
* interesting consequences: Lock command called later below will pass,
|
||||
* but locking range will _not_ be locked at all.
|
||||
*/
|
||||
.RLE = 1,
|
||||
.WLE = 1,
|
||||
.session = {
|
||||
.who = OPAL_ADMIN1,
|
||||
.opal_key = {
|
||||
.key_len = admin_key_len,
|
||||
.lr = segment_number,
|
||||
},
|
||||
},
|
||||
};
|
||||
crypt_safe_memcpy(setup->session.opal_key.key, admin_key, admin_key_len);
|
||||
|
||||
r = opal_ioctl(cd, fd, IOC_OPAL_LR_SETUP, setup);
|
||||
if (r != OPAL_STATUS_SUCCESS) {
|
||||
log_dbg(cd, "Failed to setup locking range of length %llu at offset %llu on OPAL device '%s': %s",
|
||||
setup->range_length, setup->range_start, crypt_get_device_name(cd), opal_status_to_string(r));
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* After setup an OPAL device is unlocked, but the expectation with cryptsetup is that it needs
|
||||
* to be activated separately, so lock it immediately. */
|
||||
@@ -661,11 +699,7 @@ int opal_setup_ranges(struct crypt_device *cd,
|
||||
&(uint64_t) {range_length_blocks * opal_block_bytes / SECTOR_SIZE},
|
||||
&(bool) {true}, &(bool){true}, NULL, NULL);
|
||||
out:
|
||||
crypt_safe_free(activate);
|
||||
crypt_safe_free(user_session);
|
||||
crypt_safe_free(user_add_to_lr);
|
||||
crypt_safe_free(new_pw);
|
||||
crypt_safe_free(setup);
|
||||
crypt_safe_free(lock);
|
||||
|
||||
return r;
|
||||
@@ -790,7 +824,11 @@ int opal_factory_reset(struct crypt_device *cd,
|
||||
if (password_len > OPAL_KEY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
fd = device_open(cd, dev, O_RDONLY);
|
||||
/*
|
||||
* Submit PSID reset on R/W file descriptor so it
|
||||
* triggers blkid rescan after we close it.
|
||||
*/
|
||||
fd = device_open(cd, dev, O_RDWR);
|
||||
if (fd < 0)
|
||||
return -EIO;
|
||||
|
||||
|
||||
@@ -1272,7 +1272,11 @@ int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, const char *u
|
||||
int LUKS2_hdr_labels(struct crypt_device *cd, struct luks2_hdr *hdr,
|
||||
const char *label, const char *subsystem, int commit)
|
||||
{
|
||||
//FIXME: check if the labels are the same and skip this.
|
||||
if ((label && strlen(label) >= LUKS2_LABEL_L) ||
|
||||
(subsystem && strlen(subsystem) >= LUKS2_LABEL_L)) {
|
||||
log_err(cd, _("Label is too long."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(hdr->label, 0, LUKS2_LABEL_L);
|
||||
if (label)
|
||||
|
||||
@@ -3045,7 +3045,11 @@ int crypt_format_inline(struct crypt_device *cd,
|
||||
iparams->journal_integrity_key_size))
|
||||
return -EINVAL;
|
||||
|
||||
if (!device_is_nop_dif(idevice, &device_tag_size)) {
|
||||
r = device_is_nop_dif(idevice, &device_tag_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!r) {
|
||||
log_err(cd, _("Device %s does not provide inline integrity data fields."), mdata_device_path(cd));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -1004,12 +1004,26 @@ int device_is_zoned(struct device *device)
|
||||
|
||||
int device_is_nop_dif(struct device *device, uint32_t *tag_size)
|
||||
{
|
||||
char *base_device_path;
|
||||
int r;
|
||||
struct stat st;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
if (stat(device_path(device), &st) < 0)
|
||||
/*
|
||||
* For partition devices, check integrity profile on the base device.
|
||||
* Partition device nodes don't advertise integrity profile directly
|
||||
* via sysfs attributes.
|
||||
*/
|
||||
base_device_path = crypt_get_base_device(device_path(device));
|
||||
if (base_device_path) {
|
||||
r = stat(base_device_path, &st);
|
||||
free(base_device_path);
|
||||
} else
|
||||
r = stat(device_path(device), &st);
|
||||
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!S_ISBLK(st.st_mode))
|
||||
|
||||
@@ -201,7 +201,7 @@ The file with the integrity key.
|
||||
The size of the journal integrity key.
|
||||
Maximum is 4096 bytes.
|
||||
|
||||
*--journal-size*, *-j* _butes_::
|
||||
*--journal-size*, *-j* _bytes_::
|
||||
Size of the journal.
|
||||
|
||||
*--journal-watermark* _percent_::
|
||||
|
||||
15
meson.build
15
meson.build
@@ -697,6 +697,21 @@ if cc.links(
|
||||
description: 'Define to 1 to use __attribute__((symver))')
|
||||
endif
|
||||
|
||||
# ==========================================================================
|
||||
# Check compiler support for zero_called_used_regs("used") function attribute
|
||||
if cc.links(
|
||||
'''void _test_fn(void);
|
||||
|
||||
__attribute__((zero_call_used_regs("used"))) void _test_fn(void) {
|
||||
volatile int *i; volatile int j = 0; if (j) *i = 0;
|
||||
}
|
||||
int main(void) { _test_fn(); return 0; }''',
|
||||
args: ['-O0', '-Werror' ],
|
||||
name: 'for zero_call_used_regs("used") attribute support')
|
||||
conf.set10('HAVE_ATTRIBUTE_ZEROCALLUSEDREGS', true,
|
||||
description: 'Define to 1 to use __attribute__((zero_call_used_regs("used")))')
|
||||
endif
|
||||
|
||||
# ==========================================================================
|
||||
|
||||
if get_option('dev-random')
|
||||
|
||||
@@ -246,4 +246,4 @@ ARG(OPT_WRITE_LOG, '\0', POPT_ARG_NONE, N_("Update log file after every block"),
|
||||
|
||||
ARG(OPT_DUMP_MASTER_KEY, '\0', POPT_ARG_NONE, N_("Alias for --dump-volume-key"), NULL, CRYPT_ARG_ALIAS, { .o.id = OPT_DUMP_VOLUME_KEY_ID}, {})
|
||||
|
||||
ARG(OPT_MASTER_KEY_FILE, '\0', POPT_ARG_STRING, N_("Alias for --dump-volume-key-file"), NULL, CRYPT_ARG_ALIAS, { .o.id = OPT_VOLUME_KEY_FILE_ID}, {})
|
||||
ARG(OPT_MASTER_KEY_FILE, '\0', POPT_ARG_STRING, N_("Alias for --volume-key-file"), NULL, CRYPT_ARG_ALIAS, { .o.id = OPT_VOLUME_KEY_FILE_ID}, {})
|
||||
|
||||
@@ -4059,6 +4059,7 @@ static void Luks2Refresh(void)
|
||||
static void Luks2Flags(void)
|
||||
{
|
||||
uint32_t flags = 42;
|
||||
const char *longlabel = "0123456789abcedf0123456789abcedf0123456789abcedf";
|
||||
|
||||
OK_(crypt_init(&cd, DEVICE_1));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
@@ -4089,6 +4090,9 @@ static void Luks2Flags(void)
|
||||
OK_(strcmp("", crypt_get_label(cd)));
|
||||
OK_(strcmp("", crypt_get_subsystem(cd)));
|
||||
|
||||
FAIL_(crypt_set_label(cd, longlabel, NULL), "long label");
|
||||
FAIL_(crypt_set_label(cd, NULL, longlabel), "long subsystem");
|
||||
|
||||
CRYPT_FREE(cd);
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1278,6 +1278,8 @@ $CRYPTSETUP luksDump $LOOPDEV | grep "Label:" | grep -q "(no label)" || fail
|
||||
$CRYPTSETUP config $LOOPDEV --subsystem SatelliteThree --label TheLabel
|
||||
$CRYPTSETUP luksDump $LOOPDEV | grep "Subsystem:" | grep -q "SatelliteThree" || fail
|
||||
$CRYPTSETUP luksDump $LOOPDEV | grep "Label:" | grep -q "TheLabel" || fail
|
||||
$CRYPTSETUP config $LOOPDEV --label 0123456789abcdef0123456789abcdef0123456789abcdef 2>/dev/null && fail
|
||||
$CRYPTSETUP config $LOOPDEV --subsystem 0123456789abcdef0123456789abcdef0123456789abcdef 2>/dev/null && fail
|
||||
|
||||
prepare "[36] LUKS PBKDF setting" wipe
|
||||
echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 --pbkdf bla $LOOPDEV >/dev/null 2>&1 && fail
|
||||
|
||||
Reference in New Issue
Block a user