From b3748f71df37d2ec7031a99fbe4f0323a264a013 Mon Sep 17 00:00:00 2001 From: Nicholas Wilson Date: Mon, 5 Mar 2018 13:32:38 +0000 Subject: [PATCH] [WebAssembly] Add validation to reloc section We now check relocations offsets are within range, and the relocation index is valid. Also updated tests which contained invalid Wasm files that were previously not checked. Differential Revision: https://reviews.llvm.org/D43684 llvm-svn: 326697 --- llvm/include/llvm/Object/Wasm.h | 4 +- llvm/lib/Object/WasmObjectFile.cpp | 44 +++++++++++++++++++-- llvm/test/ObjectYAML/wasm/code_section.yaml | 13 ++++++ llvm/test/ObjectYAML/wasm/data_section.yaml | 12 +++++- 4 files changed, 67 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h index 3561a64ed6ce1..da462e4d5d8f2 100644 --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -203,7 +203,9 @@ class WasmObjectFile : public ObjectFile { bool isDefinedFunctionIndex(uint32_t Index) const; bool isValidGlobalIndex(uint32_t Index) const; bool isDefinedGlobalIndex(uint32_t Index) const; - bool isValidFunctionSymbolIndex(uint32_t Index) const; + bool isValidFunctionSymbol(uint32_t Index) const; + bool isValidGlobalSymbol(uint32_t Index) const; + bool isValidDataSymbol(uint32_t Index) const; wasm::WasmFunction &getDefinedFunction(uint32_t Index); wasm::WasmGlobal &getDefinedGlobal(uint32_t Index); diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 23f25ea9aed19..044bd76e5f689 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -339,7 +339,7 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, wasm::WasmInitFunc Init; Init.Priority = readVaruint32(Ptr); Init.Symbol = readVaruint32(Ptr); - if (!isValidFunctionSymbolIndex(Init.Symbol)) + if (!isValidFunctionSymbol(Init.Symbol)) return make_error("Invalid function symbol: " + Twine(Init.Symbol), object_error::parse_failed); @@ -554,9 +554,10 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr, return make_error("Invalid section code", object_error::parse_failed); uint32_t RelocCount = readVaruint32(Ptr); + uint32_t LastOffset = 0; + uint32_t EndOffset = Section->Content.size(); while (RelocCount--) { - wasm::WasmRelocation Reloc; - memset(&Reloc, 0, sizeof(Reloc)); + wasm::WasmRelocation Reloc = {}; Reloc.Type = readVaruint32(Ptr); Reloc.Offset = readVaruint32(Ptr); Reloc.Index = readVaruint32(Ptr); @@ -564,12 +565,26 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr, case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: + if (!isValidFunctionSymbol(Reloc.Index)) + return make_error("Bad relocation function index", + object_error::parse_failed); + break; case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: + if (Reloc.Index >= Signatures.size()) + return make_error("Bad relocation type index", + object_error::parse_failed); + break; case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + if (!isValidGlobalSymbol(Reloc.Index)) + return make_error("Bad relocation global index", + object_error::parse_failed); break; case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + if (!isValidDataSymbol(Reloc.Index)) + return make_error("Bad relocation data index", + object_error::parse_failed); Reloc.Addend = readVarint32(Ptr); break; default: @@ -577,6 +592,19 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr, Twine(Reloc.Type), object_error::parse_failed); } + + // Relocations must fit inside the section, and must appear in order. They + // also shouldn't overlap a function/element boundary, but we don't bother + // to check that. + uint64_t Size = 5; + if (Reloc.Type == wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 || + Reloc.Type == wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32) + Size = 4; + if (Reloc.Offset < LastOffset || Reloc.Offset + Size > EndOffset) + return make_error("Bad relocation offset", + object_error::parse_failed); + LastOffset = Reloc.Offset; + Section->Relocations.push_back(Reloc); } if (Ptr != End) @@ -787,10 +815,18 @@ bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const { return Index >= NumImportedGlobals && isValidGlobalIndex(Index); } -bool WasmObjectFile::isValidFunctionSymbolIndex(uint32_t Index) const { +bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const { return Index < Symbols.size() && Symbols[Index].isTypeFunction(); } +bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const { + return Index < Symbols.size() && Symbols[Index].isTypeGlobal(); +} + +bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const { + return Index < Symbols.size() && Symbols[Index].isTypeData(); +} + wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) { assert(isDefinedFunctionIndex(Index)); return Functions[Index - NumImportedFunctions]; diff --git a/llvm/test/ObjectYAML/wasm/code_section.yaml b/llvm/test/ObjectYAML/wasm/code_section.yaml index 4f7da6725ec3b..62f60d65424ad 100644 --- a/llvm/test/ObjectYAML/wasm/code_section.yaml +++ b/llvm/test/ObjectYAML/wasm/code_section.yaml @@ -37,6 +37,19 @@ Sections: - Type: I32 Count: 1 Body: 108180808000210020000F0B + - Type: CUSTOM + Name: linking + SymbolTable: + - Index: 0 + Kind: FUNCTION + Name: func1 + Flags: [ ] + Function: 0 + - Index: 1 + Kind: FUNCTION + Name: func2 + Flags: [ ] + Function: 1 ... # CHECK: --- !WASM # CHECK: FileHeader: diff --git a/llvm/test/ObjectYAML/wasm/data_section.yaml b/llvm/test/ObjectYAML/wasm/data_section.yaml index d2595ddedb2ad..5c9b688f9c107 100644 --- a/llvm/test/ObjectYAML/wasm/data_section.yaml +++ b/llvm/test/ObjectYAML/wasm/data_section.yaml @@ -22,6 +22,16 @@ Sections: Index: 0 Offset: 0x00000006 Addend: -6 + - Type: CUSTOM + Name: linking + SymbolTable: + - Index: 0 + Kind: DATA + Name: dataSymbol + Flags: [ ] + Segment: 0 + Offset: 0 + Size: 4 ... # CHECK: --- !WASM # CHECK: FileHeader: @@ -44,4 +54,4 @@ Sections: # CHECK-NEXT: Opcode: I32_CONST # CHECK-NEXT: Value: 4 # CHECK-NEXT: Content: '10001000' -# CHECK-NEXT: ... +# CHECK-NEXT: - Type: CUSTOM