| #include <compartment-macros-asm.S> |
| #include <cheri-builtins.h> |
| #include "../allocator/token.h" |
| |
| .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 |
| |
| .p2align 1 |
| |
| /** |
| * The core of unsealing: |
| * |
| * void *token_unseal_internal( |
| * struct SKeyStruct *, struct SObjStruct *, void *); |
| */ |
| .Ltoken_unseal_internal: |
| /* |
| * Register allocation: |
| * |
| * - ca0 holds the user's sealing key, and is replaced with the unsealed |
| * value or NULL |
| * |
| * - ca1 holds the user's sealed object pointer |
| * |
| * - ca2 holds the unsealing authority and is clobbered on failure |
| * explicitly and on success with a scalar (the sealed payload's length) |
| * |
| * - a3 is used within each local computation and never holds secrets |
| */ |
| |
| /* Verify key tag */ |
| cgettag a3, ca0 |
| beqz a3, .Lexit_failure |
| |
| /* Verify key address == base and len > 0 */ |
| cgetbase a3, ca0 |
| bne a0, a3, .Lexit_failure // as-integer access to ca0 gives address |
| cgetlen a3, ca0 |
| beqz a3, .Lexit_failure |
| |
| /* Verify key has unseal permission */ |
| cgetperm a3, ca0 |
| andi a3, a3, CHERI_PERM_UNSEAL |
| beqz a3, .Lexit_failure |
| |
| /* Unseal, clobbering authority */ |
| cunseal ca2, ca1, ca2 |
| |
| /* Verify tag of unsealed form */ |
| cgettag a3, ca2 |
| beqz a3, .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 a3, TokenSObj_offset_type(ca2) |
| |
| /* Verify that the loaded value matches the address of the key. */ |
| bne a0, a3, .Lexit_failure |
| |
| /* Subset bounds to ->data */ |
| // Get the top into a3 |
| cgettop a3, 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, clobbering our unsealing key. |
| sub a2, a3, 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, a2 |
| |
| /* And that's an unwrap. */ |
| cret |
| |
| .Lexit_failure: |
| /* Failure; clobber potential sensitive state in ca2 and return null */ |
| zeroOne a2 |
| zeroOne a0 |
| cret |
| |
| /** |
| * An in-assembler implementation of |
| * |
| * [[cheri::interrupt_state(disabled)]] void *__cheri_libcall |
| * token_obj_unseal(struct SKeyStruct *, struct SObjStruct *); |
| * |
| * The name has been manually mangled as per the C++ rules. |
| */ |
| .hidden _Z16token_obj_unsealP10SKeyStructP10SObjStruct |
| .globl _Z16token_obj_unsealP10SKeyStructP10SObjStruct |
| _Z16token_obj_unsealP10SKeyStructP10SObjStruct: |
| 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 a3, ca1 |
| csetaddr ca2, ca2, a3 |
| |
| j .Ltoken_unseal_internal |
| |
| /** |
| * An in-assembler implementation of |
| * |
| * [[cheri::interrupt_state(disabled)]] void *__cheri_libcall |
| * token_obj_unseal_static(struct SKeyStruct *, struct SObjStruct *); |
| * |
| * The name has been manually mangled as per the C++ rules. |
| */ |
| .hidden _Z23token_obj_unseal_staticP10SKeyStructP10SObjStruct |
| .globl _Z23token_obj_unseal_staticP10SKeyStructP10SObjStruct |
| _Z23token_obj_unseal_staticP10SKeyStructP10SObjStruct: |
| LoadCapPCC ca2, __sealingkey_static |
| j .Ltoken_unseal_internal |
| |
| /** |
| * An in-assembler implementation of |
| * |
| * [[cheri::interrupt_state(disabled)]] void *__cheri_libcall |
| * token_obj_unseal_dynamic(struct SKeyStruct *, struct SObjStruct *); |
| * |
| * The name has been manually mangled as per the C++ rules. |
| */ |
| .hidden _Z24token_obj_unseal_dynamicP10SKeyStructP10SObjStruct |
| .globl _Z24token_obj_unseal_dynamicP10SKeyStructP10SObjStruct |
| _Z24token_obj_unseal_dynamicP10SKeyStructP10SObjStruct: |
| LoadCapPCC ca2, __sealingkey_dynamic |
| j .Ltoken_unseal_internal |
| |
| /* TODO: Eventually this goes away, when the assembler can generate it for us */ |
| CHERIOT_EXPORT_LIBCALL \ |
| _Z16token_obj_unsealP10SKeyStructP10SObjStruct, \ |
| 0 /* No stack usage */, \ |
| 0b00010010 /* IRQs deferred, zero two registers */ |
| |
| CHERIOT_EXPORT_LIBCALL \ |
| _Z23token_obj_unseal_staticP10SKeyStructP10SObjStruct, \ |
| 0 /* No stack usage */, \ |
| 0b00010010 /* IRQs deferred, zero two registers */ |
| |
| CHERIOT_EXPORT_LIBCALL \ |
| _Z24token_obj_unseal_dynamicP10SKeyStructP10SObjStruct, \ |
| 0 /* No stack usage */, \ |
| 0b00010010 /* IRQs deferred, zero two registers */ |