Documentation Index
Fetch the complete documentation index at: https://docs.z23.cc/llms.txt
Use this file to discover all available pages before exploring further.
OP-TEE Storage Migration and Versioning - Analysis
Overview
This document analyzes OP-TEE’s storage migration and versioning mechanisms, covering format versioning, backward compatibility, schema evolution, and migration strategies between different storage backends and versions.
RPMB File System Versioning
- Location:
/home/dzb/optee/optee_os/core/tee/tee_rpmb_fs.c
- Current Version: FS_VERSION = 2
- Magic Number: 0x52504D42 (“RPMB” in ASCII)
#define RPMB_FS_MAGIC 0x52504D42
#define FS_VERSION 2
struct rpmb_fs_partition {
uint32_t rpmb_fs_magic; // Magic: 0x52504D42
uint32_t fs_version; // Current: 2
uint32_t write_counter; // Anti-rollback counter
uint32_t fat_start_address; // File allocation table
uint8_t reserved[112]; // Future expansion
};
Hash Tree Compatibility
The hash tree implementation supports format evolution through configuration:
// Backward compatibility for hash sizes
if (IS_ENABLED(CFG_REE_FS_HTREE_HASH_SIZE_COMPAT)) {
// Use old 16-byte hash size for compatibility
aad_len += TEE_FS_HTREE_FEK_SIZE;
} else {
// Use full 32-byte SHA256 hash
aad_len += TEE_FS_HTREE_HASH_SIZE;
}
HUK Subkey Compatibility Layer
Hardware Unique Key derivation includes compatibility mode for legacy systems:
#ifdef CFG_CORE_HUK_SUBKEY_COMPAT
/*
* Special treatment for RPMB and SSK key derivations to give
* the same result as when huk_subkey_derive() wasn't used.
*/
static TEE_Result huk_compat(void *ctx, enum huk_subkey_usage usage)
{
uint8_t chip_id[TEE_FS_KM_CHIP_ID_LENGTH] = { 0 };
static uint8_t ssk_str[] = "ONLY_FOR_tee_fs_ssk";
switch (usage) {
case HUK_SUBKEY_RPMB:
return TEE_SUCCESS; // No additional data for RPMB
case HUK_SUBKEY_SSK:
// Legacy SSK derivation includes chip ID and salt
res = get_otp_die_id(chip_id, sizeof(chip_id));
if (res) return res;
res = crypto_mac_update(ctx, chip_id, sizeof(chip_id));
if (res) return res;
return crypto_mac_update(ctx, ssk_str, sizeof(ssk_str));
default:
return mac_usage(ctx, usage); // Standard derivation
}
}
#endif
Migration Between Storage Backends
REE File System Migration
The REE file system supports migration from non-integrity-protected to integrity-protected mode:
static TEE_Result open_dirh(struct tee_fs_dirfile_dirh **dirh)
{
uint32_t min_counter = 0;
// Attempt to get current counter value
res = nv_counter_get_ree_fs(&min_counter);
if (res) {
if (res != TEE_ERROR_NOT_IMPLEMENTED || !IS_ENABLED(CFG_INSECURE))
return res;
IMSG("WARNING (insecure configuration): Using counter 0");
min_counter = 0;
}
// Try to open existing directory file
res = tee_fs_dirfile_open(false, NULL, min_counter, &ree_dirf_ops, dirh);
if (res == TEE_ERROR_ITEM_NOT_FOUND) {
if (min_counter) {
if (!IS_ENABLED(CFG_REE_FS_ALLOW_RESET)) {
DMSG("dirf.db file not found");
return TEE_ERROR_SECURITY; // Prevent rollback
}
DMSG("dirf.db not found, initializing with non-zero counter");
}
// Create new directory file with current counter
return tee_fs_dirfile_open(true, NULL, min_counter, &ree_dirf_ops, dirh);
}
return res;
}
RPMB to REE Migration Strategy
While not directly implemented, the architecture supports migration through:
- Export Phase: Read all objects from source storage
- Key Preservation: Maintain FEK encryption for seamless transition
- Import Phase: Write objects to destination storage format
- Validation: Verify integrity of migrated data
Backward Compatibility Mechanisms
Configuration-Based Compatibility
Multiple compile-time flags control compatibility behavior:
// Configuration options for compatibility
CFG_REE_FS_HTREE_HASH_SIZE_COMPAT // Hash size compatibility
CFG_CORE_HUK_SUBKEY_COMPAT // HUK derivation compatibility
CFG_REE_FS_ALLOW_RESET // Allow counter reset
CFG_INSECURE // Debug/insecure mode
Directory entries use reserved space for future expansion:
struct dirfile_entry {
TEE_UUID uuid; // 16 bytes
uint8_t oid[TEE_OBJECT_ID_MAX_LEN]; // 64 bytes
uint32_t oidlen; // 4 bytes
uint8_t hash[TEE_FS_HTREE_HASH_SIZE]; // 32 bytes
uint32_t file_number; // 4 bytes
// Total: 120 bytes, room for expansion
};
Object ID Compatibility
Support for zero-length object IDs with special encoding:
#define OID_EMPTY_NAME 1
/*
* An object can have an ID of size zero. This object is represented by
* oidlen == 0 and oid[0] == OID_EMPTY_NAME. When both are zero, the entry is
* not a valid object.
*/
static bool is_free(struct dirfile_entry *dent)
{
assert(dent->oidlen || !dent->oid[0] || dent->oid[0] == OID_EMPTY_NAME);
return !dent->oidlen && !dent->oid[0];
}
Schema Evolution Strategies
Counter-Based Evolution
Monotonic counters provide migration checkpoints:
// Counter validation with minimum requirements
if (ht->head.counter < min_counter)
return TEE_ERROR_SECURITY; // Prevent rollback to old format
Versioned Storage Operations
Each storage backend can implement version-specific behavior:
struct tee_fs_htree_storage {
size_t block_size;
// Function pointers for version-specific operations
TEE_Result (*rpc_read_init)(void *aux, struct tee_fs_rpc_operation *op,
enum tee_fs_htree_type type, size_t idx,
uint8_t vers, void **data);
TEE_Result (*rpc_write_init)(void *aux, struct tee_fs_rpc_operation *op,
enum tee_fs_htree_type type, size_t idx,
uint8_t vers, void **data);
// ... additional operations
};
Test Infrastructure for Migration
Dedicated test framework for storage format validation:
// Location: /home/dzb/optee/optee_os/core/pta/tests/fs_htree.c
#define TEST_BLOCK_SIZE 144 // Minimum viable block size
// Test-specific storage layout
static TEE_Result test_get_offs_size(enum tee_fs_htree_type type, size_t idx,
uint8_t vers, size_t *offs, size_t *size)
{
// Implement test-specific layout for validation
switch (type) {
case TEE_FS_HTREE_TYPE_HEAD:
*offs = sizeof(struct tee_fs_htree_image) * vers;
*size = sizeof(struct tee_fs_htree_image);
return TEE_SUCCESS;
// ... handle other types
}
}
Version Detection and Negotiation
Magic Number Validation
Storage formats use magic numbers for identification:
// RPMB file system magic validation
if (partition->rpmb_fs_magic != RPMB_FS_MAGIC) {
EMSG("Invalid RPMB FS magic: 0x%x", partition->rpmb_fs_magic);
return TEE_ERROR_CORRUPT_OBJECT;
}
// Version compatibility check
if (partition->fs_version > FS_VERSION) {
EMSG("Unsupported FS version: %d > %d", partition->fs_version, FS_VERSION);
return TEE_ERROR_NOT_SUPPORTED;
}
Feature Detection
Runtime detection of storage capabilities:
// Detect RPMB device capabilities
struct rpmb_dev_info {
uint8_t cid[16]; // Card identification
uint8_t rpmb_size_mult; // Size multiplier
uint8_t rel_wr_sec_c; // Reliable write sector count
uint8_t ret_code; // Response code
};
Migration Safety Mechanisms
Atomic Migration Operations
Migration operations use the same atomic commit mechanisms:
- Preparation: Verify source and destination integrity
- Copy: Transfer data while maintaining encryption
- Verification: Validate copied data
- Commit: Atomically switch to new format
- Cleanup: Remove old format data
Rollback Protection
Counter mechanisms prevent rollback to older formats:
// Enforce minimum counter requirements
res = nv_counter_get_ree_fs(&min_counter);
if (res == TEE_SUCCESS) {
if (current_counter < min_counter) {
EMSG("Counter rollback detected: %d < %d", current_counter, min_counter);
return TEE_ERROR_SECURITY;
}
}
Storage behavior adapts to platform capabilities:
// RPMB availability detection
static TEE_Result rpmb_probe_reset(void)
{
res = thread_rpc_cmd(OPTEE_RPC_CMD_RPMB_PROBE_RESET, 1, params);
if (res) return res;
rpmb_ctx->legacy_operation = false;
rpmb_ctx->dev_id = 0;
switch (params[0].u.value.a) {
case OPTEE_RPC_SHM_TYPE_APPL:
rpmb_ctx->shm_type = THREAD_SHM_TYPE_APPLICATION;
return TEE_SUCCESS;
case OPTEE_RPC_SHM_TYPE_KERNEL:
rpmb_ctx->shm_type = THREAD_SHM_TYPE_KERNEL_PRIVATE;
return TEE_SUCCESS;
default:
return TEE_ERROR_GENERIC;
}
}
Legacy Operation Support
Support for older RPC protocols:
// Legacy vs. new RPC command selection
uint32_t cmd = OPTEE_RPC_CMD_RPMB_FRAMES;
if (rpmb_ctx->legacy_operation)
cmd = OPTEE_RPC_CMD_RPMB; // Use legacy command
return thread_rpc_cmd(cmd, 2, params);
Future Migration Considerations
Reserved Space Utilization
Storage structures include reserved space for future features:
struct rpmb_fs_partition {
// ... existing fields
uint8_t reserved[112]; // 112 bytes for future expansion
};
Hash tree headers can accommodate new metadata:
struct tee_fs_htree_imeta {
struct tee_fs_htree_meta meta; // Current metadata
uint32_t max_node_id; // Implementation detail
// Additional fields can be added here
};
Version-Specific Operations
Framework supports version-specific storage operations through function pointers, enabling smooth transitions between storage format versions while maintaining data integrity and security properties.
This migration and versioning architecture ensures OP-TEE storage can evolve while maintaining backward compatibility and data integrity across different storage backends and format versions.