From 8c253f7e88f638ac0108ca8ec34daf236737cd83 Mon Sep 17 00:00:00 2001 From: JF Bastien Date: Sun, 22 Feb 2015 19:32:03 +0000 Subject: [PATCH] Use common parse routine to read alignment values from bitcode While fuzzing LLVM bitcode files, I discovered that (1) the bitcode reader doesn't check that alignments are no larger than 2**29; (2) downstream code doesn't check the range; and (3) for values out of range, corresponding large memory requests (based on alignment size) will fail. This code fixes the bitcode reader to check for valid alignments, fixing this problem. This CL fixes alignment value on global variables, functions, and instructions: alloca, load, load atomic, store, store atomic. Patch by Karl Schimpf (kschimpf@google.com). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@230180 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/Value.h | 3 +- lib/Bitcode/Reader/BitcodeReader.cpp | 56 ++++++++++++++++++++------- lib/Bitcode/Reader/BitcodeReader.h | 4 ++ test/Bitcode/Inputs/invalid-align.bc | Bin 0 -> 428 bytes test/Bitcode/invalid.test | 3 ++ 5 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 test/Bitcode/Inputs/invalid-align.bc diff --git a/include/llvm/IR/Value.h b/include/llvm/IR/Value.h index 517dd26d300..b7213a67220 100644 --- a/include/llvm/IR/Value.h +++ b/include/llvm/IR/Value.h @@ -469,7 +469,8 @@ public: /// /// This is the greatest alignment value supported by load, store, and alloca /// instructions, and global values. - static const unsigned MaximumAlignment = 1u << 29; + static const unsigned MaxAlignmentExponent = 29; + static const unsigned MaximumAlignment = 1u << MaxAlignmentExponent; /// \brief Mutate the type of this Value to be of the specified type. /// diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index bb6ba6fc6e1..3b3a6eb43d1 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -794,6 +794,16 @@ static Attribute::AttrKind GetAttrFromCode(uint64_t Code) { } } +std::error_code BitcodeReader::parseAlignmentValue(uint64_t Exponent, + unsigned &Alignment) { + // Note: Alignment in bitcode files is incremented by 1, so that zero + // can be used for default alignment. + if (Exponent > Value::MaxAlignmentExponent + 1) + return Error("Invalid alignment value"); + Alignment = (1 << static_cast(Exponent)) >> 1; + return std::error_code(); +} + std::error_code BitcodeReader::ParseAttrKind(uint64_t Code, Attribute::AttrKind *Kind) { *Kind = GetAttrFromCode(Code); @@ -2462,7 +2472,9 @@ std::error_code BitcodeReader::ParseModule(bool Resume) { bool isConstant = Record[1]; uint64_t RawLinkage = Record[3]; GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); - unsigned Alignment = (1 << Record[4]) >> 1; + unsigned Alignment; + if (std::error_code EC = parseAlignmentValue(Record[4], Alignment)) + return EC; std::string Section; if (Record[5]) { if (Record[5]-1 >= SectionTable.size()) @@ -2542,7 +2554,10 @@ std::error_code BitcodeReader::ParseModule(bool Resume) { Func->setLinkage(getDecodedLinkage(RawLinkage)); Func->setAttributes(getAttributes(Record[4])); - Func->setAlignment((1 << Record[5]) >> 1); + unsigned Alignment; + if (std::error_code EC = parseAlignmentValue(Record[5], Alignment)) + return EC; + Func->setAlignment(Alignment); if (Record[6]) { if (Record[6]-1 >= SectionTable.size()) return Error("Invalid ID"); @@ -3539,12 +3554,17 @@ std::error_code BitcodeReader::ParseFunctionBody(Function *F) { dyn_cast_or_null(getTypeByID(Record[0])); Type *OpTy = getTypeByID(Record[1]); Value *Size = getFnValueByID(Record[2], OpTy); - unsigned AlignRecord = Record[3]; - bool InAlloca = AlignRecord & (1 << 5); - unsigned Align = AlignRecord & ((1 << 5) - 1); + uint64_t AlignRecord = Record[3]; + const uint64_t InAllocaMask = uint64_t(1) << 5; + bool InAlloca = AlignRecord & InAllocaMask; + unsigned Align; + if (std::error_code EC = + parseAlignmentValue(AlignRecord & ~InAllocaMask, Align)) { + return EC; + } if (!Ty || !Size) return Error("Invalid record"); - AllocaInst *AI = new AllocaInst(Ty->getElementType(), Size, (1 << Align) >> 1); + AllocaInst *AI = new AllocaInst(Ty->getElementType(), Size, Align); AI->setUsedWithInAlloca(InAlloca); I = AI; InstructionList.push_back(I); @@ -3556,8 +3576,10 @@ std::error_code BitcodeReader::ParseFunctionBody(Function *F) { if (getValueTypePair(Record, OpNum, NextValueNo, Op) || OpNum+2 != Record.size()) return Error("Invalid record"); - - I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1); + unsigned Align; + if (std::error_code EC = parseAlignmentValue(Record[OpNum], Align)) + return EC; + I = new LoadInst(Op, "", Record[OpNum+1], Align); InstructionList.push_back(I); break; } @@ -3577,8 +3599,10 @@ std::error_code BitcodeReader::ParseFunctionBody(Function *F) { return Error("Invalid record"); SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+3]); - I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1, - Ordering, SynchScope); + unsigned Align; + if (std::error_code EC = parseAlignmentValue(Record[OpNum], Align)) + return EC; + I = new LoadInst(Op, "", Record[OpNum+1], Align, Ordering, SynchScope); InstructionList.push_back(I); break; } @@ -3590,8 +3614,10 @@ std::error_code BitcodeReader::ParseFunctionBody(Function *F) { cast(Ptr->getType())->getElementType(), Val) || OpNum+2 != Record.size()) return Error("Invalid record"); - - I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1); + unsigned Align; + if (std::error_code EC = parseAlignmentValue(Record[OpNum], Align)) + return EC; + I = new StoreInst(Val, Ptr, Record[OpNum+1], Align); InstructionList.push_back(I); break; } @@ -3613,8 +3639,10 @@ std::error_code BitcodeReader::ParseFunctionBody(Function *F) { if (Ordering != NotAtomic && Record[OpNum] == 0) return Error("Invalid record"); - I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1, - Ordering, SynchScope); + unsigned Align; + if (std::error_code EC = parseAlignmentValue(Record[OpNum], Align)) + return EC; + I = new StoreInst(Val, Ptr, Record[OpNum+1], Align, Ordering, SynchScope); InstructionList.push_back(I); break; } diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index 5090be48450..9803e78b929 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -335,6 +335,10 @@ private: return getFnValueByID(ValNo, Ty); } + /// Converts alignment exponent (i.e. power of two (or zero)) to the + /// corresponding alignment to use. If alignment is too large, returns + /// a corresponding error code. + std::error_code parseAlignmentValue(uint64_t Exponent, unsigned &Alignment); std::error_code ParseAttrKind(uint64_t Code, Attribute::AttrKind *Kind); std::error_code ParseModule(bool Resume); std::error_code ParseAttributeBlock(); diff --git a/test/Bitcode/Inputs/invalid-align.bc b/test/Bitcode/Inputs/invalid-align.bc new file mode 100644 index 0000000000000000000000000000000000000000..e84fa6cdda5fa4329ff3c3dee0897cc3b4032a07 GIT binary patch literal 428 zcmZ>AK5$Qwhk+r3fq{X$Nr8b0NDBcmd!zD1#}h1`Yyw7>lNeigR9QJBt%tiM#YaG*m?gnMgULyXLjt77c@Bt#fD?y-dVx%1 zjs}?{4`tFs7;QV8Em{uuI5n_WRhKI!)$w|qNk*Qy_$o)(xbhgfW4}KxvZkSK%rgoj3D2e349L?`11_-AAjKc z5Wr_Fa76Z=qRb6N*+YqPX$GCvdz!5;I9qOEw%OBc)52_h=7UIC0(*4^yLm=?5s++X zFPP9?kicH1!Cv-*6=-aELwh_&d!a;o(Tw)W8I3ycKJdMJ!1wh4-y4QP1qN^!vpMMS n836s22;_4BX<-&dRu3Z%c2M{;1F@Pwh?oPzVF5%)FfafBb(?oZ literal 0 HcmV?d00001 diff --git a/test/Bitcode/invalid.test b/test/Bitcode/invalid.test index 84bc9278d91..fb818884eed 100644 --- a/test/Bitcode/invalid.test +++ b/test/Bitcode/invalid.test @@ -10,6 +10,8 @@ RUN: not llvm-dis -disable-output %p/Inputs/invalid-type-table-forward-ref.bc 2> RUN: FileCheck --check-prefix=BAD-TYPE-TABLE-FORWARD-REF %s RUN: not llvm-dis -disable-output %p/Inputs/invalid-bitwidth.bc 2>&1 | \ RUN: FileCheck --check-prefix=BAD-BITWIDTH %s +RUN: not llvm-dis -disable-output %p/Inputs/invalid-align.bc 2>&1 | \ +RUN: FileCheck --check-prefix=BAD-ALIGN %s INVALID-ENCODING: Invalid encoding BAD-ABBREV: Abbreviation starts with an Array or a Blob @@ -17,6 +19,7 @@ UNEXPECTED-EOF: Unexpected end of file BAD-ABBREV-NUMBER: Invalid abbrev number BAD-TYPE-TABLE-FORWARD-REF: Invalid TYPE table: Only named structs can be forward referenced BAD-BITWIDTH: Bitwidth for integer type out of range +BAD-ALIGN: Invalid alignment value RUN: not llvm-dis -disable-output %p/Inputs/invalid-extractval-array-idx.bc 2>&1 | \ RUN: FileCheck --check-prefix=EXTRACT-ARRAY %s