Skip to content

Commit 84955ae

Browse files
rcvalleveselypeta
authored andcommitted
Add CFI integer types normalization
This commit adds a new option (i.e., `-fsanitize-cfi-icall-normalize-integers`) for normalizing integer types as vendor extended types for cross-language LLVM CFI/KCFI support with other languages that can't represent and encode C/C++ integer types. Specifically, integer types are encoded as their defined representations (e.g., 8-bit signed integer, 16-bit signed integer, 32-bit signed integer, ...) for compatibility with languages that define explicitly-sized integer types (e.g., i8, i16, i32, ..., in Rust). ``-fsanitize-cfi-icall-normalize-integers`` is compatible with ``-fsanitize-cfi-icall-generalize-pointers``. This helps with providing cross-language CFI support with the Rust compiler and is an alternative solution for the issue described and alternatives proposed in the RFC rust-lang/rfcs#3296. For more information about LLVM CFI/KCFI and cross-language LLVM CFI/KCFI support for the Rust compiler, see the design document in the tracking issue rust-lang/rust#89653. Relands b1e9ab7 with fixes. Reviewed By: pcc, samitolvanen Differential Revision: https://reviews.llvm.org/D139395
2 parents 556a958 + 71c7313 commit 84955ae

File tree

13 files changed

+300
-16
lines changed

13 files changed

+300
-16
lines changed

clang/docs/ControlFlowIntegrity.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,25 @@ long as the qualifiers for the type they point to match. For example, ``char*``,
236236
``-fsanitize-cfi-icall-generalize-pointers`` is not compatible with
237237
``-fsanitize-cfi-cross-dso``.
238238

239+
.. _cfi-icall-experimental-normalize-integers:
240+
241+
``-fsanitize-cfi-icall-experimental-normalize-integers``
242+
--------------------------------------------------------
243+
244+
This option enables normalizing integer types as vendor extended types for
245+
cross-language LLVM CFI/KCFI support with other languages that can't represent
246+
and encode C/C++ integer types.
247+
248+
Specifically, integer types are encoded as their defined representations (e.g.,
249+
8-bit signed integer, 16-bit signed integer, 32-bit signed integer, ...) for
250+
compatibility with languages that define explicitly-sized integer types (e.g.,
251+
i8, i16, i32, ..., in Rust).
252+
253+
``-fsanitize-cfi-icall-experimental-normalize-integers`` is compatible with
254+
``-fsanitize-cfi-icall-generalize-pointers``.
255+
256+
This option is currently experimental.
257+
239258
.. _cfi-canonical-jump-tables:
240259

241260
``-fsanitize-cfi-canonical-jump-tables``

clang/docs/UsersManual.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,6 +1992,14 @@ are listed below.
19921992
checked by Control Flow Integrity indirect call checking. See
19931993
:doc:`ControlFlowIntegrity` for more details.
19941994

1995+
.. option:: -fsanitize-cfi-icall-experimental-normalize-integers
1996+
1997+
Normalize integers in return and argument types in function type signatures
1998+
checked by Control Flow Integrity indirect call checking. See
1999+
:doc:`ControlFlowIntegrity` for more details.
2000+
2001+
This option is currently experimental.
2002+
19952003
.. option:: -fstrict-vtable-pointers
19962004

19972005
Enable optimizations based on the strict rules for overwriting polymorphic

clang/include/clang/AST/Mangle.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ class MangleContext {
140140
unsigned ManglingNumber,
141141
raw_ostream &) = 0;
142142
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
143-
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
143+
virtual void mangleCXXRTTIName(QualType T, raw_ostream &,
144+
bool NormalizeIntegers = false) = 0;
144145
virtual void mangleStringLiteral(const StringLiteral *SL, raw_ostream &) = 0;
145146
virtual void mangleMSGuidDecl(const MSGuidDecl *GD, raw_ostream&);
146147

@@ -177,7 +178,8 @@ class MangleContext {
177178
/// or type uniquing.
178179
/// TODO: Extend this to internal types by generating names that are unique
179180
/// across translation units so it can be used with LTO.
180-
virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
181+
virtual void mangleTypeName(QualType T, raw_ostream &,
182+
bool NormalizeIntegers = false) = 0;
181183

182184
/// @}
183185
};

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime f
257257
///< diagnostics.
258258
CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in
259259
///< CFI icall function signatures
260+
CODEGENOPT(SanitizeCfiICallNormalizeIntegers, 1, 0) ///< Normalize integer types in
261+
///< CFI icall function signatures
260262
CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical
261263
///< instead of creating a local jump table.
262264
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage

clang/include/clang/Driver/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1975,6 +1975,10 @@ def fsanitize_cfi_icall_generalize_pointers : Flag<["-"], "fsanitize-cfi-icall-g
19751975
Group<f_clang_Group>,
19761976
HelpText<"Generalize pointers in CFI indirect call type signature checks">,
19771977
MarshallingInfoFlag<CodeGenOpts<"SanitizeCfiICallGeneralizePointers">>;
1978+
def fsanitize_cfi_icall_normalize_integers : Flag<["-"], "fsanitize-cfi-icall-experimental-normalize-integers">,
1979+
Group<f_clang_Group>,
1980+
HelpText<"Normalize integers in CFI indirect call type signature checks">,
1981+
MarshallingInfoFlag<CodeGenOpts<"SanitizeCfiICallNormalizeIntegers">>;
19781982
defm sanitize_cfi_canonical_jump_tables : BoolOption<"f", "sanitize-cfi-canonical-jump-tables",
19791983
CodeGenOpts<"SanitizeCfiCanonicalJumpTables">, DefaultFalse,
19801984
PosFlag<SetTrue, [], "Make">, NegFlag<SetFalse, [CoreOption, NoXarchOption], "Do not make">,

clang/include/clang/Driver/SanitizerArgs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class SanitizerArgs {
3737
bool MsanParamRetval = true;
3838
bool CfiCrossDso = false;
3939
bool CfiICallGeneralizePointers = false;
40+
bool CfiICallNormalizeIntegers = false;
4041
bool CfiCanonicalJumpTables = false;
4142
int AsanFieldPadding = 0;
4243
bool SharedRuntime = false;

clang/lib/AST/ItaniumMangle.cpp

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
115115
void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
116116
const CXXRecordDecl *Type, raw_ostream &) override;
117117
void mangleCXXRTTI(QualType T, raw_ostream &) override;
118-
void mangleCXXRTTIName(QualType T, raw_ostream &) override;
119-
void mangleTypeName(QualType T, raw_ostream &) override;
118+
void mangleCXXRTTIName(QualType T, raw_ostream &,
119+
bool NormalizeIntegers) override;
120+
void mangleTypeName(QualType T, raw_ostream &,
121+
bool NormalizeIntegers) override;
120122

121123
void mangleCXXCtorComdat(const CXXConstructorDecl *D, raw_ostream &) override;
122124
void mangleCXXDtorComdat(const CXXDestructorDecl *D, raw_ostream &) override;
@@ -221,6 +223,10 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {
221223
class CXXNameMangler {
222224
ItaniumMangleContextImpl &Context;
223225
raw_ostream &Out;
226+
/// Normalize integer types for cross-language CFI support with other
227+
/// languages that can't represent and encode C/C++ integer types.
228+
bool NormalizeIntegers = false;
229+
224230
bool NullOut = false;
225231
/// In the "DisableDerivedAbiTags" mode derived ABI tags are not calculated.
226232
/// This mode is used when mangler creates another mangler recursively to
@@ -419,6 +425,10 @@ class CXXNameMangler {
419425
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
420426
AbiTagsRoot(AbiTags) {}
421427

428+
CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
429+
bool NormalizeIntegers_)
430+
: Context(C), Out(Out_), NormalizeIntegers(NormalizeIntegers_),
431+
NullOut(false), Structor(nullptr), AbiTagsRoot(AbiTags) {}
422432
CXXNameMangler(CXXNameMangler &Outer, raw_ostream &Out_)
423433
: Context(Outer.Context), Out(Out_), Structor(Outer.Structor),
424434
StructorType(Outer.StructorType), SeqID(Outer.SeqID),
@@ -2944,6 +2954,85 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
29442954
// ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
29452955
// ::= u <source-name> # vendor extended type
29462956
std::string type_name;
2957+
// Normalize integer types as vendor extended types:
2958+
// u<length>i<type size>
2959+
// u<length>u<type size>
2960+
if (NormalizeIntegers && T->isInteger()) {
2961+
if (T->isSignedInteger()) {
2962+
switch (getASTContext().getTypeSize(T)) {
2963+
case 8:
2964+
// Pick a representative for each integer size in the substitution
2965+
// dictionary. (Its actual defined size is not relevant.)
2966+
if (mangleSubstitution(BuiltinType::SChar))
2967+
break;
2968+
Out << "u2i8";
2969+
addSubstitution(BuiltinType::SChar);
2970+
break;
2971+
case 16:
2972+
if (mangleSubstitution(BuiltinType::Short))
2973+
break;
2974+
Out << "u3i16";
2975+
addSubstitution(BuiltinType::Short);
2976+
break;
2977+
case 32:
2978+
if (mangleSubstitution(BuiltinType::Int))
2979+
break;
2980+
Out << "u3i32";
2981+
addSubstitution(BuiltinType::Int);
2982+
break;
2983+
case 64:
2984+
if (mangleSubstitution(BuiltinType::Long))
2985+
break;
2986+
Out << "u3i64";
2987+
addSubstitution(BuiltinType::Long);
2988+
break;
2989+
case 128:
2990+
if (mangleSubstitution(BuiltinType::Int128))
2991+
break;
2992+
Out << "u4i128";
2993+
addSubstitution(BuiltinType::Int128);
2994+
break;
2995+
default:
2996+
llvm_unreachable("Unknown integer size for normalization");
2997+
}
2998+
} else {
2999+
switch (getASTContext().getTypeSize(T)) {
3000+
case 8:
3001+
if (mangleSubstitution(BuiltinType::UChar))
3002+
break;
3003+
Out << "u2u8";
3004+
addSubstitution(BuiltinType::UChar);
3005+
break;
3006+
case 16:
3007+
if (mangleSubstitution(BuiltinType::UShort))
3008+
break;
3009+
Out << "u3u16";
3010+
addSubstitution(BuiltinType::UShort);
3011+
break;
3012+
case 32:
3013+
if (mangleSubstitution(BuiltinType::UInt))
3014+
break;
3015+
Out << "u3u32";
3016+
addSubstitution(BuiltinType::UInt);
3017+
break;
3018+
case 64:
3019+
if (mangleSubstitution(BuiltinType::ULong))
3020+
break;
3021+
Out << "u3u64";
3022+
addSubstitution(BuiltinType::ULong);
3023+
break;
3024+
case 128:
3025+
if (mangleSubstitution(BuiltinType::UInt128))
3026+
break;
3027+
Out << "u4u128";
3028+
addSubstitution(BuiltinType::UInt128);
3029+
break;
3030+
default:
3031+
llvm_unreachable("Unknown integer size for normalization");
3032+
}
3033+
}
3034+
return;
3035+
}
29473036
switch (T->getKind()) {
29483037
case BuiltinType::Void:
29493038
Out << 'v';
@@ -6552,16 +6641,17 @@ void ItaniumMangleContextImpl::mangleCXXRTTI(QualType Ty, raw_ostream &Out) {
65526641
Mangler.mangleType(Ty);
65536642
}
65546643

6555-
void ItaniumMangleContextImpl::mangleCXXRTTIName(QualType Ty,
6556-
raw_ostream &Out) {
6644+
void ItaniumMangleContextImpl::mangleCXXRTTIName(
6645+
QualType Ty, raw_ostream &Out, bool NormalizeIntegers = false) {
65576646
// <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
6558-
CXXNameMangler Mangler(*this, Out);
6647+
CXXNameMangler Mangler(*this, Out, NormalizeIntegers);
65596648
Mangler.getStream() << "_ZTS";
65606649
Mangler.mangleType(Ty);
65616650
}
65626651

6563-
void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) {
6564-
mangleCXXRTTIName(Ty, Out);
6652+
void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out,
6653+
bool NormalizeIntegers = false) {
6654+
mangleCXXRTTIName(Ty, Out, NormalizeIntegers);
65656655
}
65666656

65676657
void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_ostream &) {

clang/lib/AST/MicrosoftMangle.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
180180
int32_t VBPtrOffset, uint32_t VBIndex,
181181
raw_ostream &Out) override;
182182
void mangleCXXRTTI(QualType T, raw_ostream &Out) override;
183-
void mangleCXXRTTIName(QualType T, raw_ostream &Out) override;
183+
void mangleCXXRTTIName(QualType T, raw_ostream &Out,
184+
bool NormalizeIntegers) override;
184185
void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived,
185186
uint32_t NVOffset, int32_t VBPtrOffset,
186187
uint32_t VBTableOffset, uint32_t Flags,
@@ -193,7 +194,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
193194
mangleCXXRTTICompleteObjectLocator(const CXXRecordDecl *Derived,
194195
ArrayRef<const CXXRecordDecl *> BasePath,
195196
raw_ostream &Out) override;
196-
void mangleTypeName(QualType T, raw_ostream &) override;
197+
void mangleTypeName(QualType T, raw_ostream &,
198+
bool NormalizeIntegers) override;
197199
void mangleReferenceTemporary(const VarDecl *, unsigned ManglingNumber,
198200
raw_ostream &) override;
199201
void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out) override;
@@ -3597,8 +3599,8 @@ void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &Out) {
35973599
Mangler.getStream() << "@8";
35983600
}
35993601

3600-
void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T,
3601-
raw_ostream &Out) {
3602+
void MicrosoftMangleContextImpl::mangleCXXRTTIName(
3603+
QualType T, raw_ostream &Out, bool NormalizeIntegers = false) {
36023604
MicrosoftCXXNameMangler Mangler(*this, Out);
36033605
Mangler.getStream() << '.';
36043606
Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result);
@@ -3765,7 +3767,8 @@ void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(
37653767
Mangler.mangleName(EnclosingDecl);
37663768
}
37673769

3768-
void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
3770+
void MicrosoftMangleContextImpl::mangleTypeName(
3771+
QualType T, raw_ostream &Out, bool NormalizeIntegers = false) {
37693772
// This is just a made up unique string for the purposes of tbaa. undname
37703773
// does *not* know how to demangle it.
37713774
MicrosoftCXXNameMangler Mangler(*this, Out);

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,7 +1820,11 @@ llvm::ConstantInt *CodeGenModule::CreateKCFITypeId(QualType T) {
18201820

18211821
std::string OutName;
18221822
llvm::raw_string_ostream Out(OutName);
1823-
getCXXABI().getMangleContext().mangleTypeName(T, Out);
1823+
getCXXABI().getMangleContext().mangleTypeName(
1824+
T, Out, getCodeGenOpts().SanitizeCfiICallNormalizeIntegers);
1825+
1826+
if (getCodeGenOpts().SanitizeCfiICallNormalizeIntegers)
1827+
Out << ".normalized";
18241828

18251829
return llvm::ConstantInt::get(Int32Ty,
18261830
static_cast<uint32_t>(llvm::xxHash64(OutName)));
@@ -7057,7 +7061,12 @@ CodeGenModule::CreateMetadataIdentifierImpl(QualType T, MetadataTypeMap &Map,
70577061
if (isExternallyVisible(T->getLinkage())) {
70587062
std::string OutName;
70597063
llvm::raw_string_ostream Out(OutName);
7060-
getCXXABI().getMangleContext().mangleTypeName(T, Out);
7064+
getCXXABI().getMangleContext().mangleTypeName(
7065+
T, Out, getCodeGenOpts().SanitizeCfiICallNormalizeIntegers);
7066+
7067+
if (getCodeGenOpts().SanitizeCfiICallNormalizeIntegers)
7068+
Out << ".normalized";
7069+
70617070
Out << Suffix;
70627071

70637072
InternalId = llvm::MDString::get(getLLVMContext(), Out.str());

clang/lib/Driver/SanitizerArgs.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC,
714714
CfiICallGeneralizePointers =
715715
Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers);
716716

717+
CfiICallNormalizeIntegers =
718+
Args.hasArg(options::OPT_fsanitize_cfi_icall_normalize_integers);
719+
717720
if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors)
718721
D.Diag(diag::err_drv_argument_not_allowed_with)
719722
<< "-fsanitize-cfi-cross-dso"
@@ -1218,6 +1221,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
12181221
if (CfiICallGeneralizePointers)
12191222
CmdArgs.push_back("-fsanitize-cfi-icall-generalize-pointers");
12201223

1224+
if (CfiICallNormalizeIntegers)
1225+
CmdArgs.push_back("-fsanitize-cfi-icall-experimental-normalize-integers");
1226+
12211227
if (CfiCanonicalJumpTables)
12221228
CmdArgs.push_back("-fsanitize-cfi-canonical-jump-tables");
12231229

0 commit comments

Comments
 (0)