Skip to content

Reinstate no randomize layout #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
1 change: 1 addition & 0 deletions clang/include/clang/AST/RandstructSeed.h
Original file line number Diff line number Diff line change
@@ -3,5 +3,6 @@
#include <string>
namespace clang {
extern std::string RandstructSeed;
extern bool RandstructAutoSelect;
}
#endif
3 changes: 3 additions & 0 deletions clang/include/clang/AST/RecordFieldReorganizer.h
Original file line number Diff line number Diff line change
@@ -37,6 +37,9 @@ class RecordFieldReorganizer {
};

class Randstruct : public RecordFieldReorganizer {
public:
/// Determines if the Record can be safely and easily randomized based on certain criteria (see implementation).
static bool isTriviallyRandomizable(const RecordDecl *D);
protected:
virtual void reorganize(const ASTContext &C, const RecordDecl *D,
SmallVector<Decl *, 64> &NewOrder) const override;
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
@@ -3208,3 +3208,10 @@ def RandomizeLayout : InheritableAttr {
let Subjects = SubjectList<[Record]>;
let Documentation = [ClangRandstructDocs];
}

def NoRandomizeLayout : InheritableAttr {
let Spellings = [GCC<"no_randomize_layout">, Declspec<"no_randomize_layout">,
Keyword<"no_randomize_layout">];
let Subjects = SubjectList<[Record]>;
let Documentation = [ClangRandstructDocs];
}
32 changes: 30 additions & 2 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
@@ -4099,10 +4099,24 @@ When compiled without ``-fobjc-arc``, this attribute is ignored.

def ClangRandstructDocs : Documentation {
let Category = DocCatVariable;
let Heading = "randomize_layout, no_randomize_layout";
let Content = [{
The attribute ``randomize_layout`` can be applied to the declaration of
a record. ``randomize_layout`` instructs the compiler to randomize the memory layout
The attributes ``randomize_layout`` and ``no_randomize_layout`` can be applied
to a record.

``randomize_layout`` instructs the compiler to randomize the memory layout
of the member variables of the record.

Conversely, ``no_randomize_layout`` is used to indicate that if using the
automatic strucuture selection feature of the Randstruct implementation, the
compiler should not shuffle the members of the record.

In the event that a record is labeled with both attributes, the compiler will
emit a warning indicating that these two cannot be used on the same record.
The default behavior in this case is to not randomize the struct, as the
attribute ``no_randomize_layout`` takes precedence over ``randomize_layout``.
This is implementation defined behavior.

.. code-block:: c

// Indicates that this struct should be randomized by Randstruct implementation.
@@ -4111,5 +4125,19 @@ of the member variables of the record.
char *b;
char *c;
}__attribute__((randomize_layout));

// Indicates that this struct should NOT be randomized by Randstruct implementation.
struct s {
char *a;
char *b;
char *c;
}__attribute__((no_randomize_layout));

// Emits compiler warning. Struct is NOT randomized by Randstruct implementation.
struct s {
char *a;
char *b;
char *c;
}__attribute__((randomize_layout)) __attribute__((no_randomize_layout));
}];
}
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticASTKinds.td
Original file line number Diff line number Diff line change
@@ -345,4 +345,7 @@ def warn_unnecessary_packed : Warning<
"packed attribute is unnecessary for %0">, InGroup<Packed>, DefaultIgnore;
def warn_randomize_attr_union : Warning<
"union declared with 'randomize_layout' attribute">, InGroup<DiagGroup<"randomize-layout">>;
def warn_randomize_attr_conflict : Warning<
"struct declared with 'randomize_layout' and 'no_randomize_layout' attributes; "
"attribute 'no_randomize_layout' takes precedence">, InGroup<DiagGroup<"no-randomize-layout">>;
}
3 changes: 3 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
@@ -1751,6 +1751,9 @@ def freroll_loops : Flag<["-"], "freroll-loops">, Group<f_Group>,
HelpText<"Turn on loop reroller">, Flags<[CC1Option]>;
def fno_reroll_loops : Flag<["-"], "fno-reroll-loops">, Group<f_Group>,
HelpText<"Turn off loop reroller">;
def randstruct_auto : Flag<["-"], "randstruct-auto">,
HelpText<"Enable automatic structure selection for field randomization; "
"disabled with no_randomize_layout">, Flags<[CC1Option]>;
def ftrigraphs : Flag<["-"], "ftrigraphs">, Group<f_Group>,
HelpText<"Process trigraph sequences">, Flags<[CC1Option]>;
def fno_trigraphs : Flag<["-"], "fno-trigraphs">, Group<f_Group>,
12 changes: 9 additions & 3 deletions clang/lib/AST/RecordFieldReorganizer.cpp
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@

namespace clang {
std::string RandstructSeed = "";
bool RandstructAutoSelect = false;

void RecordFieldReorganizer::reorganizeFields(const ASTContext &C,
const RecordDecl *D) const {
@@ -37,7 +38,6 @@ void RecordFieldReorganizer::reorganizeFields(const ASTContext &C,
mutateGuard.insert(f);
fields.push_back(f);
}

// Now allow subclass implementations to reorder the fields
reorganize(C, D, fields);

@@ -52,7 +52,6 @@ void RecordFieldReorganizer::reorganizeFields(const ASTContext &C,

commit(D, fields);
}

void RecordFieldReorganizer::commit(
const RecordDecl *D, SmallVectorImpl<Decl *> &NewFieldOrder) const {
Decl *First, *Last;
@@ -254,5 +253,12 @@ void Randstruct::reorganize(const ASTContext &C, const RecordDecl *D,
SmallVector<Decl *, 64> randomized = perfrandomize(C, NewOrder);
NewOrder = randomized;
}

bool Randstruct::isTriviallyRandomizable(const RecordDecl *D) {
for (auto f : D->fields()){
//If an element of the structure does not have a
//function type is not a function pointer
if(f->getFunctionType() == nullptr){ return false; }
}
return true;
}
} // namespace clang
25 changes: 15 additions & 10 deletions clang/lib/AST/RecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
@@ -2987,18 +2987,23 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
if (Entry) return *Entry;

const ASTRecordLayout *NewEntry = nullptr;

bool ShouldBeRandomized = D->getAttr<RandomizeLayoutAttr>() != nullptr;
if (ShouldBeRandomized) {
// There is no technical benefit to randomizing the fields of a union
// since they all share the same offset of zero.
if (D->isUnion()) {
bool NotToBeRandomized = D->getAttr<NoRandomizeLayoutAttr>() != nullptr;
bool AutoSelectable = RandstructAutoSelect && Randstruct::isTriviallyRandomizable(D);

if (ShouldBeRandomized && NotToBeRandomized) {
getDiagnostics().Report(D->getLocation(), diag::warn_randomize_attr_conflict);
}

if (ShouldBeRandomized && D->isUnion()) {
getDiagnostics().Report(D->getLocation(), diag::warn_randomize_attr_union);
}
else {
Randstruct randstruct;
randstruct.reorganizeFields(*this,D);
}
NotToBeRandomized = true;
}

if (!NotToBeRandomized && (ShouldBeRandomized || AutoSelectable)) {
Randstruct randstruct;
randstruct.reorganizeFields(*this,D);
}

if (isMsLayout(*this)) {
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
@@ -4411,6 +4411,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(A->getValue(0));
}

if (Arg *A = Args.getLastArg(options::OPT_randstruct_auto)) {
CmdArgs.push_back( "-randstruct-auto" );
}

// -fvisibility= and -fvisibility-ms-compat are of a piece.
if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ,
options::OPT_fvisibility_ms_compat)) {
3 changes: 3 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
@@ -1674,6 +1674,9 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
if (const Arg* A = Args.getLastArg(OPT_randstruct_seed)) {
RandstructSeed = A->getValue(0);
}
if (const Arg* A = Args.getLastArg(OPT_randstruct_auto)) {
RandstructAutoSelect = true;
}
Opts.AddPluginActions = Args.getAllArgValues(OPT_add_plugin);
for (const auto *AA : Args.filtered(OPT_plugin_arg))
Opts.PluginArgs[AA->getValue(0)].emplace_back(AA->getValue(1));
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
@@ -6856,6 +6856,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case ParsedAttr::AT_RandomizeLayout:
handleSimpleAttribute<RandomizeLayoutAttr>(S, D, AL);
break;
case ParsedAttr::AT_NoRandomizeLayout:
handleSimpleAttribute<NoRandomizeLayoutAttr>(S, D, AL);
break;
case ParsedAttr::AT_CodeSeg:
handleCodeSegAttr(S, D, AL);
break;
Original file line number Diff line number Diff line change
@@ -80,6 +80,7 @@
// CHECK-NEXT: NoInstrumentFunction (SubjectMatchRule_function)
// CHECK-NEXT: NoMicroMips (SubjectMatchRule_function)
// CHECK-NEXT: NoMips16 (SubjectMatchRule_function)
// CHECK-NEXT: NoRandomizeLayout (SubjectMatchRule_record)
// CHECK-NEXT: NoSanitize (SubjectMatchRule_function, SubjectMatchRule_objc_method, SubjectMatchRule_variable_is_global)
// CHECK-NEXT: NoSanitizeSpecific (SubjectMatchRule_function, SubjectMatchRule_variable_is_global)
// CHECK-NEXT: NoSpeculativeLoadHardening (SubjectMatchRule_function, SubjectMatchRule_objc_method)