token_unseal: wield three unsealing authorities
diff --git a/sdk/core/loader/boot.cc b/sdk/core/loader/boot.cc index 9aabbb0..bc67535 100644 --- a/sdk/core/loader/boot.cc +++ b/sdk/core/loader/boot.cc
@@ -1267,15 +1267,31 @@ sizeof(void *), PermissionSet{Permission::Global, Permission::Unseal}); - setSealingKey(imgHdr.allocator(), Allocator); + /* + * The token library unseals both static and dynamic objects, sometimes + * either and sometimes with static knowledge of which is expected. To + * avoid `li; csetaddr; csetbounds` sequences, we give it a separate cap + * for each case. + */ setSealingKey(imgHdr.token_library(), Allocator, 2, // Allocator and StaticToken 0, PermissionSet{Permission::Global, Permission::Unseal}); + setSealingKey(imgHdr.token_library(), + StaticToken, + 1, + sizeof(void *), + PermissionSet{Permission::Global, Permission::Unseal}); + setSealingKey(imgHdr.token_library(), + Allocator, + 1, + 2 * sizeof(void *), + PermissionSet{Permission::Global, Permission::Unseal}); + constexpr size_t DynamicSealingLength = std::numeric_limits<ptraddr_t>::max() - FirstDynamicSoftware + 1; - + setSealingKey(imgHdr.allocator(), Allocator); setSealingKey(imgHdr.allocator(), FirstDynamicSoftware, DynamicSealingLength,
diff --git a/sdk/core/token_library/token_unseal.S b/sdk/core/token_library/token_unseal.S index 1dccc04..8528d72 100644 --- a/sdk/core/token_library/token_unseal.S +++ b/sdk/core/token_library/token_unseal.S
@@ -2,15 +2,34 @@ #include <cheri-builtins.h> #include "../allocator/token.h" - .hidden __sealingkey - .type __sealingkey,@object - .section .sealing_key1,"aw",@progbits - .globl __sealingkey - .p2align 3 -__sealingkey: - .chericap 0 - .size __sealingkey, 8 +.include "assembly-helpers.s" + .hidden __sealingkey_either + .type __sealingkey_either,@object + .section .sealing_key1,"aw",@progbits + .globl __sealingkey_either + .p2align 3 +__sealingkey_either: + .chericap 0 + .size __sealingkey_either, 8 + + .hidden __sealingkey_static + .type __sealingkey_static,@object + .section .sealing_key2,"aw",@progbits + .globl __sealingkey_static + .p2align 3 +__sealingkey_static: + .chericap 0 + .size __sealingkey_static, 8 + + .hidden __sealingkey_dynamic + .type __sealingkey_dynamic,@object + .section .sealing_key3,"aw",@progbits + .globl __sealingkey_dynamic + .p2align 3 +__sealingkey_dynamic: + .chericap 0 + .size __sealingkey_dynamic, 8 .section .text,"ax",@progbits @@ -19,21 +38,20 @@ /** * The core of unsealing: * - * void *token_unseal_internal(struct SKeyStruct *, struct SObjStruct *, int); + * void *token_unseal_internal( + * struct SKeyStruct *, struct SObjStruct *, void *); */ - .Ltoken_unseal_internal: /* * Register allocation: * - * - ca0 holds a sealing key, either the user's or the real deal, and is - * replaced with the unsealed value or NULL + * - ca0 holds the user's sealing key, and is replaced with the unsealed + * value or NULL * * - ca1 holds the user's sealed object pointer * - * - a2 contains the expected sealing type. - * - * - t0 holds a copy of the user key's address field (authorized type) + * - ca2 holds the unsealing authority and is clobbered on failure + * explicitly and on success with a scalar (the sealed payload's length) * * - t1 is used within each local computation and never holds secrets */ @@ -53,53 +71,41 @@ andi t1, t1, CHERI_PERM_UNSEAL beqz t1, .Lexit_failure - /* Copy key type to scratch register */ - cgetaddr t0, ca0 - - /* - * Load unsealing root capability, to be clobbered by return value - * This faults only if something has gone very, very wrong, and exposes no - * secrets if so. - */ -.Lload_sealing_key: - auipcc ca0, %cheriot_compartment_hi(__sealingkey) - clc ca0, %cheriot_compartment_lo_i(.Lload_sealing_key)(ca0) - csetaddr ca0, ca0, a2 - /* Unseal, clobbering authority */ - cunseal ca0, ca1, ca0 + cunseal ca2, ca1, ca2 /* Verify tag of unsealed form */ - cgettag t1, ca0 + cgettag t1, ca2 beqz t1, .Lexit_failure /* * Load software type tag. This will not trap, thanks to above tag check and * because IRQs are deferred (see our export entry below) */ - clw t1, TokenSObj_offset_type(ca0) + clw t1, TokenSObj_offset_type(ca2) /* Verify that the loaded value matches the address of the key. */ - bne t0, t1, .Lexit_failure + bne a0, t1, .Lexit_failure /* Subset bounds to ->data */ // Get the top into t1 - cgettop t1, ca0 - // Move the address to the start of the data - cincoffset ca0, ca0, TokenSObj_offset_data + cgettop t1, ca2 + // Move the address to the start of the data, clobber the user's sealing key + cincoffset ca0, ca2, TokenSObj_offset_data // Subtract the address of the (to-be-returned-unsealed) data from the top to - // give the length. - sub t1, t1, a0 + // give the length, clobbering our unsealing key. + sub a2, t1, a0 // Set the new bounds, using an exact setting so that any errors in the // allocator's alignment turn into an untagged capability here. - csetboundsexact ca0, ca0, t1 + csetboundsexact ca0, ca0, a2 /* And that's an unwrap. */ cret .Lexit_failure: - /* Failure; clobber potential sensitive state in ca0 and return null */ - cmove ca0, cnull + /* Failure; clobber potential sensitive state in ca2 and return null */ + zeroOne a2 + zeroOne a0 cret /** @@ -113,7 +119,16 @@ .hidden _Z16token_obj_unsealP10SKeyStructP10SObjStruct .globl _Z16token_obj_unsealP10SKeyStructP10SObjStruct _Z16token_obj_unsealP10SKeyStructP10SObjStruct: - cgettype a2, ca1 + LoadCapPCC ca2, __sealingkey_either + + /* + * Backwards compatibility with CUnseal that requires address match. + * This can (and should) be removed once everyone's caught up with + * https://github.com/CHERIoT-Platform/cheriot-sail/pull/87 . + */ + cgettype t1, ca1 + csetaddr ca2, ca2, t1 + j .Ltoken_unseal_internal /** @@ -127,8 +142,8 @@ .hidden _Z23token_obj_unseal_staticP10SKeyStructP10SObjStruct .globl _Z23token_obj_unseal_staticP10SKeyStructP10SObjStruct _Z23token_obj_unseal_staticP10SKeyStructP10SObjStruct: - li a2, CheriSealTypeStaticToken - j .Ltoken_unseal_internal + LoadCapPCC ca2, __sealingkey_static + j .Ltoken_unseal_internal /** * An in-assembler implementation of @@ -138,11 +153,11 @@ * * The name has been manually mangled as per the C++ rules. */ - .hidden _Z16token_obj_unsealP10SKeyStructP10SObjStruct - .globl _Z16token_obj_unsealP10SKeyStructP10SObjStruct + .hidden _Z24token_obj_unseal_dynamicP10SKeyStructP10SObjStruct + .globl _Z24token_obj_unseal_dynamicP10SKeyStructP10SObjStruct _Z24token_obj_unseal_dynamicP10SKeyStructP10SObjStruct: - li a2, CheriSealTypeAllocator - j .Ltoken_unseal_internal + LoadCapPCC ca2, __sealingkey_dynamic + j .Ltoken_unseal_internal /* TODO: Eventually this goes away, when the assembler can generate it for us */ CHERIOT_EXPORT_LIBCALL \