Skip to content

Commit

Permalink
[randstruct] Automatically randomize a structure of function pointers
Browse files Browse the repository at this point in the history
Strutures of function pointers are a good surface area for attacks. We
should therefore randomize them unless explicitly told not to.

Reviewed By: aaron.ballman, MaskRay

Differential Revision: https://reviews.llvm.org/D123544
  • Loading branch information
isanbard committed Apr 29, 2022
1 parent ec6d1a0 commit 6f79700
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
21 changes: 19 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Expand Up @@ -18057,8 +18057,25 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
// Handle attributes before checking the layout.
ProcessDeclAttributeList(S, Record, Attrs);

// Maybe randomize the record's decls.
if (!getLangOpts().CPlusPlus && Record->hasAttr<RandomizeLayoutAttr>() &&
// Check to see if a FieldDecl is a pointer to a function.
auto IsFunctionPointer = [&](const Decl *D) {
const FieldDecl *FD = dyn_cast<FieldDecl>(D);
if (!FD)
return false;
QualType FieldType = FD->getType().getDesugaredType(Context);
if (isa<PointerType>(FieldType)) {
QualType PointeeType = cast<PointerType>(FieldType)->getPointeeType();
return PointeeType.getDesugaredType(Context)->isFunctionType();
}
return false;
};

// Maybe randomize the record's decls. We automatically randomize a record
// of function pointers, unless it has the "no_randomize_layout" attribute.
if (!getLangOpts().CPlusPlus &&
(Record->hasAttr<RandomizeLayoutAttr>() ||
(!Record->hasAttr<NoRandomizeLayoutAttr>() &&
llvm::all_of(Record->decls(), IsFunctionPointer))) &&
!Record->isUnion() && !getLangOpts().RandstructSeed.empty() &&
!Record->isRandomized()) {
SmallVector<Decl *, 32> NewDeclOrdering;
Expand Down
44 changes: 44 additions & 0 deletions clang/unittests/AST/RandstructTest.cpp
Expand Up @@ -583,5 +583,49 @@ TEST(RANDSTRUCT_TEST, AnonymousStructsAndUnionsReferenced) {
EXPECT_EQ(OriginalDeclCount, declCount(RD));
}

TEST(RANDSTRUCT_TEST, AutoRandomizeStructOfFunctionPointers) {
const std::unique_ptr<ASTUnit> AST = makeAST(R"c(
typedef void (*func_ptr)();
struct test {
func_ptr a;
func_ptr b;
func_ptr c;
func_ptr d;
func_ptr e;
func_ptr f;
func_ptr g;
};
)c");

EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());

const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");

EXPECT_TRUE(RD->isRandomized());
}

TEST(RANDSTRUCT_TEST, DisableAutoRandomizeStructOfFunctionPointers) {
const std::unique_ptr<ASTUnit> AST = makeAST(R"c(
typedef void (*func_ptr)();
struct test {
func_ptr a;
func_ptr b;
func_ptr c;
func_ptr d;
func_ptr e;
func_ptr f;
func_ptr g;
} __attribute__((no_randomize_layout));
)c");

EXPECT_FALSE(AST->getDiagnostics().hasErrorOccurred());

const RecordDecl *RD = getRecordDeclFromAST(AST->getASTContext(), "test");

EXPECT_FALSE(RD->isRandomized());
}

} // namespace ast_matchers
} // namespace clang

0 comments on commit 6f79700

Please sign in to comment.