Index: clang/include/clang/Basic/Attr.td =================================================================== --- clang/include/clang/Basic/Attr.td +++ clang/include/clang/Basic/Attr.td @@ -3580,3 +3580,19 @@ let SemaHandler = 0; let Documentation = [Undocumented]; } + +def EnforceTCB : InheritableAttr { + let Spellings = [GCC<"enforce_tcb">]; + let Subjects = SubjectList<[Function]>; + let Args = [StringArgument<"TCBName">]; + let Documentation = [EnforceTCBDocs]; + bit InheritEvenIfAlreadyPresent = 1; +} + +def EnforceTCBLeaf : InheritableAttr { + let Spellings = [GCC<"enforce_tcb_leaf">]; + let Subjects = SubjectList<[Function]>; + let Args = [StringArgument<"TCBName">]; + let Documentation = [EnforceTCBLeafDocs]; + bit InheritEvenIfAlreadyPresent = 1; +} Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -5486,3 +5486,28 @@ `_ for more information. }]; } + +def EnforceTCBDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ + The ``enforce_tcb`` attribute can be placed on functions to enforce that a + trusted compute base (TCB) does not call out of the TCB. This generates a + warning everytime a function not marked with an enforce_tcb attribute is + called from a function with the enforce_tcb attribute. A function may be + a part of multiple TCBs. Invocations of function pointers and C++ methods + are not checked. Builtins are considered to a part of every TCB. + + - ``enforce_tcb(Name)`` indicates that this function is a part of the TCB named ``Name`` + }]; +} + +def EnforceTCBLeafDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ + The ``enforce_tcb_leaf`` attribute satisfies the requirement enforced by + ``enforce_tcb`` for the marked function to be in the named TCB but does not + continue to check the functions called from within the leaf function. + + - ``enforce_tcb_leaf(Name)`` indicates that this function is a part of the TCB named ``Name`` + }]; +} Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -1242,3 +1242,5 @@ def WebAssemblyExceptionSpec : DiagGroup<"wasm-exception-spec">; def RTTI : DiagGroup<"rtti">; + +def TCBEnforcement : DiagGroup<"tcb-enforcement">; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11046,4 +11046,9 @@ def err_probability_out_of_range : Error< "probability argument to __builtin_expect_with_probability is outside the " "range [0.0, 1.0]">; + +// TCB warnings +def warn_tcb_enforcement_violation : Warning< + "TCB [%0] has been violated by calling a function [%1] that is not in the TCB.">, + InGroup; } // end of sema component. Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -12451,6 +12451,8 @@ /// attempts to add itself into the container void CheckObjCCircularContainer(ObjCMessageExpr *Message); + void CheckTCBEnforcement(CallExpr *TheCall, FunctionDecl *Callee); + void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, bool DeleteWasArrayForm); Index: clang/lib/Sema/SemaChecking.cpp =================================================================== --- clang/lib/Sema/SemaChecking.cpp +++ clang/lib/Sema/SemaChecking.cpp @@ -75,6 +75,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/AtomicOrdering.h" @@ -4568,6 +4569,8 @@ if (!FnInfo) return false; + CheckTCBEnforcement(TheCall, FDecl); + CheckAbsoluteValueFunction(TheCall, FDecl); CheckMaxUnsignedZero(TheCall, FDecl); @@ -16058,3 +16061,34 @@ return CallResult; } + +/// \brief Enforce the bounds of a TCB +/// CheckTCBEnforcement - Enforces that every function in a named TCB only +/// directly calls other functions in the same TCB as marked by the enforce_tcb +/// and enforce_tcb_leaf attributes. +void Sema::CheckTCBEnforcement(CallExpr *TheCall, FunctionDecl *Callee) { + FunctionDecl *Caller = getCurFunctionDecl(); + + // Calls to builtins are not enforced + if (!Caller || !Caller->hasAttr() || Callee->getBuiltinID() != 0) { + return; + } + + // Search through the enforce_tcb and enforce_tcb_leaf attributes to find all TCBs the callee is a part of + llvm::StringSet<> CalleeTCBs; + for (const auto *Attr : Callee->specific_attrs()) { + CalleeTCBs.insert(Attr->getTCBName()); + } + for (const auto *Attr : Callee->specific_attrs()) { + CalleeTCBs.insert(Attr->getTCBName()); + } + + // Go through the TCBs the caller is a part of and emit warnings if Caller is in a TCB that the Callee is not + for (const auto *Attr : Caller->specific_attrs()) { + llvm::StringRef CallerTCB = Attr->getTCBName(); + + if (CalleeTCBs.count(CallerTCB) == 0) { + Diag(TheCall->getExprLoc(), diag::warn_tcb_enforcement_violation) << CallerTCB << Callee->getName(); + } + } +} Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -7336,6 +7336,14 @@ D->addAttr(::new (S.Context) CFGuardAttr(S.Context, AL, Arg)); } +template +static void handleEnforceTCBAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Argument; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument)) + return; + D->addAttr(Attr::Create(S.Context, Argument, AL)); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -8015,6 +8023,14 @@ case ParsedAttr::AT_UseHandle: handleHandleAttr(S, D, AL); break; + + case ParsedAttr::AT_EnforceTCB: + handleEnforceTCBAttr(S, D, AL); + break; + + case ParsedAttr::AT_EnforceTCBLeaf: + handleEnforceTCBAttr(S, D, AL); + break; } } Index: clang/test/Sema/attr-enforce-tcb.c =================================================================== --- /dev/null +++ clang/test/Sema/attr-enforce-tcb.c @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +#define PLACE_IN_TCB(NAME) __attribute__ ((enforce_tcb(NAME))) +#define PLACE_IN_TCB_LEAF(NAME) __attribute__ ((enforce_tcb_leaf(NAME))) + +void foo1 (void) PLACE_IN_TCB("bar"); +void foo2 (void) PLACE_IN_TCB("bar"); +void foo3 (void); // not in any TCB +void foo4 (void) PLACE_IN_TCB("bar2"); +void foo5 (void) PLACE_IN_TCB_LEAF("bar"); +void foo6 (void) PLACE_IN_TCB("bar2") PLACE_IN_TCB("bar"); +void foo7 (void) PLACE_IN_TCB("bar3"); +void foo8 (void) PLACE_IN_TCB("bar") PLACE_IN_TCB("bar2"); +void foo9 (void); + +void +foo1() +{ + foo2(); // OK - function in same TCB + foo3(); // expected-warning {{TCB [bar] has been violated by calling a function [foo3]}} + foo4(); // expected-warning {{TCB [bar] has been violated by calling a function [foo4]}} + foo5(); // OK - in leaf node + foo6(); // OK - in multiple TCBs, one of which is the same + foo7(); // expected-warning {{TCB [bar] has been violated by calling a function [foo7]}} + (void) __builtin_clz(5); // OK - builtins are excluded +} + +// Normal use without any attributes works +void +foo3() +{ + foo9(); // OK +} + +void +foo5() +{ + // all calls should be okay, function in TCB leaf + foo2(); + foo3(); + foo4(); +} + + +void +foo6() +{ + foo1(); // expected-warning {{TCB [bar2] has been violated by calling a function [foo1]}} + foo4(); // expected-warning {{TCB [bar] has been violated by calling a function [foo4]}} + foo8(); // OK + foo7(); // #1 + // expected-warning@#1 {{TCB [bar] has been violated by calling a function [foo7] that is not in the TCB.}} + // expected-warning@#1 {{TCB [bar2] has been violated by calling a function [foo7] that is not in the TCB.}} +}