Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit e5c16c8

Browse files
committed
Harden writer of munged bitcode for fuzzing
Hardens the writer of munged bitcode. Does this by adding error recovery that guarantees the bitstream writer will not fail on assertions. Also cleans up error recovery in general and adds tests to show what errors are reported by the writer, as well as what error recovery is applied. BUG= https://code.google.com/p/nativeclient/issues/detail?id=4169 [email protected] Review URL: https://codereview.chromium.org/1139673004
1 parent d0089f0 commit e5c16c8

File tree

9 files changed

+741
-250
lines changed

9 files changed

+741
-250
lines changed

include/llvm/Bitcode/NaCl/NaClBitcodeMunge.h

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ class NaClBitcodeMunger {
7373
}
7474

7575
/// Creates MungedInput and DumpStream for running tests, based on
76-
/// given Munges.
77-
void setupTest(
76+
/// given Munges. Returns true if able to set up test.
77+
bool setupTest(
7878
const char *TestName, const uint64_t Munges[], size_t MungesSize,
7979
bool AddHeader);
8080

81-
/// Cleans up state after a test.
82-
void cleanupTest();
81+
/// Cleans up state after a test. Returns true if no errors found.
82+
bool cleanupTest();
8383

8484
/// Returns the resulting string generated by the corresponding test.
8585
const std::string &getTestResults() const {
@@ -110,6 +110,16 @@ class NaClBitcodeMunger {
110110
WriteFlags.setWriteBadAbbrevIndex(NewValue);
111111
}
112112

113+
/// Get access to munged bitcodes.
114+
NaClMungedBitcode &getMungedBitcode() {
115+
return MungedBitcode;
116+
}
117+
118+
/// Apply given munges to the munged bitcode.
119+
void munge(const uint64_t Munges[], size_t MungesSize) {
120+
MungedBitcode.munge(Munges, MungesSize, RecordTerminator);
121+
}
122+
113123
protected:
114124
// The bitcode records being munged.
115125
NaClMungedBitcode MungedBitcode;
@@ -151,6 +161,35 @@ class NaClBitcodeMunger {
151161
}
152162
};
153163

164+
/// Class to run tests writing munged bitcode.
165+
class NaClWriteMunger : public NaClBitcodeMunger {
166+
public:
167+
NaClWriteMunger(const uint64_t Records[], size_t RecordsSize,
168+
uint64_t RecordTerminator)
169+
: NaClBitcodeMunger(Records, RecordsSize, RecordTerminator) {}
170+
171+
/// Writes munged bitcode and puts error messages into DumpResults.
172+
/// Returns true if successful.
173+
bool runTest(const char* TestName, const uint64_t Munges[],
174+
size_t MungesSize);
175+
176+
/// Same as above, but without test name.
177+
bool runTest(const uint64_t Munges[], size_t MungesSize) {
178+
return runTest("Test", Munges, MungesSize);
179+
}
180+
181+
/// Same as above, but without any edits.
182+
bool runTest(const char* TestName) {
183+
uint64_t NoMunges[] = {0};
184+
return runTest(TestName, NoMunges, 0);
185+
}
186+
187+
/// Same as above, but without test name.
188+
bool runTest() {
189+
return runTest("Test");
190+
}
191+
};
192+
154193
/// Class to run tests for function llvm::NaClObjDump.
155194
class NaClObjDumpMunger : public NaClBitcodeMunger {
156195
public:
@@ -182,12 +221,17 @@ class NaClObjDumpMunger : public NaClBitcodeMunger {
182221
return runTestWithFlags(TestName, true, false, false);
183222
}
184223

185-
/// Same as runTest, but only print out assembly and errors.
224+
/// Same as above but without test name.
225+
bool runTest() {
226+
return runTest("Test");
227+
}
228+
229+
/// Same as above, but only print out assembly and errors.
186230
bool runTestForAssembly(const char *TestName) {
187231
return runTestWithFlags(TestName, true, true, false);
188232
}
189233

190-
/// Same as runTest, but only generate error messages.
234+
/// Same as above, but only generate error messages.
191235
bool runTestForErrors(const char *TestName) {
192236
return runTestWithFlags(TestName, true, true, true);
193237
}
@@ -212,6 +256,10 @@ class NaClObjDumpMunger : public NaClBitcodeMunger {
212256
return runTestWithFlags(TestName, Munges, MungesSize, true, false, false);
213257
}
214258

259+
bool runTest(const uint64_t Munges[], size_t MungesSize) {
260+
return runTest("Test", Munges, MungesSize);
261+
}
262+
215263
bool runTestForAssembly(const char* TestName, const uint64_t Munges[],
216264
size_t MungesSize) {
217265
return runTestWithFlags(TestName, Munges, MungesSize, true, true, false);
@@ -235,6 +283,11 @@ class NaClParseBitcodeMunger : public NaClBitcodeMunger {
235283
bool runTest(const char* TestName, const uint64_t Munges[],
236284
size_t MungesSize, bool VerboseErrors);
237285

286+
/// Same as above, but without test name.
287+
bool runTest(const uint64_t Munges[], size_t MungesSize, bool VerboseErrors) {
288+
return runTest("Test", Munges, MungesSize, VerboseErrors);
289+
}
290+
238291
// Same as above, but without any edits.
239292
bool runTest(const char* TestName, bool VerboseErrors) {
240293
uint64_t NoMunges[] = {0};

include/llvm/Bitcode/NaCl/NaClBitstreamWriter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ class NaClBitstreamWriter {
148148
/// \brief Retrieve the current position in the stream, in bits.
149149
uint64_t GetCurrentBitNo() const { return GetBufferOffset() * 8 + CurBit; }
150150

151+
/// \brief Returns the maximum abbreviation index allowed for the
152+
/// current block.
153+
size_t getMaxCurAbbrevIndex() const {
154+
return CurAbbrevs.size() + naclbitc::DEFAULT_MAX_ABBREV;
155+
}
156+
151157
//===--------------------------------------------------------------------===//
152158
// Basic Primitives for emitting bits to the stream.
153159
//===--------------------------------------------------------------------===//

lib/Bitcode/NaCl/TestUtils/NaClBitcodeMunge.cpp

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ using namespace llvm;
2929
// For debugging. When true, shows each test being run.
3030
static bool TraceTestRuns = false;
3131

32-
void NaClBitcodeMunger::setupTest(
32+
bool NaClBitcodeMunger::setupTest(
3333
const char *TestName, const uint64_t Munges[], size_t MungesSize,
3434
bool AddHeader) {
3535
assert(DumpStream == nullptr && "Test run with DumpStream already defined");
@@ -53,8 +53,10 @@ void NaClBitcodeMunger::setupTest(
5353
&& !(WriteFlags.getTryToRecover()
5454
&& Results.NumRepairs == Results.NumErrors)
5555
&& !(WriteFlags.getWriteBadAbbrevIndex()
56-
&& Results.WroteBadAbbrevIndex && Results.NumErrors == 1))
57-
report_fatal_error("Unable to generate bitcode file due to write errors");
56+
&& Results.WroteBadAbbrevIndex && Results.NumErrors == 1)) {
57+
Error() << "Unable to generate bitcode file due to write errors\n";
58+
return false;
59+
}
5860

5961
// Add null terminator, so that we meet the requirements of the
6062
// MemoryBuffer API.
@@ -63,9 +65,10 @@ void NaClBitcodeMunger::setupTest(
6365
MungedInput = MemoryBuffer::getMemBuffer(
6466
StringRef(MungedInputBuffer.data(), MungedInputBuffer.size()-1),
6567
TestName);
68+
return true;
6669
}
6770

68-
void NaClBitcodeMunger::cleanupTest() {
71+
bool NaClBitcodeMunger::cleanupTest() {
6972
RunAsDeathTest = false;
7073
WriteFlags.reset();
7174
MungedBitcode.removeEdits();
@@ -74,6 +77,7 @@ void NaClBitcodeMunger::cleanupTest() {
7477
DumpStream->flush();
7578
delete DumpStream;
7679
DumpStream = nullptr;
80+
return !FoundErrors;
7781
}
7882

7983
// Return the next line of input (including eoln), starting from
@@ -110,24 +114,38 @@ getLinesWithTextMatch(const std::string &Substring, bool MustBePrefix) const {
110114
return Messages;
111115
}
112116

117+
bool NaClWriteMunger::runTest(const char* Name, const uint64_t Munges[],
118+
size_t MungesSize) {
119+
bool AddHeader = true;
120+
if (!setupTest(Name, Munges, MungesSize, AddHeader))
121+
return cleanupTest();
122+
MemoryBufferRef InputRef(MungedInput->getMemBufferRef());
123+
NaClMungedBitcode WrittenBitcode(MemoryBuffer::getMemBuffer(InputRef));
124+
WrittenBitcode.print(WriteFlags.getErrStream());
125+
return cleanupTest();
126+
}
127+
113128
bool NaClObjDumpMunger::runTestWithFlags(
114129
const char *Name, const uint64_t Munges[], size_t MungesSize,
115130
bool AddHeader, bool NoRecords, bool NoAssembly) {
116-
setupTest(Name, Munges, MungesSize, AddHeader);
131+
if (!setupTest(Name, Munges, MungesSize, AddHeader))
132+
return cleanupTest();
117133

118134
if (NaClObjDump(MungedInput.get()->getMemBufferRef(),
119135
getDumpStream(), NoRecords, NoAssembly))
120136
FoundErrors = true;
121-
cleanupTest();
122-
return !FoundErrors;
137+
return cleanupTest();
123138
}
124139

125140
bool NaClParseBitcodeMunger::runTest(
126141
const char *Name, const uint64_t Munges[], size_t MungesSize,
127142
bool VerboseErrors) {
128143
bool AddHeader = true;
129-
setupTest(Name, Munges, MungesSize, AddHeader);
144+
if (!setupTest(Name, Munges, MungesSize, AddHeader))
145+
return cleanupTest();
146+
130147
LLVMContext &Context = getGlobalContext();
148+
131149
raw_ostream *VerboseStrm = VerboseErrors ? &getDumpStream() : nullptr;
132150
ErrorOr<Module *> ModuleOrError =
133151
NaClParseBitcodeFile(MungedInput->getMemBufferRef(), Context,
@@ -139,16 +157,17 @@ bool NaClParseBitcodeMunger::runTest(
139157
} else {
140158
Error() << ModuleOrError.getError().message() << "\n";
141159
}
142-
cleanupTest();
143-
return !FoundErrors;
160+
return cleanupTest();
144161
}
145162

146163
bool NaClCompressMunger::runTest(const char* Name, const uint64_t Munges[],
147164
size_t MungesSize) {
148165
bool AddHeader = true;
149-
setupTest(Name, Munges, MungesSize, AddHeader);
166+
if (!setupTest(Name, Munges, MungesSize, AddHeader))
167+
return cleanupTest();
168+
150169
NaClBitcodeCompressor Compressor;
151-
bool Result = Compressor.compress(MungedInput.get(), getDumpStream());
152-
cleanupTest();
153-
return Result;
170+
if (!Compressor.compress(MungedInput.get(), getDumpStream()))
171+
Error() << "Unable to compress\n";
172+
return cleanupTest();
154173
}

lib/Bitcode/NaCl/TestUtils/NaClBitcodeMungeUtils.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ void readNaClBitcodeRecordList(NaClBitcodeRecordList &RecordList,
8787
} // end of namespace llvm
8888

8989
void NaClBitcodeAbbrevRecord::print(raw_ostream &Out) const {
90-
NaClBitcodeRecordData::Print(Out << format("%8u", Abbrev) << ": ");
90+
NaClBitcodeRecordData::Print(Out << Abbrev << ": ");
9191
}
9292

9393
void NaClBitcodeAbbrevRecord::read(const uint64_t Vals[], size_t ValsSize,
@@ -119,6 +119,13 @@ void NaClMungedBitcode::print(raw_ostream &Out) const {
119119
for (size_t i = 0; i < Indent; ++i) {
120120
Out << " ";
121121
}
122+
// Blank fill to make abbreviation indices right align, and then
123+
// print record.
124+
uint32_t Cutoff = 9999999;
125+
while (Record.Abbrev <= Cutoff && Cutoff) {
126+
Out << " ";
127+
Cutoff /= 10;
128+
}
122129
Out << Record << "\n";
123130
if (Record.Code == naclbitc::BLK_CODE_ENTER)
124131
++Indent;

0 commit comments

Comments
 (0)