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).
This commit is contained in:
Ondrej Kozina
2018-01-15 16:03:08 +01:00
committed by Milan Broz
parent d12fb3d6e1
commit 598dd672bc
3 changed files with 42 additions and 1 deletions

View File

@@ -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 */

View File

@@ -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);
}

View File

@@ -30,6 +30,7 @@
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#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;
}