CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Loading...
Searching...
No Matches
cheri.hh
Go to the documentation of this file.
1// Copyright Microsoft and CHERIoT Contributors.
2// SPDX-License-Identifier: MIT
3
4#pragma once
5/**
6 * \file
7 * \brief C++ helpers for operating on capabilities.
8 */
9#include <cheri.h>
10#include <cstddef>
11#include <cstdint>
12#include <initializer_list>
13#include <magic_enum/magic_enum.hpp>
14
15namespace CHERI
16{
17 /**
18 * The complete set of architectural permissions.
19 */
20 enum class Permission : uint32_t
21 {
22 /**
23 * Capability refers to global memory (this capability may be stored
24 * anywhere).
25 */
27 /**
28 * Global capabilities can be loaded through this capability. Without
29 * this permission, any capability loaded via this capability will
30 * have `Global` and `LoadGlobal` removed.
31 */
33 /**
34 * Capability may be used to store. Any store via a capability without
35 * this permission will trap.
36 */
38 /**
39 * Capabilities with store permission may be loaded through this
40 * capability. Without this, any loaded capability will have
41 * `LoadMutable` and `Store` removed.
42 */
44 /**
45 * This capability may be used to store capabilities that do not have
46 * `Global` permission.
47 */
49 /**
50 * This capability can be used to load.
51 */
53 /**
54 * Any load and store permissions on this capability convey the right to
55 * load or store capabilities in addition to data.
56 */
58 /**
59 * If installed as the program counter capability, running code may
60 * access privileged system registers.
61 */
63 /**
64 * This capability may be used as a jump target and used to execute
65 * instructions.
66 */
68 /**
69 * This capability may be used to unseal other capabilities. The
70 * 'address' range is in the sealing type namespace and not in the
71 * memory namespace.
72 */
74 /**
75 * This capability may be used to seal other capabilities. The
76 * 'address' range is in the sealing type namespace and not in the
77 * memory namespace.
78 */
80 /**
81 * Software defined permission bit, no architectural meaning.
82 */
84 };
85
86 /**
87 * Class encapsulating a set of permissions.
88 */
89 class PermissionSet
90 {
91 /**
92 * Helper that returns the bit associated with a given permission.
93 */
94 static constexpr uint32_t permission_bit(Permission p)
95 {
96 return 1 << static_cast<uint32_t>(p);
97 }
98
99 /**
100 * Helper for building permissions, adds a permission to the raw
101 * bitfield.
102 */
103 __always_inline constexpr void add_permission(Permission p)
104 {
105 rawPermissions |= permission_bit(p);
106 }
107
108 /**
109 * Private constructor for creating a permission set from a raw bitmask.
110 * This should never be used accidentally and so is hidden behind a
111 * factory method with an explicit name. Callers should use
112 * `PermissionSet::from_raw`.
113 */
114 constexpr PermissionSet(uint32_t rawPermissions)
116 {
117 }
118
119 public:
120 /**
121 * Computes (at compile time) a bitmask containing the set of valid
122 * permission bits.
123 *
124 * FIXME would ideally make this private and expose a public static
125 * constexpr field but this seems to trigger a compiler bug when trying
126 * to initialise said field using this function.
127 */
128 static constexpr uint32_t valid_permissions_mask()
129 {
130 uint32_t mask = 0;
131 for (auto permission : magic_enum::enum_values<Permission>())
132 {
133 mask |= 1 << static_cast<uint32_t>(permission);
134 }
135 return mask;
136 }
137
138 private:
139 /**
140 * Permissions iterator. Stores the permissions and iterates over them
141 * one bit at a time.
142 */
143 class Iterator
144 {
145 /// `PermissionSet` may construct this.
146 friend class PermissionSet;
147 /// The raw permissions bitmap.
148 uint32_t permissions;
149 /// Constructor, take a raw permissions bitmap.
150 constexpr Iterator(uint32_t rawPermissions)
151 : permissions(rawPermissions)
152 {
153 }
154
155 public:
156 /**
157 * Dereference, returns the lowest-numbered permission.
158 */
159 constexpr Permission operator*()
160 {
161 return static_cast<Permission>(__builtin_ffs(permissions) - 1);
162 }
163
164 /**
165 * Preincrement, drops the lowest-numbered permission.
166 */
167 constexpr Iterator &operator++()
168 {
169 permissions &= ~(1 << (__builtin_ffs(permissions) - 1));
170 return *this;
171 }
172
173 /**
174 * Returns true if the other iterator has a different set of
175 * permissions.
176 */
177 constexpr bool operator!=(const Iterator Other)
178 {
179 return permissions != Other.permissions;
180 }
181 };
182
183 public:
184 /**
185 * The raw bitmap of permissions. This is public so that this class
186 * meets the requirements of a structural type and can therefore be
187 * used as a template parameter. This field should never be directly
188 * modified.
189 */
190 uint32_t rawPermissions = 0;
191
192 /**
193 * Constructs a permission set from a raw permission mask.
194 */
195 static constexpr PermissionSet from_raw(uint32_t raw)
196 {
197 raw &= valid_permissions_mask();
198 return {raw};
199 }
200
201 /**
202 * Constructs a permission set from a single permission.
203 */
205 {
206 add_permission(p);
207 }
208
209 /**
210 * Construct a permission set from a list of permissions.
211 */
212 __always_inline constexpr PermissionSet(
213 std::initializer_list<Permission> permissions)
214 {
215 for (auto p : permissions)
216 {
217 add_permission(p);
218 }
219 }
220
221 /**
222 * Copy constructor.
223 */
224 constexpr PermissionSet(const PermissionSet &other)
225
226 = default;
227
228 /**
229 * Returns a permission set representing all permissions.
230 */
231 constexpr static PermissionSet omnipotent()
232 {
233 return PermissionSet{valid_permissions_mask()};
234 }
235
236 /**
237 * And-permissions operation, creates a new permission set containing
238 * only permissions present in both this set and the argument.
239 */
240 constexpr PermissionSet operator&(PermissionSet p)
241 {
242 return PermissionSet{rawPermissions & p.rawPermissions};
243 }
244
245 /**
246 * And-permissions operation, removes all permissions that are not
247 * present in both permission sets.
248 */
249 constexpr PermissionSet &operator&=(PermissionSet p)
250 {
252 return *this;
253 }
254
255 /**
256 * Constructs a new permission set without the specified permission.
257 */
258 [[nodiscard]] constexpr PermissionSet without(Permission p) const
259 {
260 return {rawPermissions & ~permission_bit(p)};
261 }
262
263 /**
264 * Constructs a new permission set without the specified permissions.
265 */
266 template<std::same_as<Permission>... Permissions>
267 [[nodiscard]] constexpr PermissionSet without(Permission p,
268 Permissions... ps) const
269 {
270 return this->without(p).without(ps...);
271 }
272
273 /**
274 * Returns true if, and only if, this permission set can be derived
275 * from the argument set.
276 */
277 [[nodiscard]] constexpr bool can_derive_from(PermissionSet other) const
278 {
279 return (rawPermissions & other.rawPermissions) == rawPermissions;
280 }
281
282 /**
283 * Returns true if this permission set contains the specified
284 * permission.
285 */
286 [[nodiscard]] constexpr bool contains(Permission permission) const
287 {
288 return (permission_bit(permission) & rawPermissions) ==
289 permission_bit(permission);
290 }
291
292 /**
293 * Returns true if this permission set contains the specified
294 * permissions.
295 */
296 template<std::same_as<Permission>... Permissions>
297 [[nodiscard]] constexpr bool contains(Permission p,
298 Permissions... ps) const
299 {
300 return this->contains(p) && this->contains(ps...);
301 }
302
303 /**
304 * Returns the raw permission mask as an integer containing a bitfield
305 * of permissions.
306 */
307 [[nodiscard]] constexpr uint32_t as_raw() const
308 {
309 return rawPermissions;
310 }
311
312 /**
313 * Returns an iterator over the permissions starting at the
314 * lowest-numbered permission.
315 */
316 [[nodiscard]] constexpr Iterator begin() const
317 {
318 return {rawPermissions};
319 }
320
321 /**
322 * Returns an end iterator.
323 */
324 [[nodiscard]] constexpr Iterator end() const
325 {
326 // Each increment of an iterator will drop one permission and so an
327 // iterator will compare equal to {0} once all permissions have
328 // been dropped.
329 return {0};
330 }
331
332 /**
333 * Three-way comparison. Treats a superset as greater-than, identical
334 * permissions as equivalent, and sets that don't have a superset
335 * releationship as unordered.
336 */
337 constexpr auto operator<=>(const PermissionSet Other) const
338 {
339 if (rawPermissions == Other.rawPermissions)
340 {
341 return std::partial_ordering::equivalent;
342 }
343 if (can_derive_from(Other))
344 {
345 return std::partial_ordering::less;
346 }
347 if (Other.can_derive_from(*this))
348 {
349 return std::partial_ordering::greater;
350 }
351 return std::partial_ordering::unordered;
352 }
353
354 /**
355 * Equality operator, wraps the three-way compare operator.
356 */
357 constexpr bool operator==(PermissionSet other) const
358 {
359 // Clang-tidy spuriously suggests that this 0 should be nullptr.
360 return (*this <=> other) == 0; // NOLINT(modernize-use-nullptr)
361 }
362 };
363
364 /**
365 * Rounds `len` up to a CHERI representable length for the current
366 * architecture.
367 */
368 __always_inline inline size_t representable_length(size_t length)
369 {
370 return __builtin_cheri_round_representable_length(length);
371 }
372
373 /**
374 * Returns the alignment mask required for a given length.
375 */
376 __always_inline inline size_t representable_alignment_mask(size_t length)
377 {
378 return __builtin_cheri_representable_alignment_mask(length);
379 }
380
381 /// Can the range [base, base + size) be precisely covered by a capability?
382 inline bool is_precise_range(ptraddr_t base, size_t size)
383 {
384 return (base & ~representable_alignment_mask(size)) == 0 &&
385 representable_length(size) == size;
386 }
387
388#if __has_extension(cheri_sealed_pointers)
389 // clang-format treats __sealed_capability differently depending on whether
390 // it knows it's a type qualifier or thinks it's an identifier. Turn off
391 // clang-format here until we've bumped the version in CI.
392 // clang-format off
393 /**
394 * Type trait to remove sealed from a capability type.
395 */
396 template<typename T>
397 struct remove_sealed; // NOLINT(readability-identifier-naming)
398
399 /**
400 * Specialisation to
401 */
402 template<typename T>
403 struct remove_sealed<T *__sealed_capability>
404 {
405 using type = T *; // NOLINT(readability-identifier-naming)
406 };
407
408 /**
409 * Type trait for checking if a type is a sealed capability.
410 */
411 template<typename T>
412 struct is_sealed_capability // NOLINT(readability-identifier-naming)
413 {
414 static constexpr bool value = // NOLINT(readability-identifier-naming)
415 false;
416 };
417
418 /**
419 * Type trait for checking if a type is a sealed capability.
420 */
421 template<typename T>
422 struct is_sealed_capability<T *__sealed_capability>
423 {
424 static constexpr bool value = // NOLINT(readability-identifier-naming)
425 true;
426 };
427
428 // clang-format on
429#else
430
431 // Fallback versions for when the compiler doesn't know something is
432 // sealed.
433
434 /**
435 * Type trait to remove sealed from a capability type.
436 */
437 template<typename T>
438 struct remove_sealed; // NOLINT(readability-identifier-naming)
439
440 /**
441 * Specialisation to
442 */
443 template<typename T>
444 struct remove_sealed<T *>
445 {
446 using type = T *; // NOLINT(readability-identifier-naming)
447 };
448
449 /**
450 * Type trait for checking if a type is a sealed capability.
451 */
452 template<typename T>
453 struct is_sealed_capability // NOLINT(readability-identifier-naming)
454 {
455 static constexpr bool value = // NOLINT(readability-identifier-naming)
456 false;
457 };
458
459#endif
460
461 /**
462 * Helper that provides the type of an unsealed capability from a sealed
463 * capability.
464 */
465 template<typename T>
466 using remove_sealed_t = // NOLINT(readability-identifier-naming)
468
469 /**
470 * Helper to check that a type is a sealed capability.
471 */
472 template<typename T>
473 constexpr bool
474 is_sealed_capability_v = // NOLINT(readability-identifier-naming)
475 is_sealed_capability<T>::value;
476
477 /**
478 * Helper class for accessing capability properties on pointers.
479 */
480 template<typename T, bool IsSealedT = false>
482 {
483 public:
484 static constexpr bool IsSealed = IsSealedT;
485 using PointerType =
486 std::conditional_t<IsSealed, CHERI_SEALED(T *), T *>;
487
488 protected:
489 /// The capability that this class wraps.
490 PointerType ptr;
491
492 private:
493 /**
494 * Constructs a PermissionSet with the permissions of the given pointer.
495 */
496 static PermissionSet permission_set_from_pointer(const volatile void *p)
497 {
498 auto perms = __builtin_cheri_perms_get(p);
500 /* FIXME teach the compiler that the builtin always returns a value
501 * that is a subset of the mask, otherwise it unnecessarily
502 * constructs and applies the mask in from_raw */
503 __builtin_assume((perms & ~mask) == 0);
504 return PermissionSet::from_raw(perms);
505 }
506
507 /**
508 * Base class for the proxies that accessors in this class return.
509 */
511 {
512 protected:
513 /**
514 * The capability that this proxy refers to.
515 */
516 Capability &cap;
517
518 /**
519 * Replaces the underlying capability
520 */
521 template<typename U>
522 void set(U *newPtr)
523 {
524 cap.ptr = static_cast<T *>(newPtr);
525 }
526
527 /**
528 * Returns the capability's pointer.
529 */
530 [[nodiscard]] auto ptr() const
531 {
532 return cap.ptr;
533 }
534
535 public:
536 /// Constructor, takes the capability whose property this class is
537 /// proxying.
538 PropertyProxyBase(Capability &c) : cap(c) {}
539 };
540
541 /**
542 * Proxy for accessing a capability's address.
543 */
544 struct AddressProxy : public PropertyProxyBase
545 {
546 /// Inherit the constructor from the base class.
547 using PropertyProxyBase::PropertyProxyBase;
548 /// Inherit the pointer accesors
549 /// @{
550 using PropertyProxyBase::ptr;
551 using PropertyProxyBase::set;
552 /// @}
553
554 /**
555 * Implicit casts can convert this to an address.
556 */
557 operator ptraddr_t() const
558 {
559 return __builtin_cheri_address_get(ptr());
560 }
561
562 /**
563 * Set the address in the underlying capability.
564 */
565 AddressProxy &operator=(ptraddr_t addr)
566 {
567 set(__builtin_cheri_address_set(ptr(), addr));
568 return *this;
569 }
570
571 /**
572 * Set the address in the underlying capability given another
573 * address proxy.
574 */
575 AddressProxy &operator=(AddressProxy addr)
576 {
577 set(__builtin_cheri_address_set(ptr(), addr));
578 return *this;
579 }
580
581 /**
582 * Add a displacement to the capability's address.
583 */
584 AddressProxy &operator+=(ptrdiff_t displacement)
585 {
586 set(__builtin_cheri_offset_increment(ptr(), displacement));
587 return *this;
588 }
589
590 /**
591 * Subtract a displacement from the capability's address.
592 */
593 AddressProxy &operator-=(ptrdiff_t displacement)
594 {
595 set(__builtin_cheri_offset_increment(ptr(), -displacement));
596 return *this;
597 }
598 };
599
600 /**
601 * Proxy for accessing an object's bounds.
602 */
603 struct BoundsProxy : public PropertyProxyBase
604 {
605 /// Inherit the constructor from the base class.
606 using PropertyProxyBase::PropertyProxyBase;
607 /// Inherit the pointer accesors
608 /// @{
609 using PropertyProxyBase::ptr;
610 using PropertyProxyBase::set;
611 /// @}
612
613 /**
614 * Return the object's bounds (displacement from the address to the
615 * end).
616 */
617 operator ptrdiff_t() const
618 {
619#if __has_builtin(__builtin_cheri_top_get)
620 return __builtin_cheri_top_get(ptr()) -
621 __builtin_cheri_address_get(ptr());
622#else
623 return __builtin_cheri_length_get(ptr()) -
624 (__builtin_cheri_address_get(ptr()) -
625 __builtin_cheri_base_get(ptr()));
626#endif
627 }
628
629 /**
630 * Set the capability's bounds, giving an invalid capability if this
631 * cannot be represented exactly.
632 */
633 BoundsProxy &operator=(size_t bounds)
634 {
635 set(__builtin_cheri_bounds_set_exact(ptr(), bounds));
636 return *this;
637 }
638
639 /**
640 * Set the bounds, adding some padding (up to the bounds of the
641 * original capability) if necessary for alignment.
642 */
643 BoundsProxy &set_inexact(size_t bounds)
644 {
645 set(__builtin_cheri_bounds_set(ptr(), bounds));
646 return *this;
647 }
648
649 private:
650 BoundsProxy &set_inexact_at_most_slow(size_t bounds)
651 {
652 ptraddr_t newBaseAddress = this->cap.address();
653
654 // The number of bits in CHERIoT's capability encoding's
655 // mantissa. This is part of the capability encoding and
656 // so, ideally, wouldn't be hard coded here.
657 static constexpr size_t MantissaBits = 9;
658
659 // The maximum possible representable length given the new
660 // base is a full mantissa width of 1s followed by 0s with
661 // its least significant 1 aligned to the least significant
662 // 1 in the base address.
663 size_t maximumLength = ((1 << MantissaBits) - 1)
664 << __builtin_ctz(newBaseAddress);
665
666 // Ensure that the requested length is representable by
667 // making sure that it fits within a mantissa width,
668 // rounding down by dropping any lower bits. This might be
669 // excessive by up to one bit position, because the
670 // representable alignment mask is designed to work with the
671 // rounding-up inexact bounds setting instruction. As a result,
672 // we might not return the largest possible representable
673 // length, but we won't return a wildly too small one, either.
674 size_t alignedLength =
676
677 // Select the smaller of those two lengths.
678 bounds = std::min<size_t>(alignedLength, maximumLength);
679 *this = bounds;
680 return *this;
681 }
682
683 public:
684 /**
685 * Set the bounds to `length` if `length` is representable with the
686 * current alignment of `buffer`. If not, then select a smaller
687 * `length` that is representable. Unlike set_inexact(), the
688 * resulting base will always be the current address; that is, there
689 * will be no padding below the current address.
690 *
691 * The caller must call .length() on the resulting capability to
692 * determine the imposed bounds.
693 *
694 * See is_precise_range().
695 */
696 __always_inline BoundsProxy &set_inexact_at_most(size_t bounds)
697 {
698 // Just try to set the requested bounds, first. If that works,
699 // there's no need for bit-twiddling at all.
700 Capability p = ptr();
701 p.bounds() = bounds;
702 if (p.is_valid())
703 {
704 set(static_cast<T *>(p));
705 return *this;
706 }
707
708 return set_inexact_at_most_slow(bounds);
709 }
710 };
711
712 /**
713 * Proxy for accessing a capability's permissions
714 */
715 struct PermissionsProxy : public PropertyProxyBase
716 {
717 /// Inherit the constructor from the base class.
718 using PropertyProxyBase::PropertyProxyBase;
719 /// Inherit the pointer accesors
720 /// @{
721 using PropertyProxyBase::ptr;
722 using PropertyProxyBase::set;
723 /// @}
724
725 /**
726 * Implicitly convert to a permission set.
727 */
728 operator PermissionSet() const
729 {
730 return permission_set_from_pointer(ptr());
731 }
732
733 /**
734 * And-permissions operation, removes all permissions that are not
735 * present in both permission sets from the capability.
736 */
737 PermissionsProxy &operator&=(PermissionSet permissions)
738 {
739 set(__builtin_cheri_perms_and(ptr(), permissions.as_raw()));
740 return *this;
741 }
742
743 /**
744 * Returns a permission set containing only the permissions held by
745 * the capability and the argument.
746 */
747 constexpr PermissionSet operator&(PermissionSet p)
748 {
749 return static_cast<PermissionSet>(*this) & p;
750 }
751
752 /**
753 * Constructs a new permission set without the specified
754 * permissions.
755 */
756 template<std::same_as<Permission>... Permissions>
757 [[nodiscard]] constexpr PermissionSet
758 without(Permissions... ps) const
759 {
760 return static_cast<PermissionSet>(*this).without(ps...);
761 }
762
763 /**
764 * Returns true if, and only if, this permission set can be derived
765 * from the argument set.
766 */
767 [[nodiscard]] constexpr bool
768 can_derive_from(PermissionSet other) const
769 {
770 return static_cast<PermissionSet>(*this).can_derive_from(other);
771 }
772
773 /**
774 * Returns true if this permission set contains the specified
775 * permissions.
776 */
777 template<std::same_as<Permission>... Permissions>
778 [[nodiscard]] constexpr bool
779 contains(Permissions... permissions) const
780 {
781 return static_cast<PermissionSet>(*this).contains(
782 permissions...);
783 }
784
785 /**
786 * Returns the raw permission mask as an integer containing a
787 * bitfield of permissions.
788 */
789 [[nodiscard]] constexpr uint32_t as_raw() const
790 {
791 return static_cast<PermissionSet>(*this).as_raw();
792 }
793
794 /**
795 * Returns an iterator over the permissions starting at the
796 * lowest-numbered permission.
797 */
798 auto begin()
799 {
800 return static_cast<PermissionSet>(*this).begin();
801 }
802
803 /**
804 * Returns an end iterator.
805 */
806 auto end()
807 {
808 return static_cast<PermissionSet>(*this).end();
809 }
810
811 /**
812 * Comparison operator.
813 */
814 constexpr std::partial_ordering
815 operator<=>(const PermissionSet Other) const
816 {
817 return static_cast<PermissionSet>(*this) <=> Other;
818 }
819
820 /**
821 * Equality operator, wraps the three-way compare operator.
822 */
823 constexpr bool operator==(const PermissionSet Other) const
824 {
825 return (*this <=> Other) == 0;
826 }
827 };
828
829 /// The property proxy base is allowed to directly access the pointer
830 /// that this class wraps.
831 friend class PropertyProxyBase;
832
833 public:
834 /// Constructor from a null pointer.
835 constexpr Capability(std::nullptr_t) : ptr(nullptr) {}
836 /// Default constructor, initialises with a null pointer.
837 constexpr Capability() : ptr(nullptr) {}
838 /// Constructor, takes an existing pointer to wrap
839 constexpr Capability(decltype(ptr) p) : ptr(p) {}
840 /// Copy constructor, aliases the object that is pointed to by `ptr`.
841 constexpr Capability(const Capability &other) = default;
842
843 /**
844 * Replace the pointer that this capability wraps with another.
845 */
846 Capability &operator=(const Capability &other) = default;
847
848 /**
849 * Access the address of the capability.
850 */
851 AddressProxy address() [[clang::lifetimebound]]
852 {
853 return {*this};
854 }
855
856 /**
857 * Return the address as an integer from a `const` capability.
858 */
859 [[nodiscard]] ptraddr_t address() const
860 {
861 return __builtin_cheri_address_get(ptr);
862 }
863
864 /**
865 * Access (read, set) the capability's bounds.
866 */
867 BoundsProxy bounds() [[clang::lifetimebound]]
868 {
869 return {*this};
870 }
871
872 /**
873 * Return the bounds as an integer.
874 */
875 [[nodiscard]] __always_inline ptrdiff_t bounds() const
876 {
877 return top() - address();
878 }
879
880 /**
881 * Access the permissions of this capability.
882 */
883 PermissionsProxy permissions() [[clang::lifetimebound]]
884 {
885 return {*this};
886 }
887
888 /**
889 * Get a copy of the permissions from a `const` capability.
890 */
891 [[nodiscard]] PermissionSet permissions() const
892 {
893 return permission_set_from_pointer(ptr);
894 }
895
896 /**
897 * Remove some permissions from this capability.
898 *
899 * Because this function computes the permission mask by clearing bits
900 * in the PermissionSet::omnipotent() all-ones mask, rather than from
901 * the set of permissions currently held by this Capability, it is safe
902 * to use to clear Global permission on a sealed capability.
903 */
904 template<std::same_as<Permission>... Permissions>
905 void without_permissions(Permissions... drop)
906 {
908 }
909
910 /**
911 * Pointer subtraction.
912 */
913 Capability operator-(ptrdiff_t diff)
914 {
915 return {ptr - diff};
916 }
917
918 /**
919 * Pointer subtraction.
920 */
921 Capability &operator-=(ptrdiff_t diff)
922 {
923 ptr -= diff;
924 return *this;
925 }
926
927 /**
928 * Pointer addition.
929 */
930 Capability operator+(ptrdiff_t diff)
931 {
932 return {ptr + diff};
933 }
934
935 /**
936 * Pointer addition.
937 */
938 Capability &operator+=(ptrdiff_t diff)
939 {
940 ptr += diff;
941 return *this;
942 }
943
944 /**
945 * Returns the tag bit indicating whether this is a valid
946 * capability.
947 *
948 * This returns a value subject to Common Subexpression
949 * Elimination (CSE): multiple calls to `is_valid` on the same
950 * capability may be optimized by the compiler into a single
951 * call. This may lead to stale results if the tag bit was
952 * cleared between the calls. See `is_valid_temporal` for a
953 * non-CSEable alternative.
954 */
955 [[nodiscard]] bool is_valid() const
956 {
957 // The clang static analyser doesn't yet know that null is untagged
958 // and so warns of possible null dereferences after this method
959 // returns true. Explicitly assume that a tagged thing is non-null
960 // to fix this.
961 if (__builtin_cheri_tag_get(ptr))
962 {
963 __builtin_assume(ptr != nullptr);
964 return true;
965 }
966 return false;
967 }
968
969 /**
970 * Returns the tag bit indicating whether this is a valid
971 * capability.
972 *
973 * This variant of `is_valid` is not subject to CSE.
974 */
975 [[nodiscard]] bool is_valid_temporal() const
976 {
977 // The clang static analyser doesn't yet know that null is untagged
978 // and so warns of possible null dereferences after this method
979 // returns true. Explicitly assume that a tagged thing is non-null
980 // to fix this.
981 if (__builtin_cheri_tag_get_temporal(ptr))
982 {
983 __builtin_assume(ptr != nullptr);
984 return true;
985 }
986 return false;
987 }
988
989 /**
990 * Return whether this is a sealed capability.
991 */
992 [[nodiscard]] bool is_sealed() const
993 {
994 return __builtin_cheri_type_get(ptr) != 0;
995 }
996
997 /**
998 * Returns the type of this capability, 0 if this is not a sealed
999 * capability.
1000 */
1001 [[nodiscard]] uint32_t type() const
1002 {
1003 return __builtin_cheri_type_get(ptr);
1004 }
1005
1006 /**
1007 * Returns the base address of this capability.
1008 */
1009 [[nodiscard]] ptraddr_t base() const
1010 {
1011 return __builtin_cheri_base_get(ptr);
1012 }
1013
1014 /**
1015 * Returns the length of this capability.
1016 */
1017 [[nodiscard]] size_t length() const
1018 {
1019 return __builtin_cheri_length_get(ptr);
1020 }
1021
1022 /**
1023 * Returns the address of the top of this capability.
1024 */
1025 [[nodiscard]] ptraddr_t top() const
1026 {
1027#if __has_builtin(__builtin_cheri_top_get)
1028 return __builtin_cheri_top_get(ptr);
1029#else
1030 return base() + length();
1031#endif
1032 }
1033
1034 /**
1035 * Capability comparison. Defines ordered comparison for capabilities
1036 * with the same bounds and permissions. All other capabilities are
1037 * either equivalent (identical bit pattern, including the tag bit) or
1038 * unordered.
1039 */
1040 constexpr std::partial_ordering operator<=>(T *other) const
1041 {
1042 return (*this <=> Capability<T>{other}) == 0;
1043 }
1044
1045 /**
1046 * Comparison against null pointer.
1047 *
1048 * Returns equivalent if this is a canonical null pointer, returns
1049 * unordered for any other (tagged or untagged) value. Callers may
1050 * often want `is_valid` instead of this.
1051 */
1052 constexpr std::partial_ordering operator<=>(std::nullptr_t) const
1053 {
1054 if (__builtin_cheri_equal_exact(ptr, nullptr))
1055 {
1056 return std::partial_ordering::equivalent;
1057 }
1058 return std::partial_ordering::unordered;
1059 }
1060
1061 constexpr bool operator==(const Capability Other) const
1062 {
1063 return __builtin_cheri_equal_exact(ptr, Other.ptr);
1064 }
1065
1066 /**
1067 * Capability comparison. Defines ordered comparison for capabilities
1068 * with the same bounds and permissions. All other capabilities are
1069 * either equivalent (identical bit pattern, including the tag bit) or
1070 * unordered.
1071 *
1072 * Callers may want to compare addresses, rather than capabilities, if
1073 * they want a defined comparison that is stable between two objects.
1074 */
1075 constexpr std::partial_ordering
1076 operator<=>(const Capability Other) const
1077 {
1078 if (__builtin_cheri_equal_exact(ptr, Other.ptr))
1079 {
1080 return std::partial_ordering::equivalent;
1081 }
1082 // If neither capability is sealed, check if everything except the
1083 // address is the same and define ordered comparison on pointers to
1084 // the same object.
1085 if (!(is_sealed() || Other.is_sealed()) &&
1086 __builtin_cheri_equal_exact(__builtin_address_set(
1087 ptr, __builtin_address_get(Other), Other)))
1088 {
1089 return static_cast<ptraddr_t>(ptr) <=>
1090 static_cast<ptraddr_t>(Other);
1091 }
1092 // Comparison of pointers to different objects is ub, you probably
1093 // want address comparison:
1094 return std::partial_ordering::unordered;
1095 }
1096
1097 /**
1098 * Equality operator, wraps the three-way compare operator.
1099 */
1100 constexpr bool operator==(std::nullptr_t) const
1101 {
1102 return (*this <=> nullptr) == 0;
1103 }
1104
1105 /**
1106 * Implicit cast to the raw pointer type (unsealed version).
1107 */
1108 template<typename U = T>
1109 requires(!std::same_as<U, void> && !IsSealed)
1110 operator U *() const
1111 {
1112 return ptr;
1113 }
1114
1115 /**
1116 * Implicit cast to the raw pointer type (sealed version)
1117 */
1118 template<typename U = T>
1119 requires(!std::same_as<U, void> && IsSealed)
1120 operator CHERI_SEALED(U *)() const
1121 {
1122 return ptr;
1123 }
1124
1125 /**
1126 * Implicit cast to a raw pointer type.
1127 */
1128 operator void *() const
1129 {
1130 return ptr;
1131 }
1132
1133 /**
1134 * Access fields of the target as if this were a raw pointer.
1135 */
1136 T *operator->() const
1137 {
1138 return ptr;
1139 }
1140
1141 /**
1142 * Explicitly get the raw pointer.
1143 */
1144 [[nodiscard]] T *get() const
1145 requires std::is_convertible_v<PointerType, T *>
1146 {
1147 return ptr;
1148 }
1149
1150 /**
1151 * Dereference operator.
1152 */
1153 template<typename U = T>
1154 requires(!std::same_as<U, void> && !IsSealed)
1155 U &operator*() const
1156 {
1157 return *ptr;
1158 }
1159
1160 /**
1161 * Cast this capability to some other type.
1162 */
1163 template<typename U>
1164 [[nodiscard]] Capability<U, IsSealed> cast() const
1165 {
1166 return {
1167 static_cast<std::conditional_t<IsSealed, CHERI_SEALED(U *), U *>>(
1168 ptr)};
1169 }
1170
1171 /**
1172 * Returns true if the tags of `this` and `other` match and if `this`
1173 * conveys no rights that are not present in `other`. Returns false in
1174 * all other cases.
1175 */
1176 template<typename U>
1177 [[nodiscard]] bool is_subset_of(Capability<U, IsSealed> other) const
1178 {
1179 return __builtin_cheri_subset_test(other.ptr, ptr);
1180 }
1181
1182 /**
1183 * Seal this capability with the given key.
1184 */
1185 [[nodiscard]] Capability<T, true> seal(void *key) const
1186 requires(!IsSealed)
1187 {
1188 return {reinterpret_cast<CHERI_SEALED(T *)>(
1189 __builtin_cheri_seal(ptr, key))};
1190 }
1191
1192 /**
1193 * Unseal this capability with the given key.
1194 */
1195 [[nodiscard]] Capability<T, false> unseal(void *key) const
1196 requires(IsSealed)
1197 {
1198#if __has_extension(cheri_sealed_pointers) && \
1199 defined(CHERIOT_NO_SEALED_POINTERS)
1200 // clang-format off
1201 return {static_cast<T *>(__builtin_cheri_unseal(
1202 reinterpret_cast<void *__sealed_capability>(ptr), key))};
1203 // clang-format on
1204#else
1205 return {static_cast<T *>(__builtin_cheri_unseal(ptr, key))};
1206#endif
1207 }
1208
1209 /**
1210 * Subscript operator.
1211 */
1212 template<typename U = T>
1213 requires(!std::same_as<U, void>)
1214 U &operator[](size_t index) const
1215 {
1216 return ptr[index];
1217 }
1218
1219 /**
1220 * Returns true if the capability is `align`-byte aligned, false
1221 * otherwise.
1222 */
1223 [[nodiscard]] bool is_aligned(size_t align) const
1224 {
1225 return __builtin_is_aligned(ptr, align);
1226 }
1227
1228 /**
1229 * Aligns the capability down to the nearest `align`-byte boundary.
1230 */
1231 Capability &align_down(size_t align)
1232 {
1233 ptr = __builtin_align_down(ptr, align);
1234 return *this;
1235 }
1236
1237 /**
1238 * Aligns the capability up to the nearest `align`-byte boundary.
1239 */
1240 Capability &align_up(size_t align)
1241 {
1242 ptr = __builtin_align_up(ptr, align);
1243 return *this;
1244 }
1245 };
1246
1247 template<typename T>
1248 Capability(T *) -> Capability<T, false>;
1249
1250#if __has_extension(cheri_sealed_pointers) && \
1251 !defined(CHERIOT_NO_SEALED_POINTERS)
1252 template<typename T>
1253 Capability(CHERI_SEALED(T *)) -> Capability<T, true>;
1254#endif
1255
1256 /*
1257 * Partially ensure that CHERI::Capability<>s can be housed in registers
1258 * rather than needing to go via memory. This is an attempt to capture some
1259 * of C++'s [class.temporary]p3 requirements, but I don't know how to
1260 * capture all of them in the existing metaprogramming library.
1261 */
1262 static_assert(std::is_trivially_copy_constructible_v<Capability<void>> &&
1263 std::is_trivially_destructible_v<Capability<void>>);
1264
1265 /**
1266 * Concept that matches pointers.
1267 */
1268 template<typename T>
1269 concept IsPointer = std::is_pointer_v<T>;
1270
1271 /**
1272 * Concept that matches smart pointers, i.e., classes which implements
1273 * a `get` method returning a pointer, and supports `operator=` with
1274 * the return value of `get`. This will match `Capability`, standard
1275 * library smart pointers, etc.
1276 */
1277 template<typename T>
1278 concept IsSmartPointerLike = requires(T b) {
1279 { b.get() } -> IsPointer;
1280 } && requires(T b) { b = b.get(); };
1281
1282 /**
1283 * Checks that `ptr` is valid, unsealed, has at least `Permissions`,
1284 * and has at least `space` bytes after the current offset.
1285 *
1286 * `ptr` can be a pointer, or a smart pointer, i.e., any class that
1287 * supports a `get` method returning a pointer, and `operator=`. This
1288 * includes `Capability` and standard library smart pointers.
1289 *
1290 * If the permissions do not include Global, then this will also check
1291 * that the capability does not point to the current thread's stack.
1292 * This behaviour can be disabled (for example, for use in a shared
1293 * library) by passing `false` for `CheckStack`.
1294 *
1295 * If `EnforceStrictPermissions` is set to `true`, this will also set
1296 * the permissions of the passed capability reference to `Permissions`, and
1297 * its bounds to `space`. This is useful for detecting cases where
1298 * compartments ask for fewer permissions than they actually require and
1299 * callers happen to provide the required permissions. Similarly, if you
1300 * are calling `check_pointer` in a function that wraps untrusted code such
1301 * as a third-party library, this lets you detect cases where your callers
1302 * are failing to remove permissions that the untrusted code should not
1303 * have.
1304 *
1305 * This function is provided as a wrapper for the `::check_pointer` C
1306 * API. It is always inlined. For each call site, it materialises the
1307 * constants needed before performing an indirect call to
1308 * `::check_pointer`.
1309 */
1310 template<PermissionSet Permissions = PermissionSet{Permission::Load},
1311 bool CheckStack = true,
1312 bool EnforceStrictPermissions = false>
1313 __always_inline inline bool
1314 check_pointer(auto &ptr,
1315 size_t space = sizeof(std::remove_pointer<decltype(ptr)>))
1316 requires(std::is_pointer_v<std::remove_cvref_t<decltype(ptr)>> ||
1317 IsSmartPointerLike<std::remove_cvref_t<decltype(ptr)>>)
1318 {
1319 // We can skip a stack check if we've asked for Global because the
1320 // stack does not have this permission.
1321 constexpr bool StackCheckNeeded =
1322 CheckStack && !Permissions.contains(Permission::Global);
1323 constexpr bool IsRawPointer =
1324 std::is_pointer_v<std::remove_cvref_t<decltype(ptr)>>;
1325
1326 bool isValid;
1327 if constexpr (IsRawPointer)
1328 {
1329 // If passed `ptr` as a raw capability (e.g., `void*`),
1330 // pass it as-is to ::check_pointer.
1331 isValid = ::check_pointer(
1332 ptr, space, Permissions.as_raw(), StackCheckNeeded);
1333 }
1334 else
1335 {
1336 // Otherwise, call `get` on `ptr` to retrieve a raw
1337 // capability.
1338 isValid = ::check_pointer(
1339 ptr.get(), space, Permissions.as_raw(), StackCheckNeeded);
1340 }
1341 // If passed `EnforceStrictPermissions`, set the permissions
1342 // of `ptr` to `Permissions`, and its bounds to `space`
1343 if constexpr (EnforceStrictPermissions)
1344 {
1345 if (isValid)
1346 {
1347 if constexpr (IsRawPointer)
1348 {
1349 Capability cap{ptr};
1350 cap.permissions() &= Permissions;
1351 cap.bounds() = space;
1352 ptr = cap.get();
1353 }
1354 else
1355 {
1356 Capability cap{ptr.get()};
1357 cap.permissions() &= Permissions;
1358 cap.bounds() = space;
1359 ptr = cap.get();
1360 }
1361 }
1362 }
1363 return isValid;
1364 }
1365
1366 /**
1367 * Invokes the passed callable object with interrupts disabled.
1368 */
1369 template<typename T>
1370 [[cheriot::interrupt_state(disabled)]] auto with_interrupts_disabled(T &&fn)
1371 {
1372 return fn();
1373 }
1374
1375 /**
1376 * The codes used in the cause field of the mtval CSR when the processor
1377 * takes a CHERI exception.
1378 */
1379 enum class CauseCode
1380 {
1381 /**
1382 * No exception. This value is passed to the error handler after a
1383 * forced unwind in a called compartment.
1384 */
1386 /**
1387 * Attempted to use a capability outside its bounds.
1388 */
1390 /**
1391 * Attempted to use an untagged capability to authorize something.
1392 */
1394 /**
1395 * Attempted to use a sealed capability to authorize something.
1396 */
1398 /**
1399 * Attempted to jump to a capability without `Permission::Execute`.
1400 */
1402 /**
1403 * Attempted to load via a capability without `Permission::Load`.
1404 */
1406 /**
1407 * Attempted to store via a capability without `Permission::Store`.
1408 */
1410 /**
1411 * Attempted to store a tagged capability via a capability without
1412 * `Permission::LoadStoreCapability`.
1413 */
1416 /**
1417 * Attempted to store a tagged capability without `Permission::Global`
1418 * via capability without `Permission::StoreLocal`.
1419 */
1422 /**
1423 * Attempted to access a restricted CSR or SCR with PCC without
1424 * `Permission::AccessSystemRegisters`.
1425 */
1428 /**
1429 * Used to represent a value that has no valid meaning in hardware.
1430 */
1432 };
1433
1434 /**
1435 * Register numbers as reported in thee cap idx field of `mtval` CSR when
1436 * a CHERI exception is taken. Values less than 32 refer to general
1437 * purpose registers and others to SCRs (of these, only PCC can actually
1438 * cause an exception).
1439 */
1441 {
1442 /**
1443 * The zero register, which always contains the `NULL` capability.
1444 */
1446 /**
1447 * `$c1` / `$cra` used by the ABI as the return address.
1448 * Not preserved across calls.
1449 */
1451 /**
1452 * `$c2` / `$csp` used by the ABI as the stack pointer.
1453 * Preserved across calls.
1454 */
1456 /**
1457 * `$c3` / `$cgp` used by the ABI as the global pointer.
1458 * Not allocatable by the compiler, set by the switcher on compartment
1459 * entry.
1460 */
1462 /**
1463 * `$c4` / `$ctp` used by the ABI as the thread pointer.
1464 * Currently unused by the compiler.
1465 * Not preserved across compartment calls.
1466 */
1468 /**
1469 * `$c5` / `$ct0` used by the ABI as temporary register.
1470 * Not preserved across calls.
1471 */
1473 /**
1474 * `$c6` / `$ct1` used by the ABI as temporary register.
1475 * Not preserved across calls.
1476 * Used by cross-compartment call as target import entry.
1477 */
1479 /**
1480 * `$c7` / `$ct2` used by the ABI as temporary register.
1481 * Not preserved across calls.
1482 */
1484 /**
1485 * `$c8` / `$cs0` used by the ABI as a callee-saved register.
1486 * Preserved across calls.
1487 */
1489 /**
1490 * `$c9` / `$cs1` used by the ABI as a callee-saved register.
1491 * Preserved across calls.
1492 */
1494 /**
1495 * `$c10` / `$ca0` used by the ABI as an argument register.
1496 * Not preserved across calls.
1497 */
1499 /**
1500 * `$c11` / `$ca1` used by the ABI as an argument register.
1501 * Not preserved across calls.
1502 */
1504 /**
1505 * `$c12` / `$ca2` used by the ABI as an argument register.
1506 * Not preserved across calls.
1507 */
1509 /**
1510 * `$c13` / `$ca3` used by the ABI as an argument register.
1511 * Not preserved across calls.
1512 */
1514 /**
1515 * `$c14` / `$ca4` used by the ABI as an argument register.
1516 * Not preserved across calls.
1517 */
1519 /**
1520 * `$c15` / `$ca5` used by the ABI as an argument register.
1521 * Not preserved across calls.
1522 */
1524 /**
1525 * The Program Counter Capability.
1526 *
1527 * Special capability register used to authorize instruction fetch. The
1528 * address is that of the faulting instruction. Also used for accessing
1529 * read-only globals.
1530 */
1532 /**
1533 * Machine-mode Trap Code Capability.
1534 *
1535 * Special capability register that
1536 * is installed in PCC when the CPU takes a trap. The address has the
1537 * same semantics as the RISC-V `mtvec` CSR. Only accessible when PCC
1538 * has the AccessSystemRegisters permission.
1539 */
1541 /**
1542 * Machine-mode Tusted Data Capability.
1543 *
1544 * Special capability register that contains the memory root capability
1545 * on boot. Only accessible when PCC has the AccessSystemRegisters
1546 * permission. Use by the RTOS to store a capability to the trusted
1547 * stack.
1548 */
1550 /**
1551 * Machine-mode Scratch Capability. Special capabiltiy register that
1552 * contains the sealing root capability on boot. Only accessible when
1553 * PCC has the AccessSystemRegisters permission.
1554 */
1556 /**
1557 * Machine-mode Exception Program Counter Capability. Special capability
1558 * register that contains the PCC of the faulting instruction on trap.
1559 * The address has the same semantics as the RISC-V `mepc` CSR. Only
1560 * accessible when PCC has the AccessSystemRegisters permission.
1561 */
1563 /**
1564 * Indicates a value that is not used by the hardware to refer to a
1565 * register.
1566 */
1568 };
1569
1570 /**
1571 * Decompose the value reported in the `mtval` CSR on CHERI exception
1572 * into a pair of `CauseCode` and `RegisterNumber`.
1573 *
1574 * Will return `CauseCode::Invalid` if the code field is not one
1575 * of the defined causes and `RegisterNumber::Invalid` if the register
1576 * number is not a valid register number. Other bits of mtval are ignored.
1577 */
1578 inline std::pair<CauseCode, RegisterNumber>
1579 extract_cheri_mtval(uint32_t mtval)
1580 {
1581 auto causeCode = magic_enum::enum_cast<CauseCode>(mtval & 0x1f)
1582 .value_or(CauseCode::Invalid);
1583 auto registerNumber =
1584 magic_enum::enum_cast<RegisterNumber>((mtval >> 5) & 0x3f)
1585 .value_or(RegisterNumber::Invalid);
1586 return {causeCode, registerNumber};
1587 }
1588
1589 /**
1590 * Helper for a value that encodes either a pointer or an error value in a
1591 * pointer-sized value, discriminated by the tag bit.
1592 *
1593 * This is a *non-owning* pointer type.
1594 */
1595 template<typename T, bool IsSealed = false>
1597 {
1598 /// The underlying value
1600
1601 public:
1602 /**
1603 * Construct from a pointer. This may be a C API that uses the
1604 * convention of holding a pointer or an error value. You may call
1605 * this constructor with an invalid pointer.
1606 */
1607 ErrorOr(T *pointer) : pointer(pointer) {}
1608
1609 /**
1610 * Construct from a CHERI::Capability. This may be a C API that uses
1611 * the convention of holding a pointer or an error value. You may call
1612 * this constructor with an invalid pointer.
1613 */
1614 __always_inline ErrorOr(Capability<T, IsSealed> pointer)
1615 : pointer(pointer)
1616 {
1617 }
1618
1619 /**
1620 * Initialise the value with an error value. By convention, error
1621 * numbers are negated in CHERIoT RTOS.
1622 */
1623 ErrorOr(int error)
1624 : pointer(reinterpret_cast<decltype(pointer)::PointerType>(
1625 static_cast<intptr_t>(error)))
1626 {
1627 }
1628
1629 /**
1630 * Returns `true` if this holds an error value, false otherwise.
1631 */
1633 {
1634 return !pointer.is_valid();
1635 }
1636
1637 /**
1638 * Generic eliminator for `ErrorOr<T>` values. Read `x.either(t, e)` as
1639 * "either calls t with x's value or e with x's error". That is,
1640 * `either` takes two callbacks, the first of which is called with
1641 * non-error `T *` values, and the second of which is called with `int`
1642 * error values. The return type of the latter (the error handler) must
1643 * be convertable to the return type of the former (the `T *` handler).
1644 */
1645 __always_inline auto either(auto &&onT,
1646 auto &&onE) /* 🏳️‍⚧️ */
1647 requires std::is_invocable_v<decltype(onT),
1649 std::is_invocable_v<decltype(onE), int> &&
1650 std::convertible_to<
1651 std::invoke_result_t<decltype(onE), int>,
1652 std::invoke_result_t<decltype(onT),
1654 {
1655 if (is_error())
1656 {
1657 auto e =
1658 reinterpret_cast<intptr_t>(static_cast<void *>(pointer));
1659
1660 /*
1661 * If `onT` returns `void`, then so must `onE` (given the
1662 * `requires`-ed `std::convertable_to` above), but `void` is not
1663 * a legal initializer type, so don't try.
1664 */
1665 if constexpr (std::is_void_v<
1666 std::invoke_result_t<decltype(onT),
1668 {
1669 return onE(e);
1670 }
1671 else
1672 {
1673 return std::invoke_result_t<decltype(onT),
1675 onE(e)};
1676 }
1677 }
1678 return onT(pointer);
1679 }
1680
1681 /**
1682 * If this holds an error value, return it, otherwise return 0.
1683 *
1684 * CHERIoT RTOS follows the C convention of using 0 to indicate
1685 * success, but this may result in ambiguity. Use `is_error` if this
1686 * ambiguity matters.
1687 */
1689 {
1690 return either([](auto) { return 0; }, [](int e) { return e; });
1691 }
1692
1693 /**
1694 * If this holds a pointer, return it, otherwise return `nullptr`.
1695 * This ensures that all values that are *not* valid pointers are
1696 * mapped to null.
1697 */
1699 requires requires() {
1700 { pointer.get() } -> std::same_as<T *>;
1701 }
1702 {
1703 return either([](auto t) { return t.get(); },
1704 [](int) { return nullptr; });
1705 }
1706
1707 /**
1708 * Returns the underlying pointer, which may be an untagged capability
1709 * with integer error value. For type safety, prefer `as_pointer` or
1710 * `as_error`.
1711 */
1713 requires requires() {
1714 { pointer.get() } -> std::same_as<T *>;
1715 }
1716 {
1717 return pointer.get();
1718 }
1719
1720 /**
1721 * Returns the underlying pointer, which may be an untagged capability
1722 * with integer error value, in its CHERI::Capability<> wrapper, which
1723 * includes the IsSealed flag. For type safety, prefer `as_pointer` or
1724 * `as_error`.
1725 */
1726 [[nodiscard]] auto as_raw_capability()
1727 {
1728 return pointer;
1729 }
1730
1731 /**
1732 * Monadic helper modelled on `std::optional`. Takes a reference to a
1733 * callable object that accepts a `T*` or something that can be
1734 * implicitly cast to a `T*`. The return value for the argument should
1735 * be either `void` (in which case `and_then` returns `*this`) or an
1736 * `ErrorOr<U>`
1737 *
1738 * The callback is invoked if and only if this holds a valid pointer.
1739 */
1740 auto and_then(auto &&function)
1741 requires std::is_convertible_v<decltype(pointer), T *> &&
1742 std::is_void_v<
1743 std::invoke_result_t<decltype(function), T *>>
1744 {
1745 either([function](T *t) { function(t); }, [](int) { return; });
1746 return *this;
1747 }
1748
1749 auto and_then(auto &&function)
1750 /*
1751 * Require that R, the result of `function` evaluation, is an
1752 * ErrorOr: in particular, that it is the same type returned by
1753 * an ErrorOr constructor (at a deduced template type, thus the
1754 * explicit namespacing!). In particular, this gets us our copy
1755 * constructor in the success case.
1756 */
1757 requires std::is_convertible_v<decltype(pointer), T *> &&
1758 requires(std::invoke_result_t<decltype(function), T *> r) {
1759 requires std::is_same_v<decltype(CHERI::ErrorOr(r)),
1760 decltype(r)>;
1761 }
1762 {
1763 return either(function, [](int e) {
1764 return std::invoke_result_t<decltype(function), T *>{e};
1765 });
1766 }
1767
1768 /**
1769 * Variant on `and_then` that returns an int: either the value returned
1770 * by the callback, or the error value held by `*this`. This is useful
1771 * for propagating error values in functions that return an int (e.g.
1772 * where negative values indicate errors and zero or positive values
1773 * indicate success).
1774 */
1775 int and_then(auto &&function)
1776 requires std::is_convertible_v<decltype(pointer), T *> &&
1777 std::is_same_v<
1778 std::invoke_result_t<decltype(function), T *>,
1779 int>
1780 {
1781 return either(function, [](int e) { return e; });
1782 }
1783
1784 /**
1785 * Monadic helper modelled on `std::optional`. Takes a reference to a
1786 * callable object that accepts an `int`. The return value for the
1787 * argument should be either `void` (in which case `or_else` returns
1788 * `*this`) or something that can implicitly cast to an `ErrorOr<T>`.
1789 *
1790 * The callback is invoked if and only if this holds an error value.
1791 */
1792 auto or_else(auto &&function)
1793 requires std::is_void_v<
1794 std::invoke_result_t<decltype(function), int>>
1795 {
1796 either([](T *) { return; }, [function](int e) { function(e); });
1797 return *this;
1798 }
1799
1800 auto or_else(auto &&function)
1801 requires std::is_convertible_v<
1802 std::invoke_result_t<decltype(function), int>,
1803 int>
1804 {
1805 return either([this](T *) { return *this; },
1806 [function](int e) { return function(e); });
1807 }
1808 };
1809
1810 /// Explicit copy constructor deduction guide
1811 template<typename T, bool IsSealed>
1813
1814 /*
1815 * Partially ensure that CHERI::ErrorOr<>s can be housed in registers rather
1816 * than needing to go via memory. See also the above test on Capability<>s.
1817 */
1818 static_assert(std::is_trivially_copy_constructible_v<ErrorOr<void>> &&
1819 std::is_trivially_destructible_v<ErrorOr<void>>);
1820
1821} // namespace CHERI
C definitions for CHERI specific functionality.
@ CheriPermissionStore
Capability may be used to store.
Definition cheri.h:37
@ CheriPermissionGlobal
Capability refers to global memory (this capability may be stored anywhere).
Definition cheri.h:26
@ CheriPermissionStoreLocal
This capability may be used to store capabilities that do not have Global permission.
Definition cheri.h:48
@ CheriPermissionLoadStoreCapability
Any load and store permissions on this capability convey the right to load or store capabilities in a...
Definition cheri.h:57
@ CheriPermissionUnseal
This capability may be used to unseal other capabilities.
Definition cheri.h:73
@ CheriPermissionUser0
Software defined permission bit, no architectural meaning.
Definition cheri.h:83
@ CheriPermissionLoadGlobal
Global capabilities can be loaded through this capability.
Definition cheri.h:32
@ CheriPermissionExecute
This capability may be used as a jump target and used to execute instructions.
Definition cheri.h:67
@ CheriPermissionAccessSystemRegisters
If installed as the program counter capability, running code may access privileged system registers.
Definition cheri.h:62
@ CheriPermissionSeal
This capability may be used to seal other capabilities.
Definition cheri.h:79
@ CheriPermissionLoad
This capability can be used to load.
Definition cheri.h:52
@ CheriPermissionLoadMutable
Capabilities with store permission may be loaded through this capability.
Definition cheri.h:43
@ CheriRegisterNumberMepcc
Machine-mode Exception Program Counter Capability.
Definition cheri.h:269
@ CheriRegisterNumberCgp
$c3 / $cgp used by the ABI as the global pointer.
Definition cheri.h:169
@ CheriRegisterNumberCsp
$c2 / $csp used by the ABI as the stack pointer.
Definition cheri.h:163
@ CheriRegisterNumberCT0
$c5 / $ct0 used by the ABI as temporary register.
Definition cheri.h:180
@ CheriRegisterNumberCS0
$c8 / $cs0 used by the ABI as a callee-saved register.
Definition cheri.h:195
@ CheriRegisterNumberCA2
$c12 / $ca2 used by the ABI as an argument register.
Definition cheri.h:215
@ CheriRegisterNumberCT2
$c7 / $ct2 used by the ABI as temporary register.
Definition cheri.h:190
@ CheriRegisterNumberCT1
$c6 / $ct1 used by the ABI as temporary register.
Definition cheri.h:185
@ CheriRegisterNumberCA1
$c11 / $ca1 used by the ABI as an argument register.
Definition cheri.h:210
@ CheriRegisterNumberCA4
$c14 / $ca4 used by the ABI as an argument register.
Definition cheri.h:225
@ CheriRegisterNumberInvalid
Indicates a value that is not used by the hardware to refer to a register.
Definition cheri.h:274
@ CheriRegisterNumberCA3
$c13 / $ca3 used by the ABI as an argument register.
Definition cheri.h:220
@ CheriRegisterNumberMScratchC
Machine-mode Scratch Capability.
Definition cheri.h:262
@ CheriRegisterNumberCtp
$c4 / $ctp used by the ABI as the thread pointer.
Definition cheri.h:175
@ CheriRegisterNumberMtdc
Machine-mode Tusted Data Capability.
Definition cheri.h:256
@ CheriRegisterNumberCS1
$c9 / $cs1 used by the ABI as a callee-saved register.
Definition cheri.h:200
@ CheriRegisterNumberCra
$c1 / $cra used by the ABI as the return address.
Definition cheri.h:158
@ CheriRegisterNumberCA5
$c15 / $ca5 used by the ABI as an argument register.
Definition cheri.h:230
@ CheriRegisterNumberCA0
$c10 / $ca0 used by the ABI as an argument register.
Definition cheri.h:205
@ CheriRegisterNumberCzr
The zero register, which always contains the NULL capability.
Definition cheri.h:153
@ CheriRegisterNumberPcc
The Program Counter Capability.
Definition cheri.h:238
@ CheriRegisterNumberMtcc
Machine-mode Trap Code Capability.
Definition cheri.h:247
bool __cheri_libcall check_pointer(const volatile void *ptr, size_t space, uint32_t rawPermissions, bool checkStackNeeded)
Checks that ptr is valid, unsealed, has at least rawPermissions, and has at least space bytes after t...
@ CheriCauseCodePermitStoreCapabilityViolation
Attempted to store a tagged capability via a capability without Permission::LoadStoreCapability.
Definition cheri.h:125
@ CheriCauseCodePermitStoreLocalCapabilityViolation
Attempted to store a tagged capability without Permission::Global via capability without Permission::...
Definition cheri.h:130
@ CheriCauseCodePermitExecuteViolation
Attempted to jump to a capability without Permission::Execute.
Definition cheri.h:112
@ CheriCauseCodePermitAccessSystemRegistersViolation
Attempted to access a restricted CSR or SCR with PCC without Permission::AccessSystemRegisters.
Definition cheri.h:135
@ CheriCauseCodeBoundsViolation
Attempted to use a capability outside its bounds.
Definition cheri.h:100
@ CheriCauseCodePermitLoadViolation
Attempted to load via a capability without Permission::Load.
Definition cheri.h:116
@ CheriCauseCodeSealViolation
Attempted to use a sealed capability to authorize something.
Definition cheri.h:108
@ CheriCauseCodeNone
No exception.
Definition cheri.h:96
@ CheriCauseCodeInvalid
Used to represent a value that has no valid meaning in hardware.
Definition cheri.h:139
@ CheriCauseCodeTagViolation
Attempted to use an untagged capability to authorize something.
Definition cheri.h:104
@ CheriCauseCodePermitStoreViolation
Attempted to store via a capability without Permission::Store.
Definition cheri.h:120
RegisterNumber
Register numbers as reported in thee cap idx field of mtval CSR when a CHERI exception is taken.
Definition cheri.hh:1441
@ CS0
$c8 / $cs0 used by the ABI as a callee-saved register.
Definition cheri.hh:1488
@ CA2
$c12 / $ca2 used by the ABI as an argument register.
Definition cheri.hh:1508
@ CT0
$c5 / $ct0 used by the ABI as temporary register.
Definition cheri.hh:1472
@ CA5
$c15 / $ca5 used by the ABI as an argument register.
Definition cheri.hh:1523
@ Invalid
Indicates a value that is not used by the hardware to refer to a register.
Definition cheri.hh:1567
@ CA0
$c10 / $ca0 used by the ABI as an argument register.
Definition cheri.hh:1498
@ MTDC
Machine-mode Tusted Data Capability.
Definition cheri.hh:1549
@ MTCC
Machine-mode Trap Code Capability.
Definition cheri.hh:1540
@ CS1
$c9 / $cs1 used by the ABI as a callee-saved register.
Definition cheri.hh:1493
@ CA4
$c14 / $ca4 used by the ABI as an argument register.
Definition cheri.hh:1518
@ CA3
$c13 / $ca3 used by the ABI as an argument register.
Definition cheri.hh:1513
@ CTP
$c4 / $ctp used by the ABI as the thread pointer.
Definition cheri.hh:1467
@ CZR
The zero register, which always contains the NULL capability.
Definition cheri.hh:1445
@ CT2
$c7 / $ct2 used by the ABI as temporary register.
Definition cheri.hh:1483
@ CT1
$c6 / $ct1 used by the ABI as temporary register.
Definition cheri.hh:1478
@ CRA
$c1 / $cra used by the ABI as the return address.
Definition cheri.hh:1450
@ CA1
$c11 / $ca1 used by the ABI as an argument register.
Definition cheri.hh:1503
@ CSP
$c2 / $csp used by the ABI as the stack pointer.
Definition cheri.hh:1455
@ PCC
The Program Counter Capability.
Definition cheri.hh:1531
@ CGP
$c3 / $cgp used by the ABI as the global pointer.
Definition cheri.hh:1461
@ MScratchC
Machine-mode Scratch Capability.
Definition cheri.hh:1555
@ MEPCC
Machine-mode Exception Program Counter Capability.
Definition cheri.hh:1562
remove_sealed< T >::type remove_sealed_t
Helper that provides the type of an unsealed capability from a sealed capability.
Definition cheri.hh:466
auto with_interrupts_disabled(T &&fn)
Invokes the passed callable object with interrupts disabled.
Definition cheri.hh:1370
std::pair< CauseCode, RegisterNumber > extract_cheri_mtval(uint32_t mtval)
Decompose the value reported in the mtval CSR on CHERI exception into a pair of CauseCode and Registe...
Definition cheri.hh:1579
CauseCode
The codes used in the cause field of the mtval CSR when the processor takes a CHERI exception.
Definition cheri.hh:1380
@ SealViolation
Attempted to use a sealed capability to authorize something.
Definition cheri.hh:1397
@ PermitStoreViolation
Attempted to store via a capability without Permission::Store.
Definition cheri.hh:1409
@ Invalid
Used to represent a value that has no valid meaning in hardware.
Definition cheri.hh:1431
@ PermitAccessSystemRegistersViolation
Attempted to access a restricted CSR or SCR with PCC without Permission::AccessSystemRegisters.
Definition cheri.hh:1426
@ PermitLoadViolation
Attempted to load via a capability without Permission::Load.
Definition cheri.hh:1405
@ PermitStoreCapabilityViolation
Attempted to store a tagged capability via a capability without Permission::LoadStoreCapability.
Definition cheri.hh:1414
@ None
No exception.
Definition cheri.hh:1385
@ TagViolation
Attempted to use an untagged capability to authorize something.
Definition cheri.hh:1393
@ PermitStoreLocalCapabilityViolation
Attempted to store a tagged capability without Permission::Global via capability without Permission::...
Definition cheri.hh:1420
@ BoundsViolation
Attempted to use a capability outside its bounds.
Definition cheri.hh:1389
@ PermitExecuteViolation
Attempted to jump to a capability without Permission::Execute.
Definition cheri.hh:1401
size_t representable_length(size_t length)
Rounds len up to a CHERI representable length for the current architecture.
Definition cheri.hh:368
bool is_precise_range(ptraddr_t base, size_t size)
Can the range [base, base + size) be precisely covered by a capability?
Definition cheri.hh:382
constexpr bool is_sealed_capability_v
Helper to check that a type is a sealed capability.
Definition cheri.hh:474
Permission
The complete set of architectural permissions.
Definition cheri.hh:21
@ Unseal
This capability may be used to unseal other capabilities.
Definition cheri.hh:73
@ LoadGlobal
Global capabilities can be loaded through this capability.
Definition cheri.hh:32
@ Execute
This capability may be used as a jump target and used to execute instructions.
Definition cheri.hh:67
@ Global
Capability refers to global memory (this capability may be stored anywhere).
Definition cheri.hh:26
@ AccessSystemRegisters
If installed as the program counter capability, running code may access privileged system registers.
Definition cheri.hh:62
@ LoadMutable
Capabilities with store permission may be loaded through this capability.
Definition cheri.hh:43
@ StoreLocal
This capability may be used to store capabilities that do not have Global permission.
Definition cheri.hh:48
@ Seal
This capability may be used to seal other capabilities.
Definition cheri.hh:79
@ Load
This capability can be used to load.
Definition cheri.hh:52
@ LoadStoreCapability
Any load and store permissions on this capability convey the right to load or store capabilities in a...
Definition cheri.hh:57
@ User0
Software defined permission bit, no architectural meaning.
Definition cheri.hh:83
@ Store
Capability may be used to store.
Definition cheri.hh:37
size_t representable_alignment_mask(size_t length)
Returns the alignment mask required for a given length.
Definition cheri.hh:376
Helper class for accessing capability properties on pointers.
Definition cheri.hh:482
Capability & align_up(size_t align)
Aligns the capability up to the nearest align-byte boundary.
Definition cheri.hh:1240
ptraddr_t top() const
Returns the address of the top of this capability.
Definition cheri.hh:1025
Capability< U, IsSealed > cast() const
Cast this capability to some other type.
Definition cheri.hh:1164
Capability< T, true > seal(void *key) const
Seal this capability with the given key.
Definition cheri.hh:1185
AddressProxy address()
Access the address of the capability.
Definition cheri.hh:851
constexpr Capability()
Default constructor, initialises with a null pointer.
Definition cheri.hh:837
constexpr bool operator==(std::nullptr_t) const
Equality operator, wraps the three-way compare operator.
Definition cheri.hh:1100
T * operator->() const
Access fields of the target as if this were a raw pointer.
Definition cheri.hh:1136
bool is_subset_of(Capability< U, IsSealed > other) const
Returns true if the tags of this and other match and if this conveys no rights that are not present i...
Definition cheri.hh:1177
Capability operator-(ptrdiff_t diff)
Pointer subtraction.
Definition cheri.hh:913
PermissionSet permissions() const
Get a copy of the permissions from a const capability.
Definition cheri.hh:891
Capability & operator-=(ptrdiff_t diff)
Pointer subtraction.
Definition cheri.hh:921
bool is_valid_temporal() const
Returns the tag bit indicating whether this is a valid capability.
Definition cheri.hh:975
Capability & align_down(size_t align)
Aligns the capability down to the nearest align-byte boundary.
Definition cheri.hh:1231
size_t length() const
Returns the length of this capability.
Definition cheri.hh:1017
friend class PropertyProxyBase
The property proxy base is allowed to directly access the pointer that this class wraps.
Definition cheri.hh:831
constexpr std::partial_ordering operator<=>(T *other) const
Capability comparison.
Definition cheri.hh:1040
ptraddr_t base() const
Returns the base address of this capability.
Definition cheri.hh:1009
Capability & operator+=(ptrdiff_t diff)
Pointer addition.
Definition cheri.hh:938
bool is_valid() const
Returns the tag bit indicating whether this is a valid capability.
Definition cheri.hh:955
uint32_t type() const
Returns the type of this capability, 0 if this is not a sealed capability.
Definition cheri.hh:1001
BoundsProxy bounds()
Access (read, set) the capability's bounds.
Definition cheri.hh:867
void without_permissions(Permissions... drop)
Remove some permissions from this capability.
Definition cheri.hh:905
T * get() const
Explicitly get the raw pointer.
Definition cheri.hh:1144
constexpr Capability(decltype(ptr) p)
Constructor, takes an existing pointer to wrap.
Definition cheri.hh:839
ptrdiff_t bounds() const
Return the bounds as an integer.
Definition cheri.hh:875
constexpr Capability(std::nullptr_t)
Constructor from a null pointer.
Definition cheri.hh:835
constexpr Capability(const Capability &other)=default
Copy constructor, aliases the object that is pointed to by ptr.
Capability< T, false > unseal(void *key) const
Unseal this capability with the given key.
Definition cheri.hh:1195
PointerType ptr
The capability that this class wraps.
Definition cheri.hh:490
PermissionsProxy permissions()
Access the permissions of this capability.
Definition cheri.hh:883
bool is_sealed() const
Return whether this is a sealed capability.
Definition cheri.hh:992
constexpr std::partial_ordering operator<=>(std::nullptr_t) const
Comparison against null pointer.
Definition cheri.hh:1052
bool is_aligned(size_t align) const
Returns true if the capability is align-byte aligned, false otherwise.
Definition cheri.hh:1223
Capability & operator=(const Capability &other)=default
Replace the pointer that this capability wraps with another.
Capability operator+(ptrdiff_t diff)
Pointer addition.
Definition cheri.hh:930
ptraddr_t address() const
Return the address as an integer from a const capability.
Definition cheri.hh:859
Helper for a value that encodes either a pointer or an error value in a pointer-sized value,...
Definition cheri.hh:1597
T * as_raw()
Returns the underlying pointer, which may be an untagged capability with integer error value.
Definition cheri.hh:1712
bool is_error()
Returns true if this holds an error value, false otherwise.
Definition cheri.hh:1632
int and_then(auto &&function)
Variant on and_then that returns an int: either the value returned by the callback,...
Definition cheri.hh:1775
T * as_pointer()
If this holds a pointer, return it, otherwise return nullptr.
Definition cheri.hh:1698
auto or_else(auto &&function)
Monadic helper modelled on std::optional.
Definition cheri.hh:1792
auto as_raw_capability()
Returns the underlying pointer, which may be an untagged capability with integer error value,...
Definition cheri.hh:1726
int as_error()
If this holds an error value, return it, otherwise return 0.
Definition cheri.hh:1688
ErrorOr(int error)
Initialise the value with an error value.
Definition cheri.hh:1623
auto and_then(auto &&function)
Monadic helper modelled on std::optional.
Definition cheri.hh:1740
ErrorOr(T *pointer)
Construct from a pointer.
Definition cheri.hh:1607
auto either(auto &&onT, auto &&onE)
Generic eliminator for ErrorOr<T> values.
Definition cheri.hh:1645
ErrorOr(Capability< T, IsSealed > pointer)
Construct from a CHERI::Capability.
Definition cheri.hh:1614
Class encapsulating a set of permissions.
Definition cheri.hh:90
uint32_t rawPermissions
The raw bitmap of permissions.
Definition cheri.hh:190
constexpr bool operator==(PermissionSet other) const
Equality operator, wraps the three-way compare operator.
Definition cheri.hh:357
constexpr Iterator begin() const
Returns an iterator over the permissions starting at the lowest-numbered permission.
Definition cheri.hh:316
constexpr auto operator<=>(const PermissionSet Other) const
Three-way comparison.
Definition cheri.hh:337
static constexpr PermissionSet omnipotent()
Returns a permission set representing all permissions.
Definition cheri.hh:231
constexpr bool can_derive_from(PermissionSet other) const
Returns true if, and only if, this permission set can be derived from the argument set.
Definition cheri.hh:277
constexpr PermissionSet(std::initializer_list< Permission > permissions)
Construct a permission set from a list of permissions.
Definition cheri.hh:212
constexpr PermissionSet without(Permission p) const
Constructs a new permission set without the specified permission.
Definition cheri.hh:258
constexpr uint32_t as_raw() const
Returns the raw permission mask as an integer containing a bitfield of permissions.
Definition cheri.hh:307
constexpr PermissionSet & operator&=(PermissionSet p)
And-permissions operation, removes all permissions that are not present in both permission sets.
Definition cheri.hh:249
constexpr PermissionSet(Permission p)
Constructs a permission set from a single permission.
Definition cheri.hh:204
static constexpr uint32_t valid_permissions_mask()
Computes (at compile time) a bitmask containing the set of valid permission bits.
Definition cheri.hh:128
static constexpr PermissionSet from_raw(uint32_t raw)
Constructs a permission set from a raw permission mask.
Definition cheri.hh:195
constexpr PermissionSet operator&(PermissionSet p)
And-permissions operation, creates a new permission set containing only permissions present in both t...
Definition cheri.hh:240
constexpr bool contains(Permission p, Permissions... ps) const
Returns true if this permission set contains the specified permissions.
Definition cheri.hh:297
constexpr Iterator end() const
Returns an end iterator.
Definition cheri.hh:324
constexpr bool contains(Permission permission) const
Returns true if this permission set contains the specified permission.
Definition cheri.hh:286
constexpr PermissionSet(const PermissionSet &other)=default
Copy constructor.
constexpr PermissionSet without(Permission p, Permissions... ps) const
Constructs a new permission set without the specified permissions.
Definition cheri.hh:267
Concept that matches pointers.
Definition cheri.hh:1269
Concept that matches smart pointers, i.e., classes which implements a get method returning a pointer,...
Definition cheri.hh:1278
Type trait for checking if a type is a sealed capability.
Definition cheri.hh:454
Type trait to remove sealed from a capability type.
Definition cheri.hh:438