From 598dd672bcb43fffaf498f46e52743164df2cf1d Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Mon, 15 Jan 2018 16:03:08 +0100 Subject: [PATCH] Detect kernel version for dm-crypt kernel key bugfix. When loading first dm-crypt table (or action that triggers dm-crypt module load) we do not know dm-crypt version yet. Let's assume all kernels before 4.15.0 are flawed and reject VK load via kernel keyring service. When dm-crypt is already in kernel, check for correct target version instead (v1.18.1 or later). --- lib/internal.h | 7 +++++++ lib/setup.c | 11 ++++++++++- lib/utils.c | 25 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/internal.h b/lib/internal.h index 198f2913..f6d5f5f0 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -197,4 +197,11 @@ int crypt_get_integrity_tag_size(struct crypt_device *cd); int crypt_key_in_keyring(struct crypt_device *cd); void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring); +static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release) +{ + return (uint64_t)release | ((uint64_t)patch << 16) | ((uint64_t)minor << 32) | ((uint64_t)major << 48); +} + +int kernel_version(uint64_t *kversion); + #endif /* INTERNAL_H */ diff --git a/lib/setup.c b/lib/setup.c index 686d14b5..2ee2aa23 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -4101,6 +4101,15 @@ static int kernel_keyring_support(void) return _kernel_keyring_supported; } +static int dmcrypt_keyring_bug(void) +{ + uint64_t kversion; + + if (kernel_version(&kversion)) + return 1; + return kversion < version(4,15,0,0); +} + int crypt_use_keyring_for_vk(const struct crypt_device *cd) { uint32_t dmc_flags; @@ -4113,7 +4122,7 @@ int crypt_use_keyring_for_vk(const struct crypt_device *cd) return 0; if (dm_flags(DM_CRYPT, &dmc_flags)) - return 1; + return dmcrypt_keyring_bug() ? 0 : 1; return (dmc_flags & DM_KERNEL_KEYRING_SUPPORTED); } diff --git a/lib/utils.c b/lib/utils.c index ac0cfd37..ca750f19 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "internal.h" @@ -553,3 +554,27 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile, return crypt_keyfile_device_read(cd, keyfile, key, key_size_read, keyfile_offset, keyfile_size_max, flags); } + +int kernel_version(uint64_t *kversion) +{ + struct utsname uts; + uint16_t maj, min, patch, rel; + int r = -EINVAL; + + if (uname(&uts) < 0) + return r; + + if (sscanf(uts.release, "%" SCNu16 ".%" SCNu16 ".%" SCNu16 "-%" SCNu16, + &maj, &min, &patch, &rel) == 4) + r = 0; + else if (sscanf(uts.release, "%" SCNu16 ".%" SCNu16 ".%" SCNu16, + &maj, &min, &patch) == 3) { + rel = 0; + r = 0; + } + + if (!r) + *kversion = version(maj, min, patch, rel); + + return r; +}