Skip to content

Commit 72ed786

Browse files
[CHERI] Add a sealed type annotation (#109)
This allows us to disallow dereferences and pointer indexing on sealed capabilities at compile time. Builtins that introspect capabilities can all work on a sealed or unsealed capability. Builtins that mutate capabilities are all disallowed on sealed capabilities, with the exception of clear-tag (which works on sealed or unsealed things). Reinterpret cast and C-style (explicit) casts are allowed. Anyone who does an explicit unsafe cast should know what they're doing *anyway* this is another case of that. Implicit casts are also permitted to `void*`. This avoids needing new overloads for things that treat `void*` as opaque values. Casting back from `void*` to something useful already requires a dangerous explicit cast and you should know what you're doing if you do that. Also adds a __has_extension check for the sealed type qualifier. Co-authored-by: Owen Anderson <[email protected]>
1 parent 6d22636 commit 72ed786

38 files changed

+725
-363
lines changed

clang/include/clang/AST/Type.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,6 +1565,9 @@ enum PointerInterpretationKind {
15651565

15661566
/// The pointer should always be interpreted as an integer.
15671567
PIK_Integer,
1568+
1569+
/// The pointer should be interpreted as a sealed capability.
1570+
PIK_SealedCapability,
15681571
};
15691572

15701573
/// The base class of the type hierarchy.
@@ -1663,7 +1666,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
16631666

16641667
/// The interpretation (PointerInterpretationKind) to use for this array.
16651668
/// For function parameters only.
1666-
unsigned PIK : 1;
1669+
unsigned PIK : 2;
16671670

16681671
/// Whether the pointer interpretation for this array is set.
16691672
unsigned HasPIK : 1;
@@ -1672,7 +1675,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
16721675
class ConstantArrayTypeBitfields {
16731676
friend class ConstantArrayType;
16741677

1675-
unsigned : NumTypeBits + 3 + 3 + 2;
1678+
unsigned : NumTypeBits + 3 + 3 + 3;
16761679

16771680
/// Whether we have a stored size expression.
16781681
unsigned HasStoredSizeExpr : 1;
@@ -1759,7 +1762,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
17591762
unsigned : NumTypeBits;
17601763

17611764
/// The interpretation (PointerInterpretationKind) to use for this pointer.
1762-
unsigned PIK : 1;
1765+
unsigned PIK : 2;
17631766
};
17641767

17651768
class DependentPointerTypeBitfields {
@@ -1768,7 +1771,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
17681771
unsigned : NumTypeBits;
17691772

17701773
/// The interpretation (PointerInterpretationKind) to use for this pointer.
1771-
unsigned PIK : 1;
1774+
unsigned PIK : 2;
17721775
};
17731776

17741777
class ReferenceTypeBitfields {
@@ -1778,7 +1781,7 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
17781781

17791782
/// The interpretation (PointerInterpretationKind) to use for the pointer
17801783
/// backing this reference type.
1781-
unsigned PIK : 1;
1784+
unsigned PIK : 2;
17821785

17831786
/// True if the type was originally spelled with an lvalue sigil.
17841787
/// This is never true of rvalue references but can also be false
@@ -2239,6 +2242,9 @@ class alignas(8) Type : public ExtQualsTypeCommonBase {
22392242
/// pointers.
22402243
bool isCHERICapabilityType(const ASTContext &Context,
22412244
bool IncludeIntCap = true) const;
2245+
2246+
/// Returns true if this type is a Cheriot sealed capability.
2247+
bool isCHERISealedCapabilityType(const ASTContext &Context) const;
22422248
/// Returns true for __uintcap_t or __intcap_t (and enums/_Atomic with that
22432249
/// underlying type)
22442250
bool isIntCapType() const;
@@ -2898,7 +2904,8 @@ class PointerInterpretationTrait {
28982904

28992905
public:
29002906
bool isCHERICapability() const {
2901-
return getPointerInterpretation() == PIK_Capability;
2907+
return getPointerInterpretation() == PIK_Capability ||
2908+
getPointerInterpretation() == PIK_SealedCapability;
29022909
}
29032910

29042911
PointerInterpretationKind getPointerInterpretation() const {
@@ -2914,7 +2921,8 @@ class OptionalPointerInterpretationTrait {
29142921

29152922
public:
29162923
bool isCHERICapability() const {
2917-
return getPointerInterpretation() == PIK_Capability;
2924+
return getPointerInterpretation() == PIK_Capability ||
2925+
getPointerInterpretation() == PIK_SealedCapability;
29182926
}
29192927

29202928
std::optional<PointerInterpretationKind> getPointerInterpretation() const {

clang/include/clang/Basic/Attr.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,11 @@ def MinimumStack : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
873873
let Documentation = [Undocumented];
874874
}
875875

876+
def CHERISealedCapability : TypeAttr {
877+
let Spellings = [CustomKeyword<"__sealed_capability">];
878+
let Documentation = [Undocumented];
879+
}
880+
876881
def InterruptState : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
877882
let Spellings = [CXX11<"cheriot", "interrupt_state">,
878883
C2x<"cheriot", "interrupt_state">,

clang/include/clang/Basic/Builtins.def

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
// D -> volatile
7373
// R -> restrict
7474
// m -> memory capability
75+
// l -> sealed capability
7576

7677
// The third value provided to the macro specifies information about attributes
7778
// of the function. These must be kept in sync with the predicates in the
@@ -1699,17 +1700,17 @@ BUILTIN(__builtin_cheri_offset_set, "v*mvC*mY", "nct")
16991700
BUILTIN(__builtin_cheri_perms_and, "v*mvC*mz", "nct")
17001701
BUILTIN(__builtin_cheri_perms_check, "vvC*mCz", "nct")
17011702
BUILTIN(__builtin_cheri_perms_get, "zvC*m", "nct")
1702-
BUILTIN(__builtin_cheri_seal, "v*mvC*mvC*m", "nct")
1703-
BUILTIN(__builtin_cheri_seal_entry, "v*mvC*m", "nct")
1704-
BUILTIN(__builtin_cheri_sealed_get, "bvC*m", "nct")
1703+
BUILTIN(__builtin_cheri_seal, "v*lvC*mvC*m", "nct")
1704+
BUILTIN(__builtin_cheri_seal_entry, "v*lvC*m", "nct")
1705+
BUILTIN(__builtin_cheri_sealed_get, "bvC*l", "nct")
17051706
BUILTIN(__builtin_cheri_subset_test, "bvC*mvC*m", "nct")
17061707
BUILTIN(__builtin_cheri_tag_clear, "v*mvC*m", "nct")
17071708
BUILTIN(__builtin_cheri_tag_get, "bvC*m", "nct")
17081709
BUILTIN(__builtin_cheri_tag_get_temporal, "bvC*m", "nct")
17091710
BUILTIN(__builtin_cheri_top_get, "zvC*m", "nct")
17101711
BUILTIN(__builtin_cheri_type_check, "vvC*mvC*m", "nct")
17111712
BUILTIN(__builtin_cheri_type_get, "YvC*m", "nct")
1712-
BUILTIN(__builtin_cheri_unseal, "v*mvC*mvC*m", "nct")
1713+
BUILTIN(__builtin_cheri_unseal, "v*mvC*lvC*m", "nct")
17131714

17141715
BUILTIN(__builtin_cheri_callback_create, "v.", "nct")
17151716

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,8 @@ def err_expected_selector_for_method : Error<
319319
"expected selector for Objective-C method">;
320320
def err_expected_property_name : Error<"expected property name">;
321321

322-
def warn_cheri_capability_qualifier_location : Warning<
323-
"use of __capability before the pointer type is deprecated">,
322+
def warn_cheri_qualifier_location : Warning<
323+
"use of %0 before the pointer type is deprecated">,
324324
InGroup<DeprecatedDeclarations>;
325325

326326
def err_unexpected_at : Error<"unexpected '@' in program">;

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,10 +1336,22 @@ def note_cheri_func_decl_add_types : Note<
13361336
def err_cheri_capability_qualifier_not_supported : Error<
13371337
"use of __capability is not supported without CHERI; "
13381338
"specify an appropriate -march= or -mcpu=">;
1339-
def err_cheri_capability_qualifier_ambiguous : Error<
1340-
"use of __capability is ambiguous">;
1341-
def err_cheri_capability_qualifier_pointers_only : Error<
1342-
"__capability only applies to pointers; type here is %0">;
1339+
def err_cheri_sealed_qualifier_not_supported : Error<
1340+
"use of __sealed_capability is not supported without CHERI; "
1341+
"specify an appropriate -march= or -mcpu=">;
1342+
def err_cheri_qualifier_ambiguous : Error<
1343+
"use of %0 is ambiguous">;
1344+
def err_cheri_qualifier_pointers_only : Error<
1345+
"%0 only applies to pointers; type here is %1">;
1346+
def err_bad_cxx_cast_sealed_qualifier : Error<
1347+
"%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|"
1348+
"functional-style cast|addrspace_cast}0 from %1 to %2 changes sealed qualifier">;
1349+
def err_sealed_pointer_cast : Error<
1350+
"cast from %0 to %1 changes sealed qualifier">;
1351+
def err_typecheck_expect_sealed_operand : Error<
1352+
"operand of type %0 where sealed capability is required">;
1353+
def err_typecheck_expect_unsealed_operand : Error<
1354+
"operand of type %0 where unsealed capability is required">;
13431355

13441356
def err_objc_var_decl_inclass :
13451357
Error<"cannot declare variable inside @interface or @protocol">;
@@ -7306,6 +7318,20 @@ def err_typecheck_convert_ptr_to_cap_unrelated_type: Error<"cannot implicitly "
73067318
"or explicitly convert non-capability%select{| reference to}2 type %0 to "
73077319
"unrelated capability type %1">;
73087320

7321+
def err_typecheck_convert_sealed_to_ptr: Error<"converting sealed"
7322+
"%select{| reference to}2 type %0 to non-sealed type %1 without "
7323+
"an explicit unsealing">;
7324+
def err_typecheck_convert_ptr_to_sealed: Error<"converting unsealed"
7325+
"%select{| reference to}2 type %0 to sealed type %1 without "
7326+
"an explicit sealing">;
7327+
def err_sealed_reference: Error<"reference type %0 cannot be sealed">;
7328+
def err_sealed_bad_operator: Error<"invalid operator applied to sealed type %0">;
7329+
def err_sealed_this_pointer: Error<"sealed type %0 cannot be used as 'this' pointer for non-static method calls">;
7330+
def err_sealed_func_pointer: Error<"sealed type %0 cannot be called">;
7331+
def err_sealed_member_access: Error<"cannot access members of sealed type %0">;
7332+
7333+
7334+
73097335
def warn_uintcap_bitwise_and : Warning<
73107336
"using bitwise and on a capability type may give surprising results; "
73117337
"if this is an alignment check use __builtin_{is_aligned,align_up,align_down}(); "

clang/include/clang/Basic/Features.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ FEATURE(experimental_library, LangOpts.ExperimentalLibrary)
242242
FEATURE(capabilities, PP.getTargetInfo().SupportsCapabilities())
243243
FEATURE(pointer_interpretation, PP.getTargetInfo().SupportsCapabilities())
244244
FEATURE(cheri_casts, PP.getTargetInfo().SupportsCapabilities())
245+
// CHERI typed sealed pointers
246+
EXTENSION(cheri_sealed_pointers, PP.getTargetInfo().SupportsCapabilities())
245247

246248
// C11 features supported by other languages as extensions.
247249
EXTENSION(c_alignas, true)

clang/include/clang/Basic/TokenKinds.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ KEYWORD(__cheri_input , KEYALL)
341341
// CHERIoT Predefine Expr
342342
KEYWORD(__cheriot_minimum_stack__ , KEYALL)
343343

344+
// Cheriot Qualifiers
345+
KEYWORD(__sealed_capability , KEYALL)
346+
344347
// C++ 2.11p1: Keywords.
345348
KEYWORD(asm , KEYCXX|KEYGNU)
346349
KEYWORD(bool , BOOLSUPPORT|KEYC2X)

clang/include/clang/Parse/Parser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2976,6 +2976,7 @@ class Parser : public CodeCompletionHandler {
29762976
void ParseOpenCLQualifiers(ParsedAttributes &Attrs);
29772977
void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
29782978
void ParseCapabilityQualifier(ParsedAttributes &Attrs);
2979+
void ParseCheriotSealedQualifier(ParsedAttributes &Attrs);
29792980
void ParseCUDAFunctionAttributes(ParsedAttributes &attrs);
29802981
bool isHLSLQualifier(const Token &Tok) const;
29812982
void ParseHLSLQualifiers(ParsedAttributes &Attrs);

clang/lib/AST/ASTContext.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11768,14 +11768,15 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
1176811768
case 'R':
1176911769
Type = Type.withRestrict();
1177011770
break;
11771+
case 'l':
1177111772
case 'm': {
1177211773
Qualifiers Qs = Type.getQualifiers();
1177311774
if (const auto *PT = Type->getAs<PointerType>())
1177411775
Type = Context.getPointerType(PT->getPointeeType(), PIK_Capability);
1177511776
else if (const auto *LRT = Type->getAs<LValueReferenceType>())
11776-
Type = Context.getLValueReferenceType(LRT->getPointeeTypeAsWritten(),
11777-
LRT->isSpelledAsLValue(),
11778-
PIK_Capability);
11777+
Type = Context.getLValueReferenceType(
11778+
LRT->getPointeeTypeAsWritten(), LRT->isSpelledAsLValue(),
11779+
c == 'l' ? PIK_SealedCapability : PIK_Capability);
1177911780
else {
1178011781
const auto *BT = Type->getAs<BuiltinType>();
1178111782
assert(BT &&

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3594,7 +3594,10 @@ void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
35943594

35953595
// <type> ::= P <type> # pointer-to
35963596
void CXXNameMangler::mangleType(const PointerType *T) {
3597-
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability())
3597+
if (T->getPointerInterpretation() == PIK_SealedCapability)
3598+
Out << "U19__sealed_capability";
3599+
else if (Context.shouldMangleCapabilityQualifier() &&
3600+
T->getPointerInterpretation() == PIK_Capability)
35983601
Out << "U12__capability";
35993602
Out << 'P';
36003603
mangleType(T->getPointeeType());
@@ -3606,16 +3609,21 @@ void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) {
36063609

36073610
// <type> ::= R <type> # reference-to
36083611
void CXXNameMangler::mangleType(const LValueReferenceType *T) {
3609-
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability())
3612+
if (T->getPointerInterpretation() == PIK_SealedCapability)
3613+
Out << "U19__sealed_capability";
3614+
else if (Context.shouldMangleCapabilityQualifier() &&
3615+
T->getPointerInterpretation() == PIK_Capability)
36103616
Out << "U12__capability";
36113617
Out << 'R';
36123618
mangleType(T->getPointeeType());
36133619
}
36143620

36153621
// <type> ::= O <type> # rvalue reference-to (C++0x)
36163622
void CXXNameMangler::mangleType(const RValueReferenceType *T) {
3617-
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability())
3623+
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability()) {
3624+
assert(T->getPointerInterpretation() != PIK_SealedCapability);
36183625
Out << "U12__capability";
3626+
}
36193627
Out << 'O';
36203628
mangleType(T->getPointeeType());
36213629
}
@@ -4057,7 +4065,10 @@ void CXXNameMangler::mangleType(const DependentAddressSpaceType *T) {
40574065
}
40584066

40594067
void CXXNameMangler::mangleType(const DependentPointerType *T) {
4060-
if (Context.shouldMangleCapabilityQualifier() && T->isCHERICapability())
4068+
if (T->getPointerInterpretation() == PIK_SealedCapability)
4069+
Out << "U19__sealed_capability";
4070+
else if (Context.shouldMangleCapabilityQualifier() &&
4071+
T->getPointerInterpretation() == PIK_Capability)
40614072
Out << "U12__capability";
40624073
mangleType(T->getPointerType());
40634074
}

0 commit comments

Comments
 (0)