[randstruct] Automatically randomize a structure of function pointers

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
This commit is contained in:
Bill Wendling 2022-04-29 11:04:58 -07:00
parent ec6d1a0278
commit 6f79700830
2 changed files with 63 additions and 2 deletions

View File

@ -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;

View File

@ -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