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.}}
+}