[clang] c163aae - [attributes] Add a facility for enforcing a Trusted Computing Base.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 11 06:39:57 PST 2021


Author: Artem Dergachev
Date: 2021-01-11T06:39:42-08:00
New Revision: c163aae45ef6b7f3bd99601195d3ce4aad5850c6

URL: https://github.com/llvm/llvm-project/commit/c163aae45ef6b7f3bd99601195d3ce4aad5850c6
DIFF: https://github.com/llvm/llvm-project/commit/c163aae45ef6b7f3bd99601195d3ce4aad5850c6.diff

LOG: [attributes]  Add a facility for enforcing a Trusted Computing Base.

Introduce a function attribute 'enforce_tcb' that prevents the function
from calling other functions without the same attribute. This allows
isolating code that's considered to be somehow privileged so that it could not
use its privileges to exhibit arbitrary behavior.

Introduce an on-by-default warning '-Wtcb-enforcement' that warns
about violations of the above rule.

Introduce a function attribute 'enforce_tcb_leaf' that suppresses
the new warning within the function it is attached to. Such leaf functions
may implement common functionality between the trusted and the untrusted code
but they require extra careful audit with respect to their capabilities.

Differential Revision: https://reviews.llvm.org/D91898

Added: 
    clang/test/Sema/attr-enforce-tcb-errors.cpp
    clang/test/Sema/attr-enforce-tcb.c
    clang/test/Sema/attr-enforce-tcb.cpp

Modified: 
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/Sema/SemaChecking.cpp
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclAttr.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 248409946123..c51e95fa6fa8 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3653,3 +3653,19 @@ def Builtin : InheritableAttr {
   let SemaHandler = 0;
   let Documentation = [Undocumented];
 }
+
+def EnforceTCB : InheritableAttr {
+  let Spellings = [Clang<"enforce_tcb">];
+  let Subjects = SubjectList<[Function]>;
+  let Args = [StringArgument<"TCBName">];
+  let Documentation = [EnforceTCBDocs];
+  bit InheritEvenIfAlreadyPresent = 1;
+}
+
+def EnforceTCBLeaf : InheritableAttr {
+  let Spellings = [Clang<"enforce_tcb_leaf">];
+  let Subjects = SubjectList<[Function]>;
+  let Args = [StringArgument<"TCBName">];
+  let Documentation = [EnforceTCBLeafDocs];
+  bit InheritEvenIfAlreadyPresent = 1;
+}

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 9cf0c59e07bb..fffede41db1e 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -5725,3 +5725,28 @@ Attribute docs`_, and `the GCC Inline docs`_.
 }];
   let Heading = "always_inline, __force_inline";
 }
+
+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 every time 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 through function pointers are currently
+  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``
+  }];
+}

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0405195912b2..c048fc89813f 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11116,4 +11116,11 @@ def err_probability_not_constant_float : Error<
 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 err_tcb_conflicting_attributes : Error<
+  "attributes '%0(\"%2\")' and '%1(\"%2\")' are mutually exclusive">;
+def warn_tcb_enforcement_violation : Warning<
+  "calling %0 is a violation of trusted computing base '%1'">,
+  InGroup<DiagGroup<"tcb-enforcement">>;
 } // end of sema component.

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1d79e5716ef7..4de3b962c660 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3210,6 +3210,9 @@ class Sema final {
       Decl *D, const WebAssemblyImportNameAttr &AL);
   WebAssemblyImportModuleAttr *mergeImportModuleAttr(
       Decl *D, const WebAssemblyImportModuleAttr &AL);
+  EnforceTCBAttr *mergeEnforceTCBAttr(Decl *D, const EnforceTCBAttr &AL);
+  EnforceTCBLeafAttr *mergeEnforceTCBLeafAttr(Decl *D,
+                                              const EnforceTCBLeafAttr &AL);
 
   void mergeDeclAttributes(NamedDecl *New, Decl *Old,
                            AvailabilityMergeKind AMK = AMK_Redeclaration);
@@ -12427,6 +12430,8 @@ class Sema final {
   /// attempts to add itself into the container
   void CheckObjCCircularContainer(ObjCMessageExpr *Message);
 
+  void CheckTCBEnforcement(const CallExpr *TheCall, const FunctionDecl *Callee);
+
   void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE);
   void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc,
                                  bool DeleteWasArrayForm);

diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 7e83a39b16ab..440b0a38481b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/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"
@@ -4569,6 +4570,8 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
   if (!FnInfo)
     return false;
 
+  CheckTCBEnforcement(TheCall, FDecl);
+
   CheckAbsoluteValueFunction(TheCall, FDecl);
   CheckMaxUnsignedZero(TheCall, FDecl);
 
@@ -16059,3 +16062,37 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall,
 
   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(const CallExpr *TheCall,
+                               const FunctionDecl *Callee) {
+  const 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_each(Callee->specific_attrs<EnforceTCBAttr>(),
+           [&](const auto *A) { CalleeTCBs.insert(A->getTCBName()); });
+  for_each(Callee->specific_attrs<EnforceTCBLeafAttr>(),
+           [&](const auto *A) { CalleeTCBs.insert(A->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_each(
+      Caller->specific_attrs<EnforceTCBAttr>(),
+      [&](const auto *A) {
+        StringRef CallerTCB = A->getTCBName();
+        if (CalleeTCBs.count(CallerTCB) == 0) {
+          Diag(TheCall->getExprLoc(), diag::warn_tcb_enforcement_violation)
+              << Callee << CallerTCB;
+        }
+      });
+}

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index dd31f3f98487..3cd32f894bd1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2612,6 +2612,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
     NewAttr = S.mergeImportModuleAttr(D, *IMA);
   else if (const auto *INA = dyn_cast<WebAssemblyImportNameAttr>(Attr))
     NewAttr = S.mergeImportNameAttr(D, *INA);
+  else if (const auto *TCBA = dyn_cast<EnforceTCBAttr>(Attr))
+    NewAttr = S.mergeEnforceTCBAttr(D, *TCBA);
+  else if (const auto *TCBLA = dyn_cast<EnforceTCBLeafAttr>(Attr))
+    NewAttr = S.mergeEnforceTCBLeafAttr(D, *TCBLA);
   else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr))
     NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
 

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 0872cc640b39..bd8ec2bdef76 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7517,6 +7517,75 @@ static void handleCFGuardAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   D->addAttr(::new (S.Context) CFGuardAttr(S.Context, AL, Arg));
 }
 
+
+template <typename AttrTy>
+static const AttrTy *findEnforceTCBAttrByName(Decl *D, StringRef Name) {
+  auto Attrs = D->specific_attrs<AttrTy>();
+  auto I = llvm::find_if(Attrs,
+                         [Name](const AttrTy *A) {
+                           return A->getTCBName() == Name;
+                         });
+  return I == Attrs.end() ? nullptr : *I;
+}
+
+template <typename AttrTy, typename ConflictingAttrTy>
+static void handleEnforceTCBAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
+  StringRef Argument;
+  if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument))
+    return;
+
+  // A function cannot be have both regular and leaf membership in the same TCB.
+  if (const ConflictingAttrTy *ConflictingAttr =
+      findEnforceTCBAttrByName<ConflictingAttrTy>(D, Argument)) {
+    // We could attach a note to the other attribute but in this case
+    // there's no need given how the two are very close to each other.
+    S.Diag(AL.getLoc(), diag::err_tcb_conflicting_attributes)
+      << AL.getAttrName()->getName() << ConflictingAttr->getAttrName()->getName()
+      << Argument;
+
+    // Error recovery: drop the non-leaf attribute so that to suppress
+    // all future warnings caused by erroneous attributes. The leaf attribute
+    // needs to be kept because it can only suppresses warnings, not cause them.
+    D->dropAttr<EnforceTCBAttr>();
+    return;
+  }
+
+  D->addAttr(AttrTy::Create(S.Context, Argument, AL));
+}
+
+template <typename AttrTy, typename ConflictingAttrTy>
+static AttrTy *mergeEnforceTCBAttrImpl(Sema &S, Decl *D, const AttrTy &AL) {
+  // Check if the new redeclaration has 
diff erent leaf-ness in the same TCB.
+  StringRef TCBName = AL.getTCBName();
+  if (const ConflictingAttrTy *ConflictingAttr =
+      findEnforceTCBAttrByName<ConflictingAttrTy>(D, TCBName)) {
+    S.Diag(ConflictingAttr->getLoc(), diag::err_tcb_conflicting_attributes)
+      << ConflictingAttr->getAttrName()->getName()
+      << AL.getAttrName()->getName() << TCBName;
+
+    // Add a note so that the user could easily find the conflicting attribute.
+    S.Diag(AL.getLoc(), diag::note_conflicting_attribute);
+
+    // More error recovery.
+    D->dropAttr<EnforceTCBAttr>();
+    return nullptr;
+  }
+
+  ASTContext &Context = S.getASTContext();
+  return ::new(Context) AttrTy(Context, AL, AL.getTCBName());
+}
+
+EnforceTCBAttr *Sema::mergeEnforceTCBAttr(Decl *D, const EnforceTCBAttr &AL) {
+  return mergeEnforceTCBAttrImpl<EnforceTCBAttr, EnforceTCBLeafAttr>(
+      *this, D, AL);
+}
+
+EnforceTCBLeafAttr *Sema::mergeEnforceTCBLeafAttr(
+    Decl *D, const EnforceTCBLeafAttr &AL) {
+  return mergeEnforceTCBAttrImpl<EnforceTCBLeafAttr, EnforceTCBAttr>(
+      *this, D, AL);
+}
+
 //===----------------------------------------------------------------------===//
 // Top Level Sema Entry Points
 //===----------------------------------------------------------------------===//
@@ -8220,6 +8289,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
   case ParsedAttr::AT_UseHandle:
     handleHandleAttr<UseHandleAttr>(S, D, AL);
     break;
+
+  case ParsedAttr::AT_EnforceTCB:
+    handleEnforceTCBAttr<EnforceTCBAttr, EnforceTCBLeafAttr>(S, D, AL);
+    break;
+
+  case ParsedAttr::AT_EnforceTCBLeaf:
+    handleEnforceTCBAttr<EnforceTCBLeafAttr, EnforceTCBAttr>(S, D, AL);
+    break;
   }
 }
 

diff  --git a/clang/test/Sema/attr-enforce-tcb-errors.cpp b/clang/test/Sema/attr-enforce-tcb-errors.cpp
new file mode 100644
index 000000000000..1ce147ab32df
--- /dev/null
+++ b/clang/test/Sema/attr-enforce-tcb-errors.cpp
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+[[clang::enforce_tcb("oops")]] int wrong_subject_type; // expected-warning{{'enforce_tcb' attribute only applies to functions}}
+
+void no_arguments() __attribute__((enforce_tcb)); // expected-error{{'enforce_tcb' attribute takes one argument}}
+
+void too_many_arguments() __attribute__((enforce_tcb("test", 12))); // expected-error{{'enforce_tcb' attribute takes one argument}}
+
+void wrong_argument_type() __attribute__((enforce_tcb(12))); // expected-error{{'enforce_tcb' attribute requires a string}}
+
+[[clang::enforce_tcb_leaf("oops")]] int wrong_subject_type_leaf; // expected-warning{{'enforce_tcb_leaf' attribute only applies to functions}}
+
+void no_arguments_leaf() __attribute__((enforce_tcb_leaf)); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
+
+void too_many_arguments_leaf() __attribute__((enforce_tcb_leaf("test", 12))); // expected-error{{'enforce_tcb_leaf' attribute takes one argument}}
+void wrong_argument_type_leaf() __attribute__((enforce_tcb_leaf(12))); // expected-error{{'enforce_tcb_leaf' attribute requires a string}}
+
+void foo();
+
+__attribute__((enforce_tcb("x")))
+__attribute__((enforce_tcb_leaf("x"))) // expected-error{{attributes 'enforce_tcb_leaf("x")' and 'enforce_tcb("x")' are mutually exclusive}}
+void both_tcb_and_tcb_leaf() {
+  foo(); // no-warning
+}
+
+__attribute__((enforce_tcb_leaf("x"))) // expected-note{{conflicting attribute is here}}
+void both_tcb_and_tcb_leaf_on_separate_redeclarations();
+__attribute__((enforce_tcb("x"))) // expected-error{{attributes 'enforce_tcb("x")' and 'enforce_tcb_leaf("x")' are mutually exclusive}}
+void both_tcb_and_tcb_leaf_on_separate_redeclarations() {
+  // Error recovery: no need to emit a warning when we didn't
+  // figure out our attributes to begin with.
+  foo(); // no-warning
+}
+
+__attribute__((enforce_tcb_leaf("x")))
+__attribute__((enforce_tcb("x"))) // expected-error{{attributes 'enforce_tcb("x")' and 'enforce_tcb_leaf("x")' are mutually exclusive}}
+void both_tcb_and_tcb_leaf_opposite_order() {
+  foo(); // no-warning
+}
+
+__attribute__((enforce_tcb("x"))) // expected-note{{conflicting attribute is here}}
+void both_tcb_and_tcb_leaf_on_separate_redeclarations_opposite_order();
+__attribute__((enforce_tcb_leaf("x"))) // expected-error{{attributes 'enforce_tcb_leaf("x")' and 'enforce_tcb("x")' are mutually exclusive}}
+void both_tcb_and_tcb_leaf_on_separate_redeclarations_opposite_order() {
+  foo(); // no-warning
+}
+
+__attribute__((enforce_tcb("x")))
+__attribute__((enforce_tcb_leaf("y"))) // no-error
+void both_tcb_and_tcb_leaf_but_
diff erent_identifiers() {
+  foo(); // expected-warning{{calling 'foo' is a violation of trusted computing base 'x'}}
+}
+__attribute__((enforce_tcb_leaf("x")))
+__attribute__((enforce_tcb("y"))) // no-error
+void both_tcb_and_tcb_leaf_but_
diff erent_identifiers_opposite_order() {
+  foo(); // expected-warning{{calling 'foo' is a violation of trusted computing base 'y'}}
+}
+
+__attribute__((enforce_tcb("x")))
+void both_tcb_and_tcb_leaf_but_
diff erent_identifiers_on_separate_redeclarations();
+__attribute__((enforce_tcb_leaf("y"))) // no-error
+void both_tcb_and_tcb_leaf_but_
diff erent_identifiers_on_separate_redeclarations() {
+  foo(); // expected-warning{{calling 'foo' is a violation of trusted computing base 'x'}}
+}
+
+__attribute__((enforce_tcb_leaf("x")))
+void both_tcb_and_tcb_leaf_but_
diff erent_identifiers_on_separate_redeclarations_opposite_order();
+__attribute__((enforce_tcb("y")))
+void both_tcb_and_tcb_leaf_but_
diff erent_identifiers_on_separate_redeclarations_opposite_order() {
+  foo(); // expected-warning{{calling 'foo' is a violation of trusted computing base 'y'}}
+}
+
+__attribute__((enforce_tcb("y")))
+__attribute__((enforce_tcb("x")))
+__attribute__((enforce_tcb_leaf("x"))) // expected-error{{attributes 'enforce_tcb_leaf("x")' and 'enforce_tcb("x")' are mutually exclusive}}
+void error_recovery_over_individual_tcbs() {
+  // FIXME: Ideally this should warn. The conflict between attributes
+  // for TCB "x" shouldn't affect the warning about TCB "y".
+  foo(); // no-warning
+}

diff  --git a/clang/test/Sema/attr-enforce-tcb.c b/clang/test/Sema/attr-enforce-tcb.c
new file mode 100644
index 000000000000..2807f770ce73
--- /dev/null
+++ b/clang/test/Sema/attr-enforce-tcb.c
@@ -0,0 +1,65 @@
+// 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 {{calling 'foo3' is a violation of trusted computing base 'bar'}}
+    foo4(); // expected-warning {{calling 'foo4' is a violation of trusted computing base 'bar'}}
+    foo5(); // OK - in leaf node
+    foo6(); // OK - in multiple TCBs, one of which is the same
+    foo7(); // expected-warning {{calling 'foo7' is a violation of trusted computing base 'bar'}}
+    (void) __builtin_clz(5); // OK - builtins are excluded
+}
+
+// Normal use without any attributes works
+void foo3() {
+    foo9(); // no-warning
+}
+
+void foo5() {
+    // all calls should be okay, function in TCB leaf
+    foo2(); // no-warning
+    foo3(); // no-warning
+    foo4(); // no-warning
+}
+
+void foo6() {
+    foo1(); // expected-warning {{calling 'foo1' is a violation of trusted computing base 'bar2'}}
+    foo4(); // expected-warning {{calling 'foo4' is a violation of trusted computing base 'bar'}}
+    foo8(); // no-warning
+    foo7(); // #1
+    // expected-warning@#1 {{calling 'foo7' is a violation of trusted computing base 'bar2'}}
+    // expected-warning@#1 {{calling 'foo7' is a violation of trusted computing base 'bar'}}
+}
+
+// Ensure that attribute merging works as expected across redeclarations.
+void foo10() PLACE_IN_TCB("bar");
+void foo10() PLACE_IN_TCB("bar2");
+void foo10() PLACE_IN_TCB("bar3");
+void foo10() {
+  foo1(); // #2
+    // expected-warning@#2 {{calling 'foo1' is a violation of trusted computing base 'bar2'}}
+    // expected-warning@#2 {{calling 'foo1' is a violation of trusted computing base 'bar3'}}
+  foo3(); // #3
+    // expected-warning@#3 {{calling 'foo3' is a violation of trusted computing base 'bar'}}
+    // expected-warning@#3 {{calling 'foo3' is a violation of trusted computing base 'bar2'}}
+    // expected-warning@#3 {{calling 'foo3' is a violation of trusted computing base 'bar3'}}
+  foo4(); // #4
+    // expected-warning@#4 {{calling 'foo4' is a violation of trusted computing base 'bar'}}
+    // expected-warning@#4 {{calling 'foo4' is a violation of trusted computing base 'bar3'}}
+  foo7(); // #5
+    // expected-warning@#5 {{calling 'foo7' is a violation of trusted computing base 'bar'}}
+    // expected-warning@#5 {{calling 'foo7' is a violation of trusted computing base 'bar2'}}
+}

diff  --git a/clang/test/Sema/attr-enforce-tcb.cpp b/clang/test/Sema/attr-enforce-tcb.cpp
new file mode 100644
index 000000000000..a01a1775e94b
--- /dev/null
+++ b/clang/test/Sema/attr-enforce-tcb.cpp
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#define PLACE_IN_TCB(NAME) [[clang::enforce_tcb(NAME)]]
+#define PLACE_IN_TCB_LEAF(NAME) [[clang::enforce_tcb_leaf(NAME)]]
+
+PLACE_IN_TCB("foo") void in_tcb_foo();
+void not_in_tcb();
+
+// Test behavior on classes and methods.
+class C {
+  void bar();
+
+  PLACE_IN_TCB("foo")
+  void foo() {
+    // TODO: Figure out if we want to support methods at all.
+    // Does it even make sense to isolate individual methods into a TCB?
+    // Maybe a per-class attribute would make more sense?
+    bar(); // expected-warning{{calling 'bar' is a violation of trusted computing base 'foo'}}
+  }
+};
+
+// Test behavior on templates.
+template <typename Ty>
+PLACE_IN_TCB("foo")
+void foo_never_instantiated() {
+  not_in_tcb(); // expected-warning{{calling 'not_in_tcb' is a violation of trusted computing base 'foo'}}
+  in_tcb_foo(); // no-warning
+}
+
+template <typename Ty>
+PLACE_IN_TCB("foo")
+void foo_specialized();
+
+template<>
+void foo_specialized<int>() {
+  not_in_tcb(); // expected-warning{{calling 'not_in_tcb' is a violation of trusted computing base 'foo'}}
+  in_tcb_foo(); // no-warning
+}
+
+PLACE_IN_TCB("foo")
+void call_template_good() {
+  foo_specialized<int>(); // no-warning
+}
+PLACE_IN_TCB("bar")
+void call_template_bad() {
+  foo_specialized<int>(); // expected-warning{{calling 'foo_specialized<int>' is a violation of trusted computing base 'bar'}}
+}
+
+template<typename Ty>
+void foo_specialization_in_tcb();
+
+template<>
+PLACE_IN_TCB("foo")
+void foo_specialization_in_tcb<int>() {
+  not_in_tcb(); //expected-warning{{calling 'not_in_tcb' is a violation of trusted computing base 'foo'}}
+  in_tcb_foo(); // no-warning
+}
+
+template<>
+void foo_specialization_in_tcb<double>() {
+  not_in_tcb(); // no-warning
+  in_tcb_foo(); // no-warning
+}
+
+PLACE_IN_TCB("foo")
+void call_specialization_in_tcb() {
+  foo_specialization_in_tcb<int>(); // no-warning
+  foo_specialization_in_tcb<long>(); // expected-warning{{calling 'foo_specialization_in_tcb<long>' is a violation of trusted computing base 'foo'}}
+  foo_specialization_in_tcb<double>(); // expected-warning{{'foo_specialization_in_tcb<double>' is a violation of trusted computing base 'foo'}}
+}


        


More information about the cfe-commits mailing list