Skip to content

Commit 7aa8c38

Browse files
connorkuehlisanbard
authored andcommitted
[randstruct] Add randomize structure layout support
The Randstruct feature is a compile-time hardening technique that randomizes the field layout for designated structures of a code base. Admittedly, this is mostly useful for closed-source releases of code, since the randomization seed would need to be available for public and open source applications. Why implement it? This patch set enhances Clang’s feature parity with that of GCC which already has the Randstruct feature. It's used by the Linux kernel in certain structures to help thwart attacks that depend on structure layouts in memory. This patch set is a from-scratch reimplementation of the Randstruct feature that was originally ported to GCC. The patches for the GCC implementation can be found here: https://www.openwall.com/lists/kernel-hardening/2017/04/06/14 Link: https://lists.llvm.org/pipermail/cfe-dev/2019-March/061607.html Co-authored-by: Cole Nixon <nixontcole@gmail.com> Co-authored-by: Connor Kuehl <cipkuehl@gmail.com> Co-authored-by: James Foster <jafosterja@gmail.com> Co-authored-by: Jeff Takahashi <jeffrey.takahashi@gmail.com> Co-authored-by: Jordan Cantrell <jordan.cantrell@mail.com> Co-authored-by: Nikk Forbus <nicholas.forbus@gmail.com> Co-authored-by: Tim Pugh <nwtpugh@gmail.com> Co-authored-by: Bill Wendling <isanbard@gmail.com> Signed-off-by: Bill Wendling <isanbard@gmail.com> Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D121556
1 parent d5e66c1 commit 7aa8c38

21 files changed

+859
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@ Major New Features
5454
There is an analogous ``zero_call_used_regs`` attribute to allow for finer
5555
control of this feature.
5656

57+
- Clang now supports randomizing structure layout in C. This feature is a
58+
compile-time hardening technique, making it more difficult for an attacker to
59+
retrieve data from structures. Specify randomization with the
60+
``randomize_layout`` attribute. The corresponding ``no_randomize_layout``
61+
attribute can be used to turn the feature off.
62+
63+
A seed value is required to enable randomization, and is deterministic based
64+
on a seed value. Use the ``-frandomize-layout-seed=`` or
65+
``-frandomize-layout-seed-file=`` flags.
66+
67+
.. note::
68+
69+
Randomizing structure layout is a C-only feature.
70+
5771
Bug Fixes
5872
------------------
5973
- ``CXXNewExpr::getArraySize()`` previously returned a ``llvm::Optional``

clang/include/clang/AST/Decl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4051,6 +4051,12 @@ class RecordDecl : public TagDecl {
40514051
RecordDeclBits.ParamDestroyedInCallee = V;
40524052
}
40534053

4054+
bool isRandomized() const { return RecordDeclBits.IsRandomized; }
4055+
4056+
void setIsRandomized(bool V) { RecordDeclBits.IsRandomized = V; }
4057+
4058+
void reorderFields(const SmallVectorImpl<Decl *> &Fields);
4059+
40544060
/// Determines whether this declaration represents the
40554061
/// injected class name.
40564062
///

clang/include/clang/AST/DeclBase.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class alignas(8) Decl {
313313
friend class ASTReader;
314314
friend class CXXClassMemberWrapper;
315315
friend class LinkageComputer;
316+
friend class RecordDecl;
316317
template<typename decl_type> friend class Redeclarable;
317318

318319
/// Access - Used by C++ decls for the access specifier.
@@ -1540,10 +1541,13 @@ class DeclContext {
15401541

15411542
/// Represents the way this type is passed to a function.
15421543
uint64_t ArgPassingRestrictions : 2;
1544+
1545+
/// Indicates whether this struct has had its field layout randomized.
1546+
uint64_t IsRandomized : 1;
15431547
};
15441548

15451549
/// Number of non-inherited bits in RecordDeclBitfields.
1546-
enum { NumRecordDeclBits = 14 };
1550+
enum { NumRecordDeclBits = 15 };
15471551

15481552
/// Stores the bits used by OMPDeclareReductionDecl.
15491553
/// If modified NumOMPDeclareReductionDeclBits and the accessor

clang/include/clang/AST/Randstruct.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===- Randstruct.h - Interfact for structure randomization -------*- C++ -*-=//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains the interface for Clang's structure field layout
10+
// randomization.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_CLANG_AST_RANDSTRUCT_H
15+
#define LLVM_CLANG_AST_RANDSTRUCT_H
16+
17+
namespace llvm {
18+
template <typename T> class ArrayRef;
19+
template <typename T> class SmallVectorImpl;
20+
class StringRef;
21+
} // end namespace llvm
22+
23+
namespace clang {
24+
25+
class ASTContext;
26+
class Decl;
27+
class RecordDecl;
28+
29+
namespace randstruct {
30+
31+
bool randomizeStructureLayout(const ASTContext &Context, llvm::StringRef Name,
32+
llvm::ArrayRef<Decl *> Fields,
33+
llvm::SmallVectorImpl<Decl *> &FinalOrdering);
34+
35+
} // namespace randstruct
36+
} // namespace clang
37+
38+
#endif // LLVM_CLANG_AST_RANDSTRUCT_H

clang/include/clang/Basic/Attr.td

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3957,3 +3957,18 @@ def HLSLNumThreads: InheritableAttr {
39573957
let LangOpts = [HLSL];
39583958
let Documentation = [NumThreadsDocs];
39593959
}
3960+
3961+
def RandomizeLayout : InheritableAttr {
3962+
let Spellings = [GCC<"randomize_layout">];
3963+
let Subjects = SubjectList<[Record]>;
3964+
let Documentation = [ClangRandomizeLayoutDocs];
3965+
let LangOpts = [COnly];
3966+
}
3967+
3968+
def NoRandomizeLayout : InheritableAttr {
3969+
let Spellings = [GCC<"no_randomize_layout">];
3970+
let Subjects = SubjectList<[Record]>;
3971+
let Documentation = [ClangRandomizeLayoutDocs];
3972+
let LangOpts = [COnly];
3973+
}
3974+
def : MutualExclusions<[RandomizeLayout, NoRandomizeLayout]>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6379,3 +6379,35 @@ dictate the thread id. Total number of threads executed is ``X * Y * Z``.
63796379
The full documentation is available here: https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-attributes-numthreads
63806380
}];
63816381
}
6382+
6383+
def ClangRandomizeLayoutDocs : Documentation {
6384+
let Category = DocCatDecl;
6385+
let Heading = "randomize_layout, no_randomize_layout";
6386+
let Content = [{
6387+
The attribute ``randomize_layout``, when attached to a C structure, selects it
6388+
for structure layout field randomization; a compile-time hardening technique. A
6389+
"seed" value, is specified via the ``-frandomize-layout-seed=`` command line flag.
6390+
For example:
6391+
6392+
.. code-block:: bash
6393+
6394+
SEED=`od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n'`
6395+
make ... CFLAGS="-frandomize-layout-seed=$SEED" ...
6396+
6397+
You can also supply the seed in a file with ``-frandomize-layout-seed-file=``.
6398+
For example:
6399+
6400+
.. code-block:: bash
6401+
6402+
od -A n -t x8 -N 32 /dev/urandom | tr -d ' \n' > /tmp/seed_file.txt
6403+
make ... CFLAGS="-frandomize-layout-seed-file=/tmp/seed_file.txt" ...
6404+
6405+
The randomization is deterministic based for a given seed, so the entire
6406+
program should be compiled with the same seed, but keep the seed safe
6407+
otherwise.
6408+
6409+
The attribute ``no_randomize_layout``, when attached to a C structure,
6410+
instructs the compiler that this structure should not have its field layout
6411+
randomized.
6412+
}];
6413+
}

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ def err_drv_amdgpu_ieee_without_no_honor_nans : Error<
165165
"invalid argument '-mno-amdgpu-ieee' only allowed with relaxed NaN handling">;
166166
def err_drv_argument_not_allowed_with : Error<
167167
"invalid argument '%0' not allowed with '%1'">;
168+
def err_drv_cannot_open_randomize_layout_seed_file : Error<
169+
"cannot read randomize layout seed file '%0'">;
168170
def err_drv_invalid_version_number : Error<
169171
"invalid version number in '%0'">;
170172
def err_drv_no_linker_llvm_support : Error<

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11588,5 +11588,7 @@ def err_hlsl_numthreads_argument_oor : Error<"argument '%select{X|Y|Z}0' to numt
1158811588
def err_hlsl_numthreads_invalid : Error<"total number of threads cannot exceed %0">;
1158911589
def err_hlsl_attribute_param_mismatch : Error<"%0 attribute parameters do not match the previous declaration">;
1159011590

11591+
// Layout randomization warning.
11592+
def err_cast_from_randomized_struct : Error<
11593+
"casting from randomized structure pointer type %0 to %1">;
1159111594
} // end of sema component.
11592-

clang/include/clang/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,9 @@ class LangOptions : public LangOptionsBase {
445445
/// The default stream kind used for HIP kernel launching.
446446
GPUDefaultStreamKind GPUDefaultStream;
447447

448+
/// The seed used by the randomize structure layout feature.
449+
std::string RandstructSeed;
450+
448451
LangOptions();
449452

450453
// Define accessors/mutators for language options of enumeration type.

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2122,6 +2122,12 @@ defm merge_all_constants : BoolFOption<"merge-all-constants",
21222122
def fmessage_length_EQ : Joined<["-"], "fmessage-length=">, Group<f_Group>, Flags<[CC1Option]>,
21232123
HelpText<"Format message diagnostics so that they fit within N columns">,
21242124
MarshallingInfoInt<DiagnosticOpts<"MessageLength">>;
2125+
def frandomize_layout_seed_EQ : Joined<["-"], "frandomize-layout-seed=">,
2126+
MetaVarName<"<seed>">, Group<f_clang_Group>, Flags<[CC1Option]>,
2127+
HelpText<"The seed used by the randomize structure layout feature">;
2128+
def frandomize_layout_seed_file_EQ : Joined<["-"], "frandomize-layout-seed-file=">,
2129+
MetaVarName<"<file>">, Group<f_clang_Group>, Flags<[CC1Option]>,
2130+
HelpText<"File holding the seed used by the randomize structure layout feature">;
21252131
def fms_compatibility : Flag<["-"], "fms-compatibility">, Group<f_Group>, Flags<[CC1Option, CoreOption]>,
21262132
HelpText<"Enable full Microsoft Visual C++ compatibility">,
21272133
MarshallingInfoFlag<LangOpts<"MSVCCompat">>;

0 commit comments

Comments
 (0)