Skip to content

Cryptfs fstrim + FDE fix #532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
May 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c0b2926
common/cryptfs: Fixed key length truncation for crypt only device
quitschbo Apr 7, 2025
d605dff
common/cryptfs: dm-integrity switch to internal_hash for discards
quitschbo Apr 4, 2025
dd0eda8
common/cryptfs: refactored error handling in create_device_node()
quitschbo Apr 14, 2025
1feab4d
daemon/container: helper container_images_dir_contains_image()
quitschbo Apr 22, 2025
1236931
daemon/c_vol: use non-stacked approach of common/cryptfs
quitschbo Apr 4, 2025
1c3a344
tpm2d/nvmcrypt: switch to new API of common/cryptfs
quitschbo Apr 11, 2025
d375cdc
common/cryptfs: introduce mode CRYPTFS_MODE_INTEGRITY_ONLY
quitschbo Apr 11, 2025
a04f812
daemon/c_vol: switch to new cryptfs API in c_vol_cleanup_dm()
quitschbo Apr 11, 2025
d44539c
daemon/c_vol: set DEBUG to WARN on failed device mapper delete
quitschbo Apr 14, 2025
8d46d72
daemon/c_vol: switch c0 images from AEAD to INTEGRITY_ONLY device
quitschbo Apr 22, 2025
845fe08
daemon/cmld: set a random key for the c0 for integrity protection
quitschbo Apr 22, 2025
afb0842
daemon/cmld: fix usage of correct variable to create keys dir
quitschbo Apr 22, 2025
e67f4c7
common/cryptfs: added mode CRYPTFS_MODE_NOT_IMPLEMENTED
quitschbo Apr 23, 2025
4ef416a
daemon/container: provide new API to get cryptfs mode
quitschbo Apr 23, 2025
eba5773
daemon/c_vol: implement container_get_cryptfs_mode helper
quitschbo Apr 23, 2025
09f6baa
daemon/control: show cryptfs mode of container in status message
quitschbo Apr 23, 2025
ab1a8a2
tpm2d: allow to build with flag NVMCRYPT_ONLY=y
quitschbo Apr 25, 2025
771d347
tpm2d/control: introduce FdeKeyType for dmcrpyt_setup message
quitschbo Apr 25, 2025
b7ec99b
tpm2d/nvmcrypt: truncate key to provided max_key_len
quitschbo Apr 25, 2025
bd70219
tpm2_control/Makefile: fixed linking order of libaries
quitschbo Apr 25, 2025
2cc24b9
tpm2_control/tpm2d_control: allow setting of key_len for FDE
quitschbo Apr 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
505 changes: 332 additions & 173 deletions common/cryptfs.c

Large diffs are not rendered by default.

18 changes: 16 additions & 2 deletions common/cryptfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@

#define CRYPTFS_FDE_KEY_LEN 64

/**
* Mode of encryption/integrity setup which should be used
*/
typedef enum {
CRYPTFS_MODE_NOT_IMPLEMENTED = 1,
CRYPTFS_MODE_AUTHENC,
CRYPTFS_MODE_ENCRYPT_ONLY,
CRYPTFS_MODE_INTEGRITY_ENCRYPT,
CRYPTFS_MODE_INTEGRITY_ONLY
} cryptfs_mode_t;

/**
* Get the full path of a cryptfs device with the specified name
*
Expand All @@ -52,20 +63,23 @@ cryptfs_get_device_path_new(const char *label);
* @param real_blk_dev The name of the loop device
* @param ascii_key The key for the volume
* @param meta_blk_dev The meta loop device
* @param mode mode used for encryption, e.g. stacked use of dm-crypt on dm-integrity
* with AEAD algorithm or individual dm-integrity and dm-crypt usage.
* @return char* The path of the newly created volume
*/
char *
cryptfs_setup_volume_new(const char *label, const char *real_blk_dev, const char *ascii_key,
const char *meta_blk_dev);
const char *meta_blk_dev, cryptfs_mode_t mode);

/**
* Close a device-mapper volume
*
* @param fd The filedescriptor of the device
* @param name The name of the device
* @param mode cryptfs mode which was used for the device with name 'name'
* @return int 0 if successful, otherwise -1
*/
int
cryptfs_delete_blk_dev(int fd, const char *name);
cryptfs_delete_blk_dev(int fd, const char *name, cryptfs_mode_t mode);

#endif /* CRYPTFS_H */
84 changes: 73 additions & 11 deletions daemon/c_vol.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ typedef struct c_vol {
const guestos_t *os;
mount_t *mnt;
mount_t *mnt_setup;
cryptfs_mode_t mode;
} c_vol_t;

/******************************************************************************/
Expand Down Expand Up @@ -140,7 +141,7 @@ c_vol_image_path_new(c_vol_t *vol, const mount_entry_t *mntent)
}

static char *
c_vol_meta_image_path_new(c_vol_t *vol, const mount_entry_t *mntent)
c_vol_meta_image_path_new(c_vol_t *vol, const mount_entry_t *mntent, const char *suffix)
{
const char *dir;

Expand All @@ -162,7 +163,8 @@ c_vol_meta_image_path_new(c_vol_t *vol, const mount_entry_t *mntent)
return NULL;
}

return mem_printf("%s/%s.meta.img", dir, mount_entry_get_img(mntent));
return mem_printf("%s/%s.meta.img%s", dir, mount_entry_get_img(mntent),
suffix ? suffix : "");
}

static char *
Expand Down Expand Up @@ -347,7 +349,7 @@ c_vol_create_image(c_vol_t *vol, const char *img, const mount_entry_t *mntent)
return 0;
case MOUNT_TYPE_OVERLAY_RW:
case MOUNT_TYPE_EMPTY: {
char *img_meta = c_vol_meta_image_path_new(vol, mntent);
char *img_meta = c_vol_meta_image_path_new(vol, mntent, NULL);
int ret = c_vol_create_image_empty(img, img_meta, mount_entry_get_size(mntent));
mem_free0(img_meta);
return ret;
Expand Down Expand Up @@ -858,16 +860,17 @@ c_vol_mount_image(c_vol_t *vol, const char *root, const mount_entry_t *mntent)
if (file_is_blk(crypt) || file_links_to_blk(crypt)) {
INFO("Using existing mapper device: %s", crypt);
} else {
DEBUG("Setting up cryptfs volume %s for %s", label, dev);
DEBUG("Setting up cryptfs volume %s for %s (%s)", label, dev,
vol->mode == CRYPTFS_MODE_AUTHENC ? "AUTHENC" : "INTEGRITY_ENCRYPT");

img_meta = c_vol_meta_image_path_new(vol, mntent);
img_meta = c_vol_meta_image_path_new(vol, mntent, NULL);
dev_meta = loopdev_create_new(&fd_meta, img_meta, 0, 0);

IF_NULL_GOTO(dev_meta, error);

mem_free0(crypt);
crypt = cryptfs_setup_volume_new(
label, dev, container_get_key(vol->container), dev_meta);
label, dev, container_get_key(vol->container), dev_meta, vol->mode);

// release loopdev fd (crypt device should keep it open now)
close(fd_meta);
Expand Down Expand Up @@ -1094,12 +1097,12 @@ c_vol_cleanup_dm(c_vol_t *vol)

DEBUG("Cleanup: removing block device %s of type %s\n", label, type);

if (!strcmp(type, "crypt")) {
if (cryptfs_delete_blk_dev(fd, label) < 0)
DEBUG("Could not delete dm-crypt dev %s", label);
if (!strcmp(type, "crypt") || !strcmp(type, "integrity")) {
if (cryptfs_delete_blk_dev(fd, label, vol->mode) < 0)
WARN("Could not delete dm-%s dev %s", type, label);
} else if (!strcmp(type, "verity")) {
if (verity_delete_blk_dev(label) < 0)
DEBUG("Could not delete dm-verity dev %s", label);
WARN("Could not delete dm-verity dev %s", label);
}
mem_free0(label);
mem_free0(type);
Expand Down Expand Up @@ -1430,6 +1433,40 @@ c_vol_verify_mount_entries_bg(const c_vol_t *vol)
return true;
}

/*
* If images_dir does not have stacked images, persist policy without stacking
* using cryptfs_mode INTEGRITY_ENCRYPT to support TRIM on SSDs.
* Call this function on container start to allow switching the policy by container
* wipe.
*/
static void
c_vol_set_dm_mode(c_vol_t *vol)
{
ASSERT(vol);

const char *images_dir = container_get_images_dir(vol->container);
ASSERT(images_dir);

bool is_c0 = container_uuid_is_c0id(container_get_uuid(vol->container));

char *not_stacked_file = mem_printf("%s/not-stacked", images_dir);
if (file_exists(not_stacked_file)) {
TRACE("file exists %s %s", not_stacked_file,
is_c0 ? "(c0) -> CRYPTFS_MODE_INTEGRITY_ONLY" :
"-> CRYPTFS_MODE_INTEGRITY_ENCRYPT");
vol->mode = is_c0 ? CRYPTFS_MODE_INTEGRITY_ONLY : CRYPTFS_MODE_INTEGRITY_ENCRYPT;
} else if (container_images_dir_contains_image(vol->container)) {
TRACE("previous image files exists -> CRYPTFS_MODE_AUTHENC");
vol->mode = CRYPTFS_MODE_AUTHENC;
} else {
TRACE("new image files %s", is_c0 ? "(c0) -> CRYPTFS_MODE_INTEGRITY_ONLY" :
"-> CRYPTFS_MODE_INTEGRITY_ENCRYPT");
vol->mode = is_c0 ? CRYPTFS_MODE_INTEGRITY_ONLY : CRYPTFS_MODE_INTEGRITY_ENCRYPT;
file_touch(not_stacked_file);
}
mem_free0(not_stacked_file);
}

/******************************************************************************/

static void *
Expand Down Expand Up @@ -1603,6 +1640,18 @@ c_vol_start_child_early(void *volp)
return -COMPARTMENT_ERROR_VOL;
}

static int
c_vol_start_pre_clone(void *volp)
{
c_vol_t *vol = volp;
ASSERT(vol);

// set device mapper mode for data integrity and encryption
c_vol_set_dm_mode(vol);

return 0;
}

static int
c_vol_start_post_clone(void *volp)
{
Expand Down Expand Up @@ -1963,6 +2012,18 @@ c_vol_is_encrypted(void *volp)
return false;
}

static cryptfs_mode_t
c_vol_get_mode(void *volp)
{
c_vol_t *vol = volp;
ASSERT(vol);

// update internal mode variable if container did not run or was wiped
c_vol_set_dm_mode(vol);

return vol->mode;
}

static void
c_vol_cleanup(void *volp, bool is_rebooting)
{
Expand All @@ -1984,7 +2045,7 @@ static compartment_module_t c_vol_module = {
.compartment_destroy = NULL,
.start_post_clone_early = NULL,
.start_child_early = c_vol_start_child_early,
.start_pre_clone = NULL,
.start_pre_clone = c_vol_start_pre_clone,
.start_post_clone = c_vol_start_post_clone,
.start_pre_exec = c_vol_start_pre_exec,
.start_post_exec = NULL,
Expand All @@ -2006,4 +2067,5 @@ c_vol_init(void)
container_register_get_rootdir_handler(MOD_NAME, c_vol_get_rootdir);
container_register_get_mnt_handler(MOD_NAME, c_vol_get_mnt);
container_register_is_encrypted_handler(MOD_NAME, c_vol_is_encrypted);
container_register_get_cryptfs_mode_handler(MOD_NAME, c_vol_get_mode);
}
9 changes: 9 additions & 0 deletions daemon/cc_mode/container.proto
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ enum ContainerTrust {
UNSIGNED = 3;
}

enum CryptfsMode {
NOT_IMPLEMENTED = 1;
AUTHENC = 2;
ENCRYPT_ONLY = 3;
INTEGRITY_ENCRYPT = 4;
INTEGRITY_ONLY = 5;
}

/**
* Represents the status of a single container.
*/
Expand All @@ -176,5 +184,6 @@ message ContainerStatus {
required uint64 created = 6;
required string guestos = 7;
required ContainerTrust trust_level = 8;
required CryptfsMode cryptfs_mode = 9;
/* TBD more state values */
}
74 changes: 70 additions & 4 deletions daemon/cmld.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "common/dir.h"
#include "common/network.h"
#include "common/reboot.h"
#include "common/hex.h"
#include "mount.h"
#include "device_config.h"
#include "device_id.h"
Expand All @@ -60,6 +61,7 @@
#include "container.h"
#include "input.h"
#include "oci.h"
#include "crypto.h"

#include <inttypes.h>
#include <stdio.h>
Expand Down Expand Up @@ -96,12 +98,14 @@
#define CMLD_KSM_AGGRESSIVE_TIME_AFTER_CONTAINER_BOOT 70000

/*
* dummy key used for unecnrypted c0 and for reboots where the real key
* is already in kernel
* dummy key used for unencrypted c0 (legacy dm ondisk format)
* and for reboots where the real key is already in kernel
*/
#define DUMMY_KEY \
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

#define CMLD_C0_KEY_BUF_SIZE 256
#define CMLD_C0_KEY_LEN 32
#define CMLD_C0_UUID "00000000-0000-0000-0000-000000000000"

static const char *cmld_path = DEFAULT_BASE_PATH;
Expand Down Expand Up @@ -1283,6 +1287,67 @@ cmld_init_c0(const char *path, const char *c0os)
return 0;
}

static int
cmld_set_key_c0(container_t *new_c0)
{
int ret = -1;

int c0_key_len;
char *c0_key, *c0_ascii_key;

char *c0_key_file = mem_printf("%s/%s.key", cmld_get_wrapped_keys_dir(), CMLD_C0_UUID);
if (file_exists(c0_key_file)) {
c0_key = mem_alloc0(CMLD_C0_KEY_BUF_SIZE);
c0_key_len = file_read(c0_key_file, c0_key, CMLD_C0_KEY_BUF_SIZE);
if (c0_key_len < CMLD_C0_KEY_LEN) {
ERROR("Failed to read key from %s for c0", c0_key_file);
goto out;
}
} else {
if (container_images_dir_contains_image(new_c0)) {
// set legacy mode where we used the dummy key for c0
c0_key_len = strlen(DUMMY_KEY) / 2;
c0_key = mem_alloc0(c0_key_len);
if (convert_hex_to_bin(DUMMY_KEY, strlen(DUMMY_KEY), (uint8_t *)c0_key,
c0_key_len) < 0) {
ERROR("Failed to generate key for c0 (using legacy DUMMY_KEY)");
goto out;
}
} else {
// for new images we use a random key for integrity protection of c0
c0_key_len = CMLD_C0_KEY_LEN;
c0_key = mem_alloc0(c0_key_len);
int bytes_read = crypto_random_get_bytes((uint8_t *)c0_key, c0_key_len);
if (bytes_read != c0_key_len) {
ERROR("Failed to generate key for c0");
goto out;
}
}

int bytes_written = file_write(c0_key_file, c0_key, c0_key_len);
if (bytes_written != c0_key_len) {
ERROR("Failed to write c0 key to file, bytes written: %d", bytes_written);
goto out;
}
}

c0_ascii_key = convert_bin_to_hex_new((uint8_t *)c0_key, c0_key_len);
container_set_key(new_c0, c0_ascii_key);

mem_memset0(c0_key, c0_key_len);
mem_memset0(c0_ascii_key, strlen(c0_ascii_key));
mem_free0(c0_ascii_key);

ret = 0;

out:
if (c0_key)
mem_free0(c0_key);
mem_free0(c0_key_file);

return ret;
}

static int
cmld_start_c0(container_t *new_c0)
{
Expand All @@ -1306,7 +1371,8 @@ cmld_start_c0(container_t *new_c0)
return -1;
}

container_set_key(new_c0, DUMMY_KEY);
IF_TRUE_RETVAL_ERROR(cmld_set_key_c0(new_c0), -1);

if (container_start(new_c0)) {
audit_log_event(container_get_uuid(new_c0), FSA, CMLD, CONTAINER_MGMT, "c0-start",
uuid_string(container_get_uuid(new_c0)), 0);
Expand Down Expand Up @@ -1533,7 +1599,7 @@ cmld_init(const char *path)
FATAL_ERRNO("Could not mkdir containers directory %s", containers_path);

cmld_wrapped_keys_path = mem_printf("%s/%s", path, CMLD_PATH_CONTAINER_KEYS_DIR);
if (mkdir(containers_path, 0700) < 0 && errno != EEXIST)
if (mkdir(cmld_wrapped_keys_path, 0700) < 0 && errno != EEXIST)
FATAL_ERRNO("Could not mkdir container keys directory %s", containers_path);

if (cmld_init_c0(containers_path, device_config_get_c0os(device_config)) < 0)
Expand Down
17 changes: 17 additions & 0 deletions daemon/container.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,20 @@ container_get_images_dir(const container_t *container)
return container->images_dir;
}

static int
container_images_exist_cb(UNUSED const char *path, const char *name, UNUSED void *data)
{
int len = strlen(name);
return (len >= 4 && !strcmp(name + len - 4, ".img")) ? 1 : 0;
}

bool
container_images_dir_contains_image(const container_t *container)
{
ASSERT(container);
return dir_foreach(container->images_dir, container_images_exist_cb, NULL) > 0;
}

static int
container_wipe_image_cb(const char *path, const char *name, UNUSED void *data)
{
Expand Down Expand Up @@ -970,6 +984,9 @@ CONTAINER_MODULE_REGISTER_WRAPPER_IMPL(get_rootdir, char *, void *)
CONTAINER_MODULE_FUNCTION_WRAPPER_IMPL(get_rootdir, char *, NULL)
CONTAINER_MODULE_REGISTER_WRAPPER_IMPL(get_mnt, void *, void *)
CONTAINER_MODULE_FUNCTION_WRAPPER_IMPL(get_mnt, void *, NULL)
CONTAINER_MODULE_REGISTER_WRAPPER_IMPL(get_cryptfs_mode, cryptfs_mode_t, void *)
CONTAINER_MODULE_FUNCTION_WRAPPER_IMPL(get_cryptfs_mode, cryptfs_mode_t,
CRYPTFS_MODE_NOT_IMPLEMENTED)
CONTAINER_MODULE_REGISTER_WRAPPER_IMPL(is_encrypted, bool, void *)
CONTAINER_MODULE_FUNCTION_WRAPPER_IMPL(is_encrypted, bool, false)

Expand Down
Loading