From ebb04bccd5c16dd600602c3599e9ecffc964a0e2 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Wed, 15 Nov 2023 15:36:56 +0800 Subject: [PATCH 01/15] faq: sealed capabilities --- faq/index.rst | 1 + faq/sealed_capabilities.rst | 343 ++++++++++++++++++++++++++++++++++++ 2 files changed, 344 insertions(+) create mode 100644 faq/sealed_capabilities.rst diff --git a/faq/index.rst b/faq/index.rst index dfdb825..64cf7b5 100644 --- a/faq/index.rst +++ b/faq/index.rst @@ -19,6 +19,7 @@ when working with CHERI software? installing_gdb printf purecap_or_hybrid_binary + sealed_capabilities python running shared_library_path diff --git a/faq/sealed_capabilities.rst b/faq/sealed_capabilities.rst new file mode 100644 index 0000000..3f639a6 --- /dev/null +++ b/faq/sealed_capabilities.rst @@ -0,0 +1,343 @@ +What is a Sealed Capability +=========================== + +Capability +---------- + +A capability is a token of authority over a continuous memory space. It associates traditional +pointers with a set of permissions and properties. Capabilities are unforgeable and unguessable, +and can be passed around between threads and processes. A capability have the following properties: +`[1] `_ + +- Value: memory location address (the conventional pointer address). +- Tag: indicates if a capability is valid (and whether it can be dereferenced, i.e., used as a base address in a memory reference). +- Bounds: base, limit, validity (the latter shows whether current combination of base, value and limit are correctly encoded). Bounds make up a semi-closed interval where base is included, and limit is not. +- Global / Local: a property that shows whether a capability is global or local (ha-ha, see below though). +- Permissions: they control operations that are available via this capability (see below). +- Executable / System access / Executive: bits that define and describe executability of a capability. +- Object type: a property related to sealing of capabilities (see below). +- Flags: application defined bits. + +You can follow the example code below if you have a Morello board or MorelloIE, the Morello +Instruction Emulator. You can use the prebuilt MorelloIE Docker image, ``cocoaxu/morelloie``, +for a quick start. + + +.. code-block:: shell + + $ docker run -it --rm cocoaxu/morelloie + + +Inside this Docker image, ``morelloie`` and ``clang`` are available. Besides that, a sysroot +directory for Purecap can be found at ``/root/musl-sysroot-purecap``, which can be used later +when compiling Purecap Morello programs with clang. + +After compiling the example code, you can use ``morelloie`` to run your program. For example, +let's say that we have the following ``func.c`` program: + + +.. code-block:: C + + // func.c + #include + + void func() { } + + int main(int argc, char *argv[]) + { + void *cap1 = fun; + void *cap2 = cap1 + 1; + printf("%#p\n", cap1); + printf("%#p\n", cap2); + } + + +We'll mention the ``%#p`` format specifier later once we saw the output. Now we can +compile it with ``clang`` using the following command, where we specify the target +as ``aarch64-linux-musl_purecap`` and the sysroot as ``/root/musl-sysroot-purecap``: + +.. code-block:: shell + + $ clang -march=morello \ + --target=aarch64-linux-musl_purecap \ + --sysroot=/root/musl-sysroot-purecap \ + func.c -o func -static + + +To run the program, we can use ``morelloie``: + +.. code-block:: shell + + $ morelloie -- ./func + 0x211545 [rxRE,0x200200-0x226c40] (sentry) + 0x211546 [rxRE,0x200200-0x226c40] (invalid,sentry) + + +The ``%#p`` format specifier is used to print a capability pointer in hexadecimal format along with some +properties of this capability pointer, which contains its address (``0x211545``), permissions (``rxRE``), +and the semi-closed memory range (``[base, limit)``) that the capability points to (``0x200200-0x226c40``). +And some extra information like the ``sentry`` keyword at the end of the output. + +The permissions part of a capability determine what operations are allowed via this capability, and they can +be grouped into the following categories: `[2] `_ + +- data access (reading from and writing to memory), +- permission-like bits that aren't permissions per se but act like they in terms of monotonicity, +- code execution (this includes loading code from memory as well), +- custom permissions for specific use cases (such as compartment switches). + +So the first line of the output shows that the first capability ``cap1`` points to the function ``func`` and +the second capability ``cap2`` points to the next byte after the function ``func``. The permissions of the +first capability ``cap1`` is ``rxRE``, which means that it is readable, executable, and has the ``RE`` property. +The ``RE`` property means that the capability is sealed, which means that it cannot be modified. + +The ``sentry`` property means that the capability is a sentry capability, which means that it is a capability +that is used to protect the memory space of the program. The ``sentry`` property is only available in Purecap +Morello. + +Usually, we don't need to explicitly change the permissions of a capability because the compiler and other +runtime library will do it. However, if you're in a situation where you need to have finer grained control over +the permissions of a capability, you can do that with builtin functions provided in ``cheriintrin.h``. For example, + +.. code-block:: C + + #include + #include + #include + + #define LOAD __CHERI_CAP_PERMISSION_PERMIT_LOAD__ + #define LOAD_CAP __CHERI_CAP_PERMISSION_PERMIT_LOAD_CAPABILITY__ + #define MUTABLE_LOAD __ARM_CAP_PERMISSION_MUTABLE_LOAD__ + + #define STORE __CHERI_CAP_PERMISSION_PERMIT_STORE__ + #define STORE_CAP __CHERI_CAP_PERMISSION_PERMIT_STORE_CAPABILITY__ + #define STORE_LOCAL __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__ + + void untrusted_3rd_party_func(char *str); + + int main() + { + char *str = malloc(sizeof(char) * 32); + char *ro_str = cheri_perms_and(str, LOAD | LOAD_CAP | MUTABLE_LOAD); + printf("str in main : %#p\n", str); + printf("ro_str in main: %#p\n", str); + untrusted_3rd_party_func(ro_str); + } + + void untrusted_3rd_party_func(char *str) + { + printf("str in func : %#p\n", str); + str[0] = 'A'; + } + + +In the example above, we have some macros that are used to define the permissions of a capability: +`[3] `_ + +- LOAD: read data (non-capability) from memory, +- LOAD_CAP: read a capability from memory, +- MUTABLE_LOAD: read a capability with permissions allowing mutable operations, +- STORE: write data (non-capability) to memory, +- STORE_CAP: write a capability, +- STORE_LOCAL: write a local capability (without this permission in the memory reference a local capability cannot be stored). + +As we want to make sure that the ``untrusted_3rd_party_func`` cannot modify the string, we use the builtin function +``cheri_perms_and`` to create a new capability ``ro_str`` that only has the ``LOAD``, ``LOAD_CAP`` and ``MUTABLE_LOAD`` +permissions. The ``LOAD`` permission means that the capability can be used to load data from memory. As for the +``LOAD_CAP`` and ``MUTABLE_LOAD`` permissions, they're used when we want to control access via copies of the +capabilities that are shared with other components of our program. + + +If we compile the example above and run it with ``morelloie``, we will get the following output: + +.. code-block:: shell + + $ clang -march=morello \ + --target=aarch64-linux-musl_purecap \ + --sysroot=/root/musl-sysroot-purecap \ + str.c -o str -static + $ morelloie -- ./str + str in main : 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] + ro_str in main: 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] + str in func : 0xffff80b98040 [rR,0xffff80b98040-0xffff80b98060] + [emulator] simulated capability fault at 2116b4 in thread 402 + Insufficient permissions (required ----w-------------) + 0x1:90100000:40608040:0000ffff:80b98040 + tag: true + address: 0x00000ffff80b98040 + base: 0x00000ffff80b98040 + limit: 0x00000ffff80b98060 + bounds: valid + in bounds: true + length: 32 + offset: 0 + permissions: -rRM-------------- + sealed: (not sealed) + flags: 0 + exponent: 0 + top: 0x8060 + bottom: 0x8040 + local: true + Segmentation fault + + +As we can see, the capability ``ro_str`` has the ``rR`` permissions, which means that it can be used to read data, +but cannot be used to write data. And when we try to modify the string in the ``untrusted_3rd_party_func``, the +Mollore Instruction Emulator will raise a capability fault with a hint telling us that the capability ``ro_str`` +does not have the ``w`` permission, which is necessay for writing data to memory. + +Sealed Capabilities +------------------- + +Before we dive into the details of these capabilities in the ``func`` program above, let's talk +about what a sealed capability is. In CHERI and Morello, a capability can be sealed, and in simple +words, a sealed capability is a capability with a non-zero object type. + +The object type is a 16-bit field in Morello, and there're 4 special values for the object type: + +- ``0x0000``: the capability is not sealed. +- ``0x0001``: the capability is RB-sealed and used for all conventional register branch. +- ``0x0002``: the capability is LPB-sealed, which is used for load pair and branch operations (relevant to compartments). +- ``0x0003``: the capability is LB-sealed and used for load and branch operations (relevant to compartments). + +The RB-, LPB- and LB-sealed capabilities are also referred to as "fixed" or "hardware" types. + +There are 4 consequences for sealing a capability: + +- Once the capability is sealed, it will be immutable. Any operations that modify the capability + will result in an invalid capability. +- A sealed capability cannot be dereferenced, that is, we cannot read or write the memory that + the capability points to. +- Also, branching to an executable but sealed capability will fault. Notice RB-, LPB- and LB-sealed + capabilities will be automatically unsealed during the corresponding branch operation. +- Lastly, a sealed capability cannot be used to seal another capability even when meeting all other + requirements for a sealing capability. + +There are also other values for the object type, which are used for sealing capabilities, but we +will not cover them here. + +RB-sealed Capabilities +---------------------- + +If we break at the ``printf`` function in the example above and as ``cap1`` is the second parameter +for ``printf``, it's stored in the register ``c1``. Hence we can do ``p c1`` to inspect the first +capability, ``cap1``, in the debugger: + +.. code-block:: shell + + $ morelloie -break printf -- ./func + /* next instruction (211c18:printf) */ + /* 211c18 0280c3ff sub csp, csp, #48, lsl #0 */ + [281:211c18] p c1 + c1 = 0x1:b090c000:8d9f0044:00000000:00211545 + tag: true + address: 0x00000000000211545 + base: 0x00000000000200200 + limit: 0x00000000000226cc0 + bounds: valid + in bounds: true + length: 158400 + offset: 70469 + permissions: GrRM---xES-------- + sealed: sealed RB (1) + ... + [281:211bec] c + 0x211545 [rxRE,0x200200-0x226c80] (sentry) + + +The output shows that if we take the address of a function, it will result in a RB-sealed +capability (``sealed RB (1)``). And the sentry keyword outputted by printf also suggested +that what we see is an executable capability that is sealed with the RB object type. + +The second capability ``cap2`` is invalid because it was created by adding 1 to the first +capability ``cap1``, and once we do any arithmetic operations on a sealed capability, the +resulting capability will be invalid, as shown in the output above (``(sentry, invalid)``). +If we try to print the second capability ``cap2`` in the debugger, we will get the following +output: + +.. code-block:: shell + + $ morelloie -break printf -- ./func + ... + [293:211bc8] p c1 + c1 = 0x1:dc104000:5f40df30:0000ffff:f063df30 + tag: true + address: 0x00000fffff063df30 + base: 0x00000fffff063df30 + limit: 0x00000fffff063df40 + bounds: valid + in bounds: true + length: 16 + offset: 0 + permissions: GrRMwWL----------- + sealed: (not sealed) + ... + [293:211bc8] c + 0x211546 [rxRE,0x200200-0x226c40] (invalid,sentry) + + +Notice that the second capability ``cap2`` is not sealed anymore, and its permissions have +also changed. It's no longer executable, meaning that we cannot jump right in the middle +of the function ``func``. In this way, we can + +Another example is the capability holding return address (link register), which is the register +``c30``. If we break at the ``printf`` function and inspect the capability holding the return +address, we will get the following output: + +.. code-block:: shell + + $ morelloie -break printf -- ./func + /* next instruction (211bc8:printf) */ + /* 211bc8 0280c3ff sub csp, csp, #48, lsl #0 */ + [294:211bc8] p clr + clr = 0x1:b090c000:8d8f0044:00000000:0021159d + tag: true + address: 0x0000000000021159d + base: 0x00000000000200200 + limit: 0x00000000000226c40 + bounds: valid + in bounds: true + length: 158272 + offset: 70557 + permissions: GrRM---xES-------- + sealed: sealed RB (1) + ... + + +The output shows that the return address is also a RB-sealed capability. This means that +the return address is also protected by the sentry. If we try to modify the return address, +the program will crash. And this is how Morello protects the control flow of a program. + +LPB- and LB-sealed Capabilities +------------------------------- + +For LPB- and LB-sealed capabilities, they are used for load pair and branch operations. In +order to create a LPB- or LB-sealed capability, we need to use inline assembly for this: + +.. code-block:: C + + inline __attribute__ ((naked)) + void *__morello_seal_lpb(void *cap) + { + void *ret; + __asm__ ("seal %0, %1, lpb" : "=C"(ret) : "C"(cap)); + return ret; + } + + inline __attribute__ ((naked)) + void *__morello_seal_lb(void *cap) + { + void *ret; + __asm__ ("seal %0, %1, lb" : "=C"(ret) : "C"(cap)); + return ret; + } + + +The ``seal`` instruction is used to seal a capability. The first operand is the destination +register, and the second operand is the source register. The third operand is the sealing +type, which can be ``lpb`` or ``lb``. These sealing types are used for sealing a capability +with the LPB and LB object types, respectively. + +You can read the `["Hello World" Example] `_ +in the Morello Compartmentalisation section. It shows how to use LPB- and LB-sealed capabilities +to compartmentalise a program. From 0d0872ff6cdc4e959a110224489e8919d5a12845 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Wed, 15 Nov 2023 18:13:24 +0800 Subject: [PATCH 02/15] updated the description for the `%#p` format specifier --- faq/sealed_capabilities.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/faq/sealed_capabilities.rst b/faq/sealed_capabilities.rst index 3f639a6..b89a178 100644 --- a/faq/sealed_capabilities.rst +++ b/faq/sealed_capabilities.rst @@ -74,9 +74,17 @@ To run the program, we can use ``morelloie``: The ``%#p`` format specifier is used to print a capability pointer in hexadecimal format along with some -properties of this capability pointer, which contains its address (``0x211545``), permissions (``rxRE``), -and the semi-closed memory range (``[base, limit)``) that the capability points to (``0x200200-0x226c40``). -And some extra information like the ``sentry`` keyword at the end of the output. +properties and attributes of this capability pointer. It prints the capability pointer in the following +format: + +.. code-block:: text + +
[,-] () + + +which contains its address (``0x211545``), permissions (``rxRE``), and the semi-closed memory range +(``[base, limit)``) that the capability points to (``0x200200-0x226c40``). And the attributes of the +capability pointer like the ``sentry`` keyword at the end of the output. The permissions part of a capability determine what operations are allowed via this capability, and they can be grouped into the following categories: `[2] `_ From b78d8aa18a0e974b1f02887487e56ffaa878d2a7 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Wed, 15 Nov 2023 23:03:28 +0800 Subject: [PATCH 03/15] fixed a typo --- faq/sealed_capabilities.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/faq/sealed_capabilities.rst b/faq/sealed_capabilities.rst index b89a178..153a564 100644 --- a/faq/sealed_capabilities.rst +++ b/faq/sealed_capabilities.rst @@ -45,7 +45,7 @@ let's say that we have the following ``func.c`` program: int main(int argc, char *argv[]) { - void *cap1 = fun; + void *cap1 = func; void *cap2 = cap1 + 1; printf("%#p\n", cap1); printf("%#p\n", cap2); From 0ac2b21d7066603d568ea42d2ac7d32f211ee224 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Wed, 15 Nov 2023 23:44:22 +0800 Subject: [PATCH 04/15] added instructions for compiling on a Morello system --- faq/sealed_capabilities.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/faq/sealed_capabilities.rst b/faq/sealed_capabilities.rst index 153a564..a7d3ca1 100644 --- a/faq/sealed_capabilities.rst +++ b/faq/sealed_capabilities.rst @@ -58,13 +58,23 @@ as ``aarch64-linux-musl_purecap`` and the sysroot as ``/root/musl-sysroot-pureca .. code-block:: shell + # compile in the MorelloIE Docker image $ clang -march=morello \ --target=aarch64-linux-musl_purecap \ --sysroot=/root/musl-sysroot-purecap \ func.c -o func -static + # or compile it on a Morello system + $ clang-morello -march=morello+c64 -mabi=purecap \ + -Xclang -morello-vararg=new \ + -O0 -g func.c -o func + + +To run the program in the MorelloIE Docker image, we can use ``morelloie`` while on a Morello +system, we can just run the output binary ``./func``. The output of the program is shown below. +And in the following sections, we'll only show the output of ``morelloie``, as the output of the +example program on a Morello system should be the same. -To run the program, we can use ``morelloie``: .. code-block:: shell @@ -72,6 +82,10 @@ To run the program, we can use ``morelloie``: 0x211545 [rxRE,0x200200-0x226c40] (sentry) 0x211546 [rxRE,0x200200-0x226c40] (invalid,sentry) + $ ./func + 0x110a3d [rxR,0x100000-0x130e80] (sentry) + 0x110a3e [rxR,0x100000-0x130e80] (invalid,sentry) + The ``%#p`` format specifier is used to print a capability pointer in hexadecimal format along with some properties and attributes of this capability pointer. It prints the capability pointer in the following From e8882af74e4e3bb11fde255c6568dbcdfd41adb7 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Thu, 16 Nov 2023 00:40:31 +0800 Subject: [PATCH 05/15] split into two short posts --- faq/capabilities.rst | 207 +++++++++++++++++++++++++++++++++ faq/index.rst | 1 + faq/sealed_capabilities.rst | 220 ++---------------------------------- 3 files changed, 216 insertions(+), 212 deletions(-) create mode 100644 faq/capabilities.rst diff --git a/faq/capabilities.rst b/faq/capabilities.rst new file mode 100644 index 0000000..0954d9e --- /dev/null +++ b/faq/capabilities.rst @@ -0,0 +1,207 @@ +==================== +What is a Capability +==================== + +A capability is a token of authority over a continuous memory space. It associates traditional +pointers with a set of permissions and properties. Capabilities are unforgeable and unguessable, +and can be passed around between threads and processes. A capability have the following properties: +`[1] `_ + +- Value: memory location address (the conventional pointer address). +- Tag: indicates if a capability is valid (and whether it can be dereferenced, i.e., used as a base address in a memory reference). +- Bounds: base, limit, validity (the latter shows whether current combination of base, value and limit are correctly encoded). Bounds make up a semi-closed interval where base is included, and limit is not. +- Global / Local: a property that shows whether a capability is global or local (ha-ha, see below though). +- Permissions: they control operations that are available via this capability (see below). +- Executable / System access / Executive: bits that define and describe executability of a capability. +- Object type: a property related to sealing of capabilities (see below). +- Flags: application defined bits. + +You can follow the example code below if you have a Morello board or MorelloIE, the Morello +Instruction Emulator. You can use the prebuilt MorelloIE Docker image, ``cocoaxu/morelloie``, +for a quick start. + + +.. code-block:: shell + + $ docker run -it --rm cocoaxu/morelloie + + +Inside this Docker image, ``morelloie`` and ``clang`` are available. Besides that, a sysroot +directory for Purecap can be found at ``/root/musl-sysroot-purecap``, which can be used later +when compiling Purecap Morello programs with clang. + +After compiling the example code, you can use ``morelloie`` to run your program. For example, +let's say that we have the following ``func.c`` program: + + +.. code-block:: C + + // func.c + #include + + void func() { } + + int main(int argc, char *argv[]) + { + void *cap1 = func; + void *cap2 = cap1 + 1; + printf("%#p\n", cap1); + printf("%#p\n", cap2); + } + + +We'll mention the ``%#p`` format specifier later once we saw the output. Now we can +compile it with ``clang`` using the following command, where we specify the target +as ``aarch64-linux-musl_purecap`` and the sysroot as ``/root/musl-sysroot-purecap``: + +.. code-block:: shell + + # compile in the MorelloIE Docker image + $ clang -march=morello \ + --target=aarch64-linux-musl_purecap \ + --sysroot=/root/musl-sysroot-purecap \ + func.c -o func -static + + # or compile it on a Morello system + $ clang-morello -march=morello+c64 -mabi=purecap \ + -Xclang -morello-vararg=new \ + -O0 -g func.c -o func + + +To run the program in the MorelloIE Docker image, we can use ``morelloie`` while on a Morello +system, we can just run the output binary ``./func``. The output of the program is shown below. +And in the following sections, we'll only show the output of ``morelloie``, as the output of the +example program on a Morello system should be the same. + + +.. code-block:: shell + + $ morelloie -- ./func + 0x211545 [rxRE,0x200200-0x226c40] (sentry) + 0x211546 [rxRE,0x200200-0x226c40] (invalid,sentry) + + $ ./func + 0x110a3d [rxR,0x100000-0x130e80] (sentry) + 0x110a3e [rxR,0x100000-0x130e80] (invalid,sentry) + + +The ``%#p`` format specifier is used to print a capability pointer in hexadecimal format along with some +properties and attributes of this capability pointer. It prints the capability pointer in the following +format: + +.. code-block:: text + +
[,-] () + + +which contains its address (``0x211545``), permissions (``rxRE``), and the semi-closed memory range +(``[base, limit)``) that the capability points to (``0x200200-0x226c40``). And the attributes of the +capability pointer like the ``sentry`` keyword at the end of the output. + +The permissions part of a capability determine what operations are allowed via this capability, and they can +be grouped into the following categories: `[2] `_ + +- data access (reading from and writing to memory), +- permission-like bits that aren't permissions per se but act like they in terms of monotonicity, +- code execution (this includes loading code from memory as well), +- custom permissions for specific use cases (such as compartment switches). + +So the first line of the output shows that the first capability ``cap1`` points to the function ``func`` and +the second capability ``cap2`` points to the next byte after the function ``func``. The permissions of the +first capability ``cap1`` is ``rxRE``, which means that it is readable, executable, and has the ``RE`` property. +The ``RE`` property means that the capability is sealed, which means that it cannot be modified. + +The ``sentry`` property means that the capability is a sentry capability, which means that it is a capability +that is used to protect the memory space of the program. The ``sentry`` property is only available in Purecap +Morello. + +Usually, we don't need to explicitly change the permissions of a capability because the compiler and other +runtime library will do it. However, if you're in a situation where you need to have finer grained control over +the permissions of a capability, you can do that with builtin functions provided in ``cheriintrin.h``. For example, + +.. code-block:: C + + #include + #include + #include + + #define LOAD __CHERI_CAP_PERMISSION_PERMIT_LOAD__ + #define LOAD_CAP __CHERI_CAP_PERMISSION_PERMIT_LOAD_CAPABILITY__ + #define MUTABLE_LOAD __ARM_CAP_PERMISSION_MUTABLE_LOAD__ + + #define STORE __CHERI_CAP_PERMISSION_PERMIT_STORE__ + #define STORE_CAP __CHERI_CAP_PERMISSION_PERMIT_STORE_CAPABILITY__ + #define STORE_LOCAL __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__ + + void untrusted_3rd_party_func(char *str); + + int main() + { + char *str = malloc(sizeof(char) * 32); + char *ro_str = cheri_perms_and(str, LOAD | LOAD_CAP | MUTABLE_LOAD); + printf("str in main : %#p\n", str); + printf("ro_str in main: %#p\n", str); + untrusted_3rd_party_func(ro_str); + } + + void untrusted_3rd_party_func(char *str) + { + printf("str in func : %#p\n", str); + str[0] = 'A'; + } + + +In the example above, we have some macros that are used to define the permissions of a capability: +`[3] `_ + +- LOAD: read data (non-capability) from memory, +- LOAD_CAP: read a capability from memory, +- MUTABLE_LOAD: read a capability with permissions allowing mutable operations, +- STORE: write data (non-capability) to memory, +- STORE_CAP: write a capability, +- STORE_LOCAL: write a local capability (without this permission in the memory reference a local capability cannot be stored). + +As we want to make sure that the ``untrusted_3rd_party_func`` cannot modify the string, we use the builtin function +``cheri_perms_and`` to create a new capability ``ro_str`` that only has the ``LOAD``, ``LOAD_CAP`` and ``MUTABLE_LOAD`` +permissions. The ``LOAD`` permission means that the capability can be used to load data from memory. As for the +``LOAD_CAP`` and ``MUTABLE_LOAD`` permissions, they're used when we want to control access via copies of the +capabilities that are shared with other components of our program. + + +If we compile the example above and run it with ``morelloie``, we will get the following output: + +.. code-block:: shell + + $ clang -march=morello \ + --target=aarch64-linux-musl_purecap \ + --sysroot=/root/musl-sysroot-purecap \ + str.c -o str -static + $ morelloie -- ./str + str in main : 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] + ro_str in main: 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] + str in func : 0xffff80b98040 [rR,0xffff80b98040-0xffff80b98060] + [emulator] simulated capability fault at 2116b4 in thread 402 + Insufficient permissions (required ----w-------------) + 0x1:90100000:40608040:0000ffff:80b98040 + tag: true + address: 0x00000ffff80b98040 + base: 0x00000ffff80b98040 + limit: 0x00000ffff80b98060 + bounds: valid + in bounds: true + length: 32 + offset: 0 + permissions: -rRM-------------- + sealed: (not sealed) + flags: 0 + exponent: 0 + top: 0x8060 + bottom: 0x8040 + local: true + Segmentation fault + + +As we can see, the capability ``ro_str`` has the ``rR`` permissions, which means that it can be used to read data, +but cannot be used to write data. And when we try to modify the string in the ``untrusted_3rd_party_func``, the +Mollore Instruction Emulator will raise a capability fault with a hint telling us that the capability ``ro_str`` +does not have the ``w`` permission, which is necessay for writing data to memory. diff --git a/faq/index.rst b/faq/index.rst index 64cf7b5..0e3afee 100644 --- a/faq/index.rst +++ b/faq/index.rst @@ -19,6 +19,7 @@ when working with CHERI software? installing_gdb printf purecap_or_hybrid_binary + capabilities sealed_capabilities python running diff --git a/faq/sealed_capabilities.rst b/faq/sealed_capabilities.rst index a7d3ca1..1c96253 100644 --- a/faq/sealed_capabilities.rst +++ b/faq/sealed_capabilities.rst @@ -1,219 +1,15 @@ +=========================== What is a Sealed Capability =========================== -Capability ----------- - -A capability is a token of authority over a continuous memory space. It associates traditional -pointers with a set of permissions and properties. Capabilities are unforgeable and unguessable, -and can be passed around between threads and processes. A capability have the following properties: -`[1] `_ - -- Value: memory location address (the conventional pointer address). -- Tag: indicates if a capability is valid (and whether it can be dereferenced, i.e., used as a base address in a memory reference). -- Bounds: base, limit, validity (the latter shows whether current combination of base, value and limit are correctly encoded). Bounds make up a semi-closed interval where base is included, and limit is not. -- Global / Local: a property that shows whether a capability is global or local (ha-ha, see below though). -- Permissions: they control operations that are available via this capability (see below). -- Executable / System access / Executive: bits that define and describe executability of a capability. -- Object type: a property related to sealing of capabilities (see below). -- Flags: application defined bits. - -You can follow the example code below if you have a Morello board or MorelloIE, the Morello -Instruction Emulator. You can use the prebuilt MorelloIE Docker image, ``cocoaxu/morelloie``, -for a quick start. - - -.. code-block:: shell - - $ docker run -it --rm cocoaxu/morelloie - - -Inside this Docker image, ``morelloie`` and ``clang`` are available. Besides that, a sysroot -directory for Purecap can be found at ``/root/musl-sysroot-purecap``, which can be used later -when compiling Purecap Morello programs with clang. - -After compiling the example code, you can use ``morelloie`` to run your program. For example, -let's say that we have the following ``func.c`` program: - - -.. code-block:: C - - // func.c - #include - - void func() { } - - int main(int argc, char *argv[]) - { - void *cap1 = func; - void *cap2 = cap1 + 1; - printf("%#p\n", cap1); - printf("%#p\n", cap2); - } - - -We'll mention the ``%#p`` format specifier later once we saw the output. Now we can -compile it with ``clang`` using the following command, where we specify the target -as ``aarch64-linux-musl_purecap`` and the sysroot as ``/root/musl-sysroot-purecap``: - -.. code-block:: shell - - # compile in the MorelloIE Docker image - $ clang -march=morello \ - --target=aarch64-linux-musl_purecap \ - --sysroot=/root/musl-sysroot-purecap \ - func.c -o func -static - - # or compile it on a Morello system - $ clang-morello -march=morello+c64 -mabi=purecap \ - -Xclang -morello-vararg=new \ - -O0 -g func.c -o func - - -To run the program in the MorelloIE Docker image, we can use ``morelloie`` while on a Morello -system, we can just run the output binary ``./func``. The output of the program is shown below. -And in the following sections, we'll only show the output of ``morelloie``, as the output of the -example program on a Morello system should be the same. - - -.. code-block:: shell - - $ morelloie -- ./func - 0x211545 [rxRE,0x200200-0x226c40] (sentry) - 0x211546 [rxRE,0x200200-0x226c40] (invalid,sentry) - - $ ./func - 0x110a3d [rxR,0x100000-0x130e80] (sentry) - 0x110a3e [rxR,0x100000-0x130e80] (invalid,sentry) - - -The ``%#p`` format specifier is used to print a capability pointer in hexadecimal format along with some -properties and attributes of this capability pointer. It prints the capability pointer in the following -format: - -.. code-block:: text - -
[,-] () - - -which contains its address (``0x211545``), permissions (``rxRE``), and the semi-closed memory range -(``[base, limit)``) that the capability points to (``0x200200-0x226c40``). And the attributes of the -capability pointer like the ``sentry`` keyword at the end of the output. - -The permissions part of a capability determine what operations are allowed via this capability, and they can -be grouped into the following categories: `[2] `_ - -- data access (reading from and writing to memory), -- permission-like bits that aren't permissions per se but act like they in terms of monotonicity, -- code execution (this includes loading code from memory as well), -- custom permissions for specific use cases (such as compartment switches). - -So the first line of the output shows that the first capability ``cap1`` points to the function ``func`` and -the second capability ``cap2`` points to the next byte after the function ``func``. The permissions of the -first capability ``cap1`` is ``rxRE``, which means that it is readable, executable, and has the ``RE`` property. -The ``RE`` property means that the capability is sealed, which means that it cannot be modified. - -The ``sentry`` property means that the capability is a sentry capability, which means that it is a capability -that is used to protect the memory space of the program. The ``sentry`` property is only available in Purecap -Morello. - -Usually, we don't need to explicitly change the permissions of a capability because the compiler and other -runtime library will do it. However, if you're in a situation where you need to have finer grained control over -the permissions of a capability, you can do that with builtin functions provided in ``cheriintrin.h``. For example, - -.. code-block:: C - - #include - #include - #include - - #define LOAD __CHERI_CAP_PERMISSION_PERMIT_LOAD__ - #define LOAD_CAP __CHERI_CAP_PERMISSION_PERMIT_LOAD_CAPABILITY__ - #define MUTABLE_LOAD __ARM_CAP_PERMISSION_MUTABLE_LOAD__ - - #define STORE __CHERI_CAP_PERMISSION_PERMIT_STORE__ - #define STORE_CAP __CHERI_CAP_PERMISSION_PERMIT_STORE_CAPABILITY__ - #define STORE_LOCAL __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__ - - void untrusted_3rd_party_func(char *str); - - int main() - { - char *str = malloc(sizeof(char) * 32); - char *ro_str = cheri_perms_and(str, LOAD | LOAD_CAP | MUTABLE_LOAD); - printf("str in main : %#p\n", str); - printf("ro_str in main: %#p\n", str); - untrusted_3rd_party_func(ro_str); - } - - void untrusted_3rd_party_func(char *str) - { - printf("str in func : %#p\n", str); - str[0] = 'A'; - } - - -In the example above, we have some macros that are used to define the permissions of a capability: -`[3] `_ - -- LOAD: read data (non-capability) from memory, -- LOAD_CAP: read a capability from memory, -- MUTABLE_LOAD: read a capability with permissions allowing mutable operations, -- STORE: write data (non-capability) to memory, -- STORE_CAP: write a capability, -- STORE_LOCAL: write a local capability (without this permission in the memory reference a local capability cannot be stored). - -As we want to make sure that the ``untrusted_3rd_party_func`` cannot modify the string, we use the builtin function -``cheri_perms_and`` to create a new capability ``ro_str`` that only has the ``LOAD``, ``LOAD_CAP`` and ``MUTABLE_LOAD`` -permissions. The ``LOAD`` permission means that the capability can be used to load data from memory. As for the -``LOAD_CAP`` and ``MUTABLE_LOAD`` permissions, they're used when we want to control access via copies of the -capabilities that are shared with other components of our program. - - -If we compile the example above and run it with ``morelloie``, we will get the following output: - -.. code-block:: shell - - $ clang -march=morello \ - --target=aarch64-linux-musl_purecap \ - --sysroot=/root/musl-sysroot-purecap \ - str.c -o str -static - $ morelloie -- ./str - str in main : 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] - ro_str in main: 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] - str in func : 0xffff80b98040 [rR,0xffff80b98040-0xffff80b98060] - [emulator] simulated capability fault at 2116b4 in thread 402 - Insufficient permissions (required ----w-------------) - 0x1:90100000:40608040:0000ffff:80b98040 - tag: true - address: 0x00000ffff80b98040 - base: 0x00000ffff80b98040 - limit: 0x00000ffff80b98060 - bounds: valid - in bounds: true - length: 32 - offset: 0 - permissions: -rRM-------------- - sealed: (not sealed) - flags: 0 - exponent: 0 - top: 0x8060 - bottom: 0x8040 - local: true - Segmentation fault - - -As we can see, the capability ``ro_str`` has the ``rR`` permissions, which means that it can be used to read data, -but cannot be used to write data. And when we try to modify the string in the ``untrusted_3rd_party_func``, the -Mollore Instruction Emulator will raise a capability fault with a hint telling us that the capability ``ro_str`` -does not have the ``w`` permission, which is necessay for writing data to memory. - -Sealed Capabilities -------------------- +This post serves as the second part of the previous post `What is a Capability `_, +and in this post, we will talk about what a sealed capability is in CHERI. Also, +we will explain sealed capabilities using the example program in the previous post, +so if you haven't read the previous post, please read it first. -Before we dive into the details of these capabilities in the ``func`` program above, let's talk -about what a sealed capability is. In CHERI and Morello, a capability can be sealed, and in simple -words, a sealed capability is a capability with a non-zero object type. +Before we dive into the details of these capabilities in the ``func`` program in the previous post, +let's talk about what a sealed capability is. In CHERI and Morello, a capability can be sealed, +and in simple words, a sealed capability is a capability with a non-zero object type. The object type is a 16-bit field in Morello, and there're 4 special values for the object type: From 9a60fdadd10de28f0e1893ed7260cd3edc20cb18 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Thu, 23 Nov 2023 23:27:49 +0800 Subject: [PATCH 06/15] some improvements on compiling in different environments --- faq/capabilities.rst | 59 ++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/faq/capabilities.rst b/faq/capabilities.rst index 0954d9e..f1e0f30 100644 --- a/faq/capabilities.rst +++ b/faq/capabilities.rst @@ -17,18 +17,23 @@ and can be passed around between threads and processes. A capability have the fo - Flags: application defined bits. You can follow the example code below if you have a Morello board or MorelloIE, the Morello -Instruction Emulator. You can use the prebuilt MorelloIE Docker image, ``cocoaxu/morelloie``, -for a quick start. +Instruction Emulator. You can use the prebuilt MorelloIE Docker image, either ``cocoaxu/morelloie-llvm`` +or ``cocoaxu/morelloie-gcc`` (LLVM-toochain and GCC-toolchain respectively), for a quick start. .. code-block:: shell - $ docker run -it --rm cocoaxu/morelloie + # using LLVM toolchain with musl libc + $ docker run -it --rm cocoaxu/morelloie-llvm + # using GCC toolchain with glibc + $ docker run -it --rm cocoaxu/morelloie-gcc -Inside this Docker image, ``morelloie`` and ``clang`` are available. Besides that, a sysroot -directory for Purecap can be found at ``/root/musl-sysroot-purecap``, which can be used later -when compiling Purecap Morello programs with clang. + +Inside these Docker images, they both have ``morelloie`` pre-installed while the CHERI compiler +is ``clang`` and ``gcc`` respectively. And for the LLVM toolchain specificly, a sysroot directory +for Purecap can be found at ``/root/musl-sysroot-purecap``, which can be used later +when compiling Purecap Morello programs with ``clang``. After compiling the example code, you can use ``morelloie`` to run your program. For example, let's say that we have the following ``func.c`` program: @@ -50,28 +55,50 @@ let's say that we have the following ``func.c`` program: } -We'll mention the ``%#p`` format specifier later once we saw the output. Now we can -compile it with ``clang`` using the following command, where we specify the target -as ``aarch64-linux-musl_purecap`` and the sysroot as ``/root/musl-sysroot-purecap``: +We'll mention the ``%#p`` format specifier later once we saw the output. -.. code-block:: shell +Now we can compile it with the CHERI compiler, and based on your enviroment, +the compilation command varies: + +- If you're using the LLVM Docker image, ``cocoaxu/morelloie-llvm``, then the + CHREI compiler is ``clang``, and we need to specify the target as + ``aarch64-linux-musl_purecap`` and the sysroot as ``/root/musl-sysroot-purecap``: + + .. code-block:: shell - # compile in the MorelloIE Docker image $ clang -march=morello \ --target=aarch64-linux-musl_purecap \ --sysroot=/root/musl-sysroot-purecap \ func.c -o func -static - # or compile it on a Morello system + +- If you're using the GCC Docker image, ``cocoaxu/morelloie-gcc``, then we can compile + the program with ``gcc`` and we don't need to specify the target or sysroot: + + .. code-block:: shell + + $ gcc -march=morello+c64 -mabi=purecap \ + -O0 -g func.c -o func + + +- If you're on a Morello system, then you can compile the program with ``clang-morello``; + also, you don't need to specify the target or sysroot. However, for old versions of + ``clang-morello`` you need to add the ``-Xclang -morello-vararg=new`` flag to the + compilation command to enable the new vararg ABI for Morello: + + .. code-block:: shell + $ clang-morello -march=morello+c64 -mabi=purecap \ -Xclang -morello-vararg=new \ -O0 -g func.c -o func -To run the program in the MorelloIE Docker image, we can use ``morelloie`` while on a Morello -system, we can just run the output binary ``./func``. The output of the program is shown below. -And in the following sections, we'll only show the output of ``morelloie``, as the output of the -example program on a Morello system should be the same. +Of course, if you're on a Morello system, you don't need ``morelloie`` to emulate the CPU. +You can simply execute the program as what you'd do on a normal aarch64 Linux system. If +you're using either LLVM or GCC Morelloie Docker image, you need to run the program with +``morelloie``. The output of the program is shown below. (In the following sections, we'll +only show the output of ``morelloie``, as the output of the example program on a Morello +system should be the same.) .. code-block:: shell From 7f29cb60bb6231b6f9102c7e8fa64198d45f3a30 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Thu, 23 Nov 2023 23:39:58 +0800 Subject: [PATCH 07/15] rephrase --- faq/capabilities.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/faq/capabilities.rst b/faq/capabilities.rst index f1e0f30..6837b29 100644 --- a/faq/capabilities.rst +++ b/faq/capabilities.rst @@ -93,13 +93,14 @@ the compilation command varies: -O0 -g func.c -o func -Of course, if you're on a Morello system, you don't need ``morelloie`` to emulate the CPU. -You can simply execute the program as what you'd do on a normal aarch64 Linux system. If -you're using either LLVM or GCC Morelloie Docker image, you need to run the program with -``morelloie``. The output of the program is shown below. (In the following sections, we'll -only show the output of ``morelloie``, as the output of the example program on a Morello -system should be the same.) - +After the compilation, if you're on a Morello system, you can simply execute the program +as what you'd do on a normal aarch64 Linux system without the need of ``morelloie`` for +emulating the CPU. + +If you're using either the LLVM or the GCC MorelloIE Docker image, you need to run the +program with ``morelloie``. The output of the program is shown below. (In the following +sections, we'll only show the output of ``morelloie``, as the output of the example program +on a Morello system should be the same.) .. code-block:: shell From 9df77e4ced96746d3c5deb426a927e90d979ca37 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Thu, 23 Nov 2023 23:42:03 +0800 Subject: [PATCH 08/15] mention ASLR --- faq/capabilities.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/faq/capabilities.rst b/faq/capabilities.rst index 6837b29..3055c25 100644 --- a/faq/capabilities.rst +++ b/faq/capabilities.rst @@ -100,7 +100,8 @@ emulating the CPU. If you're using either the LLVM or the GCC MorelloIE Docker image, you need to run the program with ``morelloie``. The output of the program is shown below. (In the following sections, we'll only show the output of ``morelloie``, as the output of the example program -on a Morello system should be the same.) +on a Morello system should be the same, except for the memory address due to ASLR +(Address space layout randomization).) .. code-block:: shell From 021c5971b87bf126e0587a2cc23df679962c43cf Mon Sep 17 00:00:00 2001 From: Cocoa Date: Fri, 24 Nov 2023 00:00:37 +0800 Subject: [PATCH 09/15] move compling instructions to faq/compling.rst --- faq/capabilities.rst | 36 +++++++------------- faq/compiling.rst | 78 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 75 insertions(+), 39 deletions(-) diff --git a/faq/capabilities.rst b/faq/capabilities.rst index 3055c25..02b1f1f 100644 --- a/faq/capabilities.rst +++ b/faq/capabilities.rst @@ -16,28 +16,7 @@ and can be passed around between threads and processes. A capability have the fo - Object type: a property related to sealing of capabilities (see below). - Flags: application defined bits. -You can follow the example code below if you have a Morello board or MorelloIE, the Morello -Instruction Emulator. You can use the prebuilt MorelloIE Docker image, either ``cocoaxu/morelloie-llvm`` -or ``cocoaxu/morelloie-gcc`` (LLVM-toochain and GCC-toolchain respectively), for a quick start. - - -.. code-block:: shell - - # using LLVM toolchain with musl libc - $ docker run -it --rm cocoaxu/morelloie-llvm - - # using GCC toolchain with glibc - $ docker run -it --rm cocoaxu/morelloie-gcc - - -Inside these Docker images, they both have ``morelloie`` pre-installed while the CHERI compiler -is ``clang`` and ``gcc`` respectively. And for the LLVM toolchain specificly, a sysroot directory -for Purecap can be found at ``/root/musl-sysroot-purecap``, which can be used later -when compiling Purecap Morello programs with ``clang``. - -After compiling the example code, you can use ``morelloie`` to run your program. For example, -let's say that we have the following ``func.c`` program: - +For example, let's say that we have the following ``func.c`` program: .. code-block:: C @@ -55,7 +34,14 @@ let's say that we have the following ``func.c`` program: } -We'll mention the ``%#p`` format specifier later once we saw the output. +We'll mention the ``%#p`` format specifier later once we saw the output. + +You can follow the example code above if you have a Morello board or use MorelloIE, the Morello +Instruction Emulator. You can use these non-official prebuilt MorelloIE Docker images, such +as ``cocoaxu/morelloie-llvm`` and ``cocoaxu/morelloie-gcc`` for a quick start. They contain +LLVM-toochain and GCC-toolchain respectively. Please refer to the post, +`How do I compile for CHERI? `_ for more +information about how to set up and how to compile for CHERI. Now we can compile it with the CHERI compiler, and based on your enviroment, the compilation command varies: @@ -69,7 +55,7 @@ the compilation command varies: $ clang -march=morello \ --target=aarch64-linux-musl_purecap \ --sysroot=/root/musl-sysroot-purecap \ - func.c -o func -static + -O0 -g func.c -o func -static - If you're using the GCC Docker image, ``cocoaxu/morelloie-gcc``, then we can compile @@ -78,7 +64,7 @@ the compilation command varies: .. code-block:: shell $ gcc -march=morello+c64 -mabi=purecap \ - -O0 -g func.c -o func + -O0 -g func.c -o func -static - If you're on a Morello system, then you can compile the program with ``clang-morello``; diff --git a/faq/compiling.rst b/faq/compiling.rst index 37cc14b..01ace64 100644 --- a/faq/compiling.rst +++ b/faq/compiling.rst @@ -8,29 +8,79 @@ Cross-compilation ================= The LLVM compiler runs in cross-compilation mode for CHERI, so you can compile to CHERI targets from a non-CHERI platform like x86_64/linux. -If you use cheribuild, then by default your CHERI LLVM toolchain will be -located in the `cheri` directory in your home directory. There is a -configuration file with the relevant parameters set up to enable cross-compilation. One convenient way to -invoke the cross-compiler is by defining appropriate environment variables: -.. code-block:: bash +- If you use cheribuild, then by default your CHERI LLVM toolchain will be + located in the `cheri` directory in your home directory. There is a + configuration file with the relevant parameters set up to enable cross-compilation. One convenient way to + invoke the cross-compiler is by defining appropriate environment variables: - export CC=~/cheri/output/morello-sdk/bin/clang - export CFLAGS="--config cheribsd-morello-purecap.cfg" + .. code-block:: bash -You can then invoke the cross-compiler on your non-CHERI platform: + export CC=~/cheri/output/morello-sdk/bin/clang + export CFLAGS="--config cheribsd-morello-purecap.cfg" -.. code-block:: bash + You can then invoke the cross-compiler on your non-CHERI platform: + + .. code-block:: bash + + $CC $CFLAGS test.c + + which will generate an `a.out` executable file that you can copy to a + CHERI system to execute. + + Cross-compilation is most useful when you are running a CHERI emulator and + the native CHERI compiler runs too slowly on the emulator. + +- You can also use some non-official MorelloIE Docker images, such as ``cocoaxu/morelloie-llvm`` + and ``cocoaxu/morelloie-gcc``. They contain the LLVM-toochain and GCC-toolchain for CHERI, + respectively. You can use them to compile your CHERI programs on your non-CHERI platform. + + Meanwhile, you can also use the ``--volume`` option to mount your source code directory + into the container. For example, if your source code is in ``/home/user/src``, you can do + the following: + + .. code-block:: shell + + # using LLVM toolchain with musl libc + $ docker run -it --rm --volume /home/user/src:/src cocoaxu/morelloie-llvm + + # using GCC toolchain with glibc + $ docker run -it --rm --volume /home/user/src:/src cocoaxu/morelloie-gcc + + Then you can compile your CHERI programs inside the container. Inside these Docker images, + they both have ``morelloie`` pre-installed while the CHERI compiler is ``clang`` and ``gcc``, + respectively. + + And for the LLVM toolchain specificly, a sysroot directory for Purecap can be found at + ``/root/musl-sysroot-purecap``, which can be used later when compiling Purecap Morello programs + with ``clang``. + + - If you're using the LLVM Docker image, ``cocoaxu/morelloie-llvm``, then the + CHREI compiler is ``clang``, and we need to specify the target as + ``aarch64-linux-musl_purecap`` and the sysroot as ``/root/musl-sysroot-purecap``: + + .. code-block:: shell + + $ clang -march=morello \ + --target=aarch64-linux-musl_purecap \ + --sysroot=/root/musl-sysroot-purecap \ + test.c -o test -static + + + - If you're using the GCC Docker image, ``cocoaxu/morelloie-gcc``, then we can compile + the program with ``gcc`` and we don't need to specify the target or sysroot: + + .. code-block:: shell - $CC $CFLAGS test.c + $ gcc -march=morello+c64 -mabi=purecap \ + test.c -o test -static -which will generate an `a.out` executable file that you can copy to a -CHERI system to execute. -Cross-compilation is most useful when you are running a CHERI emulator and -the native CHERI compiler runs too slowly on the emulator. + After the compilation, you need to run the program with ``morelloie``. For example: + .. code-block:: shell + $ morelloie -- ./test Native compilation From 3344d440bafa7b66e3fc86a7089da365e30bff66 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Fri, 24 Nov 2023 01:09:24 +0800 Subject: [PATCH 10/15] using 3 spaces for indentation --- ...=> what_is_a_capabilities_long_answer.rst} | 158 +++++++++--------- 1 file changed, 79 insertions(+), 79 deletions(-) rename faq/{capabilities.rst => what_is_a_capabilities_long_answer.rst} (72%) diff --git a/faq/capabilities.rst b/faq/what_is_a_capabilities_long_answer.rst similarity index 72% rename from faq/capabilities.rst rename to faq/what_is_a_capabilities_long_answer.rst index 02b1f1f..94323bc 100644 --- a/faq/capabilities.rst +++ b/faq/what_is_a_capabilities_long_answer.rst @@ -1,6 +1,6 @@ -==================== -What is a Capability -==================== +========================================= +What is a CHERI capability? (long answer) +========================================= A capability is a token of authority over a continuous memory space. It associates traditional pointers with a set of permissions and properties. Capabilities are unforgeable and unguessable, @@ -20,18 +20,18 @@ For example, let's say that we have the following ``func.c`` program: .. code-block:: C - // func.c - #include + // func.c + #include - void func() { } + void func() { } - int main(int argc, char *argv[]) - { - void *cap1 = func; - void *cap2 = cap1 + 1; - printf("%#p\n", cap1); - printf("%#p\n", cap2); - } + int main(int argc, char *argv[]) + { + void *cap1 = func; + void *cap2 = cap1 + 1; + printf("%#p\n", cap1); + printf("%#p\n", cap2); + } We'll mention the ``%#p`` format specifier later once we saw the output. @@ -52,10 +52,10 @@ the compilation command varies: .. code-block:: shell - $ clang -march=morello \ - --target=aarch64-linux-musl_purecap \ - --sysroot=/root/musl-sysroot-purecap \ - -O0 -g func.c -o func -static + $ clang -march=morello \ + --target=aarch64-linux-musl_purecap \ + --sysroot=/root/musl-sysroot-purecap \ + -O0 -g func.c -o func -static - If you're using the GCC Docker image, ``cocoaxu/morelloie-gcc``, then we can compile @@ -63,8 +63,8 @@ the compilation command varies: .. code-block:: shell - $ gcc -march=morello+c64 -mabi=purecap \ - -O0 -g func.c -o func -static + $ gcc -march=morello+c64 -mabi=purecap \ + -O0 -g func.c -o func -static - If you're on a Morello system, then you can compile the program with ``clang-morello``; @@ -74,9 +74,9 @@ the compilation command varies: .. code-block:: shell - $ clang-morello -march=morello+c64 -mabi=purecap \ - -Xclang -morello-vararg=new \ - -O0 -g func.c -o func + $ clang-morello -march=morello+c64 -mabi=purecap \ + -Xclang -morello-vararg=new \ + -O0 -g func.c -o func After the compilation, if you're on a Morello system, you can simply execute the program @@ -91,13 +91,13 @@ on a Morello system should be the same, except for the memory address due to ASL .. code-block:: shell - $ morelloie -- ./func - 0x211545 [rxRE,0x200200-0x226c40] (sentry) - 0x211546 [rxRE,0x200200-0x226c40] (invalid,sentry) + $ morelloie -- ./func + 0x211545 [rxRE,0x200200-0x226c40] (sentry) + 0x211546 [rxRE,0x200200-0x226c40] (invalid,sentry) - $ ./func - 0x110a3d [rxR,0x100000-0x130e80] (sentry) - 0x110a3e [rxR,0x100000-0x130e80] (invalid,sentry) + $ ./func + 0x110a3d [rxR,0x100000-0x130e80] (sentry) + 0x110a3e [rxR,0x100000-0x130e80] (invalid,sentry) The ``%#p`` format specifier is used to print a capability pointer in hexadecimal format along with some @@ -106,7 +106,7 @@ format: .. code-block:: text -
[,-] () +
[,-] () which contains its address (``0x211545``), permissions (``rxRE``), and the semi-closed memory range @@ -136,34 +136,34 @@ the permissions of a capability, you can do that with builtin functions provided .. code-block:: C - #include - #include - #include + #include + #include + #include - #define LOAD __CHERI_CAP_PERMISSION_PERMIT_LOAD__ - #define LOAD_CAP __CHERI_CAP_PERMISSION_PERMIT_LOAD_CAPABILITY__ - #define MUTABLE_LOAD __ARM_CAP_PERMISSION_MUTABLE_LOAD__ + #define LOAD __CHERI_CAP_PERMISSION_PERMIT_LOAD__ + #define LOAD_CAP __CHERI_CAP_PERMISSION_PERMIT_LOAD_CAPABILITY__ + #define MUTABLE_LOAD __ARM_CAP_PERMISSION_MUTABLE_LOAD__ - #define STORE __CHERI_CAP_PERMISSION_PERMIT_STORE__ - #define STORE_CAP __CHERI_CAP_PERMISSION_PERMIT_STORE_CAPABILITY__ - #define STORE_LOCAL __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__ + #define STORE __CHERI_CAP_PERMISSION_PERMIT_STORE__ + #define STORE_CAP __CHERI_CAP_PERMISSION_PERMIT_STORE_CAPABILITY__ + #define STORE_LOCAL __CHERI_CAP_PERMISSION_PERMIT_STORE_LOCAL__ - void untrusted_3rd_party_func(char *str); + void untrusted_3rd_party_func(char *str); - int main() - { - char *str = malloc(sizeof(char) * 32); - char *ro_str = cheri_perms_and(str, LOAD | LOAD_CAP | MUTABLE_LOAD); - printf("str in main : %#p\n", str); - printf("ro_str in main: %#p\n", str); - untrusted_3rd_party_func(ro_str); - } + int main() + { + char *str = malloc(sizeof(char) * 32); + char *ro_str = cheri_perms_and(str, LOAD | LOAD_CAP | MUTABLE_LOAD); + printf("str in main : %#p\n", str); + printf("ro_str in main: %#p\n", str); + untrusted_3rd_party_func(ro_str); + } - void untrusted_3rd_party_func(char *str) - { - printf("str in func : %#p\n", str); - str[0] = 'A'; - } + void untrusted_3rd_party_func(char *str) + { + printf("str in func : %#p\n", str); + str[0] = 'A'; + } In the example above, we have some macros that are used to define the permissions of a capability: @@ -187,33 +187,33 @@ If we compile the example above and run it with ``morelloie``, we will get the f .. code-block:: shell - $ clang -march=morello \ - --target=aarch64-linux-musl_purecap \ - --sysroot=/root/musl-sysroot-purecap \ - str.c -o str -static - $ morelloie -- ./str - str in main : 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] - ro_str in main: 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] - str in func : 0xffff80b98040 [rR,0xffff80b98040-0xffff80b98060] - [emulator] simulated capability fault at 2116b4 in thread 402 - Insufficient permissions (required ----w-------------) - 0x1:90100000:40608040:0000ffff:80b98040 - tag: true - address: 0x00000ffff80b98040 - base: 0x00000ffff80b98040 - limit: 0x00000ffff80b98060 - bounds: valid - in bounds: true - length: 32 - offset: 0 - permissions: -rRM-------------- - sealed: (not sealed) - flags: 0 - exponent: 0 - top: 0x8060 - bottom: 0x8040 - local: true - Segmentation fault + $ clang -march=morello \ + --target=aarch64-linux-musl_purecap \ + --sysroot=/root/musl-sysroot-purecap \ + str.c -o str -static + $ morelloie -- ./str + str in main : 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] + ro_str in main: 0xffff80b98040 [rwRW,0xffff80b98040-0xffff80b98060] + str in func : 0xffff80b98040 [rR,0xffff80b98040-0xffff80b98060] + [emulator] simulated capability fault at 2116b4 in thread 402 + Insufficient permissions (required ----w-------------) + 0x1:90100000:40608040:0000ffff:80b98040 + tag: true + address: 0x00000ffff80b98040 + base: 0x00000ffff80b98040 + limit: 0x00000ffff80b98060 + bounds: valid + in bounds: true + length: 32 + offset: 0 + permissions: -rRM-------------- + sealed: (not sealed) + flags: 0 + exponent: 0 + top: 0x8060 + bottom: 0x8040 + local: true + Segmentation fault As we can see, the capability ``ro_str`` has the ``rR`` permissions, which means that it can be used to read data, From c2d5e74dd29ccc9ac5aa59a993c1b3cca6864cdb Mon Sep 17 00:00:00 2001 From: Cocoa Date: Fri, 24 Nov 2023 01:10:26 +0800 Subject: [PATCH 11/15] fixed the output format --- faq/what_is_a_capabilities_long_answer.rst | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/faq/what_is_a_capabilities_long_answer.rst b/faq/what_is_a_capabilities_long_answer.rst index 94323bc..5dbdd57 100644 --- a/faq/what_is_a_capabilities_long_answer.rst +++ b/faq/what_is_a_capabilities_long_answer.rst @@ -198,21 +198,21 @@ If we compile the example above and run it with ``morelloie``, we will get the f [emulator] simulated capability fault at 2116b4 in thread 402 Insufficient permissions (required ----w-------------) 0x1:90100000:40608040:0000ffff:80b98040 - tag: true + tag: true address: 0x00000ffff80b98040 base: 0x00000ffff80b98040 - limit: 0x00000ffff80b98060 - bounds: valid - in bounds: true - length: 32 - offset: 0 - permissions: -rRM-------------- - sealed: (not sealed) - flags: 0 - exponent: 0 - top: 0x8060 - bottom: 0x8040 - local: true + limit: 0x00000ffff80b98060 + bounds: valid + in bounds: true + length: 32 + offset: 0 + permissions: -rRM-------------- + sealed: (not sealed) + flags: 0 + exponent: 0 + top: 0x8060 + bottom: 0x8040 + local: true Segmentation fault From 3c0ee2e8d9505e3ef321f3b7145b8ae7cf83fcc9 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Fri, 24 Nov 2023 01:10:49 +0800 Subject: [PATCH 12/15] renamed what_is_a_capability.rst --- ...pability.rst => what_is_a_capabilities_short_answer.rst} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename faq/{what_is_a_capability.rst => what_is_a_capabilities_short_answer.rst} (83%) diff --git a/faq/what_is_a_capability.rst b/faq/what_is_a_capabilities_short_answer.rst similarity index 83% rename from faq/what_is_a_capability.rst rename to faq/what_is_a_capabilities_short_answer.rst index fc2ea21..e84fa92 100644 --- a/faq/what_is_a_capability.rst +++ b/faq/what_is_a_capabilities_short_answer.rst @@ -1,6 +1,6 @@ -============================ -What is a CHERI capability? -============================ +========================================== +What is a CHERI capability? (short answer) +========================================== A capability is an unforgeable token of authority that grants particular rights to perform an action in an execution context. From b01b9ca0db18c4f186dd61da0d8d3b8d8bf6dfdc Mon Sep 17 00:00:00 2001 From: Cocoa Date: Fri, 24 Nov 2023 01:11:24 +0800 Subject: [PATCH 13/15] updated index.rst file --- faq/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/faq/index.rst b/faq/index.rst index 6b72f5b..043ea61 100644 --- a/faq/index.rst +++ b/faq/index.rst @@ -9,7 +9,8 @@ when working with CHERI software? .. toctree:: :maxdepth: 1 - what_is_a_capability + what_is_a_capability_short_answer + what_is_a_capability_long_answer get_a_board compiling configure_networking From 9bf0bea4a4310caadee650ce0ecdd3db3f1e9d39 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Fri, 24 Nov 2023 01:14:32 +0800 Subject: [PATCH 14/15] renamed files --- ...es_long_answer.rst => what_is_a_capability_long_answer.rst} | 0 ..._short_answer.rst => what_is_a_capability_short_answer.rst} | 3 +++ 2 files changed, 3 insertions(+) rename faq/{what_is_a_capabilities_long_answer.rst => what_is_a_capability_long_answer.rst} (100%) rename faq/{what_is_a_capabilities_short_answer.rst => what_is_a_capability_short_answer.rst} (77%) diff --git a/faq/what_is_a_capabilities_long_answer.rst b/faq/what_is_a_capability_long_answer.rst similarity index 100% rename from faq/what_is_a_capabilities_long_answer.rst rename to faq/what_is_a_capability_long_answer.rst diff --git a/faq/what_is_a_capabilities_short_answer.rst b/faq/what_is_a_capability_short_answer.rst similarity index 77% rename from faq/what_is_a_capabilities_short_answer.rst rename to faq/what_is_a_capability_short_answer.rst index e84fa92..696ca0a 100644 --- a/faq/what_is_a_capabilities_short_answer.rst +++ b/faq/what_is_a_capability_short_answer.rst @@ -13,3 +13,6 @@ this is a bolt-on to a standard RISC instruction set architecture to provide support for capabilities in the processor architecture. The prototype `Arm Morello `_ processor supports capabilities natively in hardware. + +For a long answer that goes into more detail with live code examples, please see this post, +`What is a CHERI capability? (long answer) `_. From 15ae813567b17f5ab2c590c2d172f552d0686951 Mon Sep 17 00:00:00 2001 From: Cocoa Date: Fri, 24 Nov 2023 01:14:41 +0800 Subject: [PATCH 15/15] updated index.rst file --- faq/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/faq/index.rst b/faq/index.rst index 043ea61..c99aa3c 100644 --- a/faq/index.rst +++ b/faq/index.rst @@ -21,7 +21,6 @@ when working with CHERI software? installing_gdb printf purecap_or_hybrid_binary - capabilities sealed_capabilities purposes_of_sealed_capabilities python