NoQ created this revision. NoQ added reviewers: aaron.ballman, dexonsmith, erik.pilkington, vsavchenko. Herald added subscribers: martong, Charusso, JDevlieghere, kristof.beyls. NoQ requested review of this revision.
Patch by Sean Dooher! I'll be addressing the review comments. The point is to markup a section of code (a set of functions) that should be isolated for security, basically like a TCB. Such section of code, being privileged in some specific manner, would not be allowed to exercise arbitrary behavior, so calling a function that's outside the set from a function that's inside the set is not allowed; they can only call each other. This is ultimately supposed to achieve security of the system with respect to that privilege through audit of the TCB. The patch adds an attribute `enforce_tcb` to define a TCB and a warning `-Wtcb-enforcement` for violating the enforcement. Additionally it adds an attribute `enforce_tcb_leaf` that allows opting out of enforcement for individual harmless functions: such "leaf" functions are allowed to be called from the respective TCB but aren't forced into the TCB themselves. https://reviews.llvm.org/D91898 Files: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/DiagnosticGroups.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaChecking.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/test/Sema/attr-enforce-tcb.c
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.}} +} 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<typename Attr> +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<UseHandleAttr>(S, D, AL); break; + + case ParsedAttr::AT_EnforceTCB: + handleEnforceTCBAttr<EnforceTCBAttr>(S, D, AL); + break; + + case ParsedAttr::AT_EnforceTCBLeaf: + handleEnforceTCBAttr<EnforceTCBLeafAttr>(S, D, AL); + break; } } 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<EnforceTCBAttr>() || 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<EnforceTCBAttr>()) { + CalleeTCBs.insert(Attr->getTCBName()); + } + for (const auto *Attr : Callee->specific_attrs<EnforceTCBLeafAttr>()) { + 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<EnforceTCBAttr>()) { + llvm::StringRef CallerTCB = Attr->getTCBName(); + + if (CalleeTCBs.count(CallerTCB) == 0) { + Diag(TheCall->getExprLoc(), diag::warn_tcb_enforcement_violation) << CallerTCB << Callee->getName(); + } + } +} 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/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<TCBEnforcement>; } // end of sema component. 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/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -5486,3 +5486,28 @@ <https://developer.arm.com/docs/ecm0359818/latest/>`_ 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/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; +}
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits