Project: wabt (webassembly/wabt), language: c++
Vulnerability instance: wabt.cve-2023-46331
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/WebAssembly/wabt/issues/2310
## Description:
Issue: WebAssembly/wabt#2310
Title: Out-of-Bound Memory Read in DataSegment::IsValidRange()
State: closed
Created by: mobsceneZ
Created at: 2023-10-08 07:32:47+00:00
Labels: sanitizer failures, interpreter

Issue Body:
### Environment

```shell
OS               : Linux 5.10.16.3-microsoft-standard-WSL2 #1 SMP Fri Apr 2 22:23:49 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
Commit           : 0e78c24fd231d5ee67ccd271bfa317faa963281c
Version          : 1.0.33 (git~1.0.33-35-gdddc03d3)
Clang Verison    : 12.0.1
Build            : mkdir build && cd build && export CC=clang CXX=clang++ CFLAGS="-fsanitize=address -g" CXXFLAGS="-fsanitize=address -g" && cmake .. && cmake --build .
Affected Tool    : wasm-interp
Enabled Features : None
Impact           : Out-of-Bound Memory Read Access
```

### Proof of Concept
[poc-wasm-interp-01.zip](https://github.com/WebAssembly/wabt/files/12840027/poc-wasm-interp-01.zip)

### Stack Trace Provide By AddressSanitizer
```shell
$  ~/wabt_asan/bin/wasm-interp poc.wasm
AddressSanitizer:DEADLYSIGNAL
=================================================================
==3549==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000008 (pc 0x00000064a0fe bp 0x7ffcceb61670 sp 0x7ffcceb61640 T0)
==3549==The signal is caused by a READ memory access.
==3549==Hint: address points to the zero page.
    #0 0x64a0fe in wabt::interp::DataSegment::IsValidRange(unsigned long, unsigned long) const /home/lain/wabt_asan/src/interp/interp.cc:734:19
    #1 0x649cd7 in wabt::interp::Memory::Init(unsigned long, wabt::interp::DataSegment const&, unsigned long, unsigned long) /home/lain/wabt_asan/src/interp/interp.cc:617:11
    #2 0x666cb4 in wabt::interp::Thread::DoMemoryInit(wabt::interp::Instr, wabt::interp::RefPtr<wabt::interp::Trap>*) /home/lain/wabt_asan/src/interp/interp.cc:2075:3
    #3 0x65b199 in wabt::interp::Thread::StepInternal(wabt::interp::RefPtr<wabt::interp::Trap>*) /home/lain/wabt_asan/src/interp/interp.cc:1510:32
    #4 0x65352b in wabt::interp::Thread::Run(int, wabt::interp::RefPtr<wabt::interp::Trap>*) /home/lain/wabt_asan/src/interp/interp.cc:1086:19
    #5 0x645a70 in wabt::interp::Thread::Run(wabt::interp::RefPtr<wabt::interp::Trap>*) /home/lain/wabt_asan/src/interp/interp.cc:1078:14
    #6 0x644caf in wabt::interp::DefinedFunc::DoCall(wabt::interp::Thread&, std::vector<wabt::interp::Value, std::allocator<wabt::interp::Value> > const&, std::vector<wabt::interp::Value, std::allocator<wabt::interp::Value> >&, wabt::interp::RefPtr<wabt::interp::Trap>*) /home/lain/wabt_asan/src/interp/interp.cc:428:19
    #7 0x64417d in wabt::interp::Func::Call(wabt::interp::Store&, std::vector<wabt::interp::Value, std::allocator<wabt::interp::Value> > const&, std::vector<wabt::interp::Value, std::allocator<wabt::interp::Value> >&, wabt::interp::RefPtr<wabt::interp::Trap>*, wabt::Stream*) /home/lain/wabt_asan/src/interp/interp.cc:394:10
    #8 0x6512e6 in wabt::interp::Instance::Instantiate(wabt::interp::Store&, wabt::interp::Ref, std::vector<wabt::interp::Ref, std::allocator<wabt::interp::Ref> > const&, wabt::interp::RefPtr<wabt::interp::Trap>*) /home/lain/wabt_asan/src/interp/interp.cc:944:22
    #9 0x5693e5 in InstantiateModule(std::vector<wabt::interp::Ref, std::allocator<wabt::interp::Ref> >&, wabt::interp::RefPtr<wabt::interp::Module> const&, wabt::interp::RefPtr<wabt::interp::Instance>*) /home/lain/wabt_asan/src/tools/wasm-interp.cc:340:19
    #10 0x562e82 in ReadAndRunModule(char const*) /home/lain/wabt_asan/src/tools/wasm-interp.cc:423:3
    #11 0x561f67 in ProgramMain(int, char**) /home/lain/wabt_asan/src/tools/wasm-interp.cc:450:25
    #12 0x563191 in main /home/lain/wabt_asan/src/tools/wasm-interp.cc:456:10
    #13 0x7f9f8fa00082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
    #14 0x4845ed in _start (/home/lain/wabt_asan/bin/wasm-interp+0x4845ed)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/lain/wabt_asan/src/interp/interp.cc:734:19 in wabt::interp::DataSegment::IsValidRange(unsigned long, unsigned long) const
==3549==ABORTING
```


Attachments:
https://github.com/WebAssembly/wabt/files/12840027/poc-wasm-interp-01.zip

Commit References:
0e78c24fd231d5ee67ccd271bfa317faa963281c

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
mkdir -p build
cd build
cmake ..
cmake --build . --parallel

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y cmake libtool make python
RUN git clone https://github.com/webassembly/wabt wabt
RUN git -C wabt checkout 963f973469b45969ce198e0c86d3af316790a780
WORKDIR $SRC/wabt
COPY build.sh $SRC/

Additional files:
filename: read_binary_interp_fuzzer.cc
content: // Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cstddef>
#include <cstdint>

#include <fuzzer/FuzzedDataProvider.h>

#include "wabt/binary-reader.h"
#include "wabt/interp/binary-reader-interp.h"
#include "wabt/interp/interp.h"
#include "wabt/ir.h"
#include "wabt/option-parser.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  wabt::Errors errors;
  wabt::Features features;
  wabt::interp::ModuleDesc module;
  FuzzedDataProvider data_provider(data, size);

#define WABT_FEATURE(variable, flag, default_, help) \
  if (data_provider.ConsumeBool()) { features.enable_##variable(); }
#include "wabt/feature.def"
#undef WABT_FEATURE
  // Add only feature related options, but no logging, stop_on_first_error, etc.
  wabt::ReadBinaryOptions options(features, nullptr, false, false, false);
  std::vector<uint8_t> text = data_provider.ConsumeRemainingBytes<uint8_t>();
  ReadBinaryInterp("<fuzzer>", text.data(), text.size(), options, &errors,
                   &module);
  return 0;
}


filename: read_binary_ir_fuzzer.cc
content: // Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cstddef>
#include <cstdint>

#include <fuzzer/FuzzedDataProvider.h>

#include "wabt/binary-reader-ir.h"
#include "wabt/binary-reader.h"
#include "wabt/ir.h"
#include "wabt/option-parser.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  wabt::Errors errors;
  wabt::Module module;
  wabt::Features features;
  FuzzedDataProvider data_provider(data, size);
#define WABT_FEATURE(variable, flag, default_, help) \
  if (data_provider.ConsumeBool()) { features.enable_##variable(); }
#include "wabt/feature.def"
#undef WABT_FEATURE
  // Add only feature related options, but no logging, stop_on_first_error, etc.
  wabt::ReadBinaryOptions options(features, nullptr, false, false, false);
  std::vector<uint8_t> text = data_provider.ConsumeRemainingBytes<uint8_t>();
  ReadBinaryIr("", text.data(), text.size(), options, &errors, &module);
  return 0;
}


filename: wasm2wat_fuzzer.cc
content: // Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "wabt/binary-reader-ir.h"
#include "wabt/binary-reader.h"
#include "wabt/common.h"
#include "wabt/ir.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  wabt::ReadBinaryOptions options;
  wabt::Errors errors;
  wabt::Module module;
  wabt::ReadBinaryIr("dummy filename", data, size, options, &errors, &module);
  return 0;
}


filename: wasm_objdump_fuzzer.cc
content: // Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "wabt/binary-reader-objdump.h"
#include "wabt/binary-reader.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  wabt::ObjdumpOptions objdump_options{};
  wabt::ObjdumpState state;

  objdump_options.debug = false;
  objdump_options.filename = "dummy";
  objdump_options.log_stream = nullptr;

  objdump_options.mode = wabt::ObjdumpMode::Prepass;
  wabt::ReadBinaryObjdump(data, size, &objdump_options, &state);

  objdump_options.mode = wabt::ObjdumpMode::Headers;
  wabt::ReadBinaryObjdump(data, size, &objdump_options, &state);

  objdump_options.mode = wabt::ObjdumpMode::Details;
  wabt::ReadBinaryObjdump(data, size, &objdump_options, &state);

  objdump_options.mode = wabt::ObjdumpMode::Disassemble;
  wabt::ReadBinaryObjdump(data, size, &objdump_options, &state);

  objdump_options.mode = wabt::ObjdumpMode::RawData;
  wabt::ReadBinaryObjdump(data, size, &objdump_options, &state);

  return 0;
}


filename: wat2wasm_fuzzer.cc
content: // Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "wabt/ir.h"
#include "wabt/wast-lexer.h"
#include "wabt/wast-parser.h"

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  wabt::Errors Lexerrors;
  std::unique_ptr<wabt::WastLexer> lexer =
      wabt::WastLexer::CreateBufferLexer("fake_file", data, size, &Lexerrors);

  if (!lexer) {
    return 0;
  }

  std::unique_ptr<wabt::Module> module;
  wabt::Errors errors;
  wabt::Features features;
  wabt::WastParseOptions parse_wast_options(features);
  ParseWatModule(lexer.get(), &module, &errors, &parse_wast_options);

  return 0;
}