CVE-2020-10739 (published 2020-06-02T13:15Z)

Istio 1.4.x before 1.4.9 and Istio 1.5.x before 1.5.4 contain the following vulnerability when telemetry v2 is enabled: by sending a specially crafted packet, an attacker could trigger a Null Pointer Exception resulting in a Denial of Service. This could be sent to the ingress gateway or a sidecar, triggering a null pointer exception which results in a denial of service. This also affects servicemesh-proxy where a null pointer exception flaw was found in servicemesh-proxy. When running Telemetry v2 (not on by default in version 1.4.x), an attacker could send a specially crafted packet to the ingress gateway or proxy sidecar, triggering a denial of service.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-476
cwe_name: NULL Pointer Dereference
description: The product dereferences a pointer that it expects to be valid but is NULL.
extended_description: 
            
            
            
         
         

Fix information:
repo_url: https://github.com/istio/envoy
commit_details: repo_url: https://github.com/istio/envoy
author: John Plevyak
author_date: 2020-05-08 19:05:05-07:00
msg: 1.4 - Do not call into the VM unless the VM Context has been created. (#24)

* Ensure that the in VM Context is created before onDone is called.

Signed-off-by: John Plevyak <jplevyak@gmail.com>

* Update as per offline discussion.

Signed-off-by: John Plevyak <jplevyak@gmail.com>

* Set in_vm_context_created_ in onNetworkNewConnection.

Signed-off-by: John Plevyak <jplevyak@gmail.com>

* Add guards to other network calls.

Signed-off-by: John Plevyak <jplevyak@gmail.com>

* Fix common/wasm tests.

Signed-off-by: John Plevyak <jplevyak@gmail.com>

* Patch tests.

Signed-off-by: John Plevyak <jplevyak@gmail.com>

* Remove unecessary file from cherry-pick.

Signed-off-by: John Plevyak <jplevyak@gmail.com>
repository: repo_url: https://github.com/istio/envoy
repo_name: istio/envoy
description: Fork of Envoy used for testing and tinkering as part of the Istio dev process
repo_language: C++
owner: istio
file_changes: filename: wasm.cc
change_type: ModificationType.MODIFY
diff: @@ -1699,6 +1699,7 @@ void Context::onStart(absl::string_view root_id, absl::string_view vm_configurat
     auto config_addr = wasm_->copyString(vm_configuration);
     wasm_->onStart_(this, id_, root_id_addr, root_id.size(), config_addr, vm_configuration.size());
   }
+  in_vm_context_created_ = true;
 }
 
 bool Context::validateConfiguration(absl::string_view configuration) {
@@ -1725,6 +1726,7 @@ void Context::onCreate(uint32_t root_context_id) {
 
 Network::FilterStatus Context::onNetworkNewConnection() {
   onCreate(root_context_id_);
+  in_vm_context_created_ = true;
   if (!wasm_->onNewConnection_) {
     return Network::FilterStatus::Continue;
   }
@@ -1735,7 +1737,7 @@ Network::FilterStatus Context::onNetworkNewConnection() {
 }
 
 Network::FilterStatus Context::onDownstreamData(int data_length, bool end_of_stream) {
-  if (!wasm_->onDownstreamData_) {
+  if (!in_vm_context_created_ || !wasm_->onDownstreamData_) {
     return Network::FilterStatus::Continue;
   }
   auto result = wasm_->onDownstreamData_(this, id_, static_cast<uint32_t>(data_length),
@@ -1745,7 +1747,7 @@ Network::FilterStatus Context::onDownstreamData(int data_length, bool end_of_str
 }
 
 Network::FilterStatus Context::onUpstreamData(int data_length, bool end_of_stream) {
-  if (!wasm_->onUpstreamData_) {
+  if (!in_vm_context_created_ || !wasm_->onUpstreamData_) {
     return Network::FilterStatus::Continue;
   }
   auto result = wasm_->onUpstreamData_(this, id_, static_cast<uint32_t>(data_length),
@@ -1755,13 +1757,13 @@ Network::FilterStatus Context::onUpstreamData(int data_length, bool end_of_strea
 }
 
 void Context::onDownstreamConnectionClose(PeerType peer_type) {
-  if (wasm_->onDownstreamConnectionClose_) {
+  if (in_vm_context_created_ && wasm_->onDownstreamConnectionClose_) {
     wasm_->onDownstreamConnectionClose_(this, id_, static_cast<uint32_t>(peer_type));
   }
 }
 
 void Context::onUpstreamConnectionClose(PeerType peer_type) {
-  if (wasm_->onUpstreamConnectionClose_) {
+  if (in_vm_context_created_ && wasm_->onUpstreamConnectionClose_) {
     wasm_->onUpstreamConnectionClose_(this, id_, static_cast<uint32_t>(peer_type));
   }
 }
@@ -1785,7 +1787,7 @@ Http::FilterHeadersStatus Context::onRequestHeaders() {
 }
 
 Http::FilterDataStatus Context::onRequestBody(int body_buffer_length, bool end_of_stream) {
-  if (!wasm_->onRequestBody_) {
+  if (!in_vm_context_created_ || !wasm_->onRequestBody_) {
     return Http::FilterDataStatus::Continue;
   }
   switch (wasm_
@@ -1804,7 +1806,7 @@ Http::FilterDataStatus Context::onRequestBody(int body_buffer_length, bool end_o
 }
 
 Http::FilterTrailersStatus Context::onRequestTrailers() {
-  if (!wasm_->onRequestTrailers_) {
+  if (!in_vm_context_created_ || !wasm_->onRequestTrailers_) {
     return Http::FilterTrailersStatus::Continue;
   }
   if (wasm_->onRequestTrailers_(this, id_).u64_ == 0) {
@@ -1814,7 +1816,7 @@ Http::FilterTrailersStatus Context::onRequestTrailers() {
 }
 
 Http::FilterMetadataStatus Context::onRequestMetadata() {
-  if (!wasm_->onRequestMetadata_) {
+  if (!in_vm_context_created_ || !wasm_->onRequestMetadata_) {
     return Http::FilterMetadataStatus::Continue;
   }
   if (wasm_->onRequestMetadata_(this, id_).u64_ == 0) {
@@ -1842,7 +1844,7 @@ Http::FilterHeadersStatus Context::onResponseHeaders() {
 }
 
 Http::FilterDataStatus Context::onResponseBody(int body_buffer_length, bool end_of_stream) {
-  if (!wasm_->onResponseBody_) {
+  if (!in_vm_context_created_ || !wasm_->onResponseBody_) {
     return Http::FilterDataStatus::Continue;
   }
   switch (wasm_
@@ -1861,7 +1863,7 @@ Http::FilterDataStatus Context::onResponseBody(int body_buffer_length, bool end_
 }
 
 Http::FilterTrailersStatus Context::onResponseTrailers() {
-  if (!wasm_->onResponseTrailers_) {
+  if (!in_vm_context_created_ || !wasm_->onResponseTrailers_) {
     return Http::FilterTrailersStatus::Continue;
   }
   if (wasm_->onResponseTrailers_(this, id_).u64_ == 0) {
@@ -1871,7 +1873,7 @@ Http::FilterTrailersStatus Context::onResponseTrailers() {
 }
 
 Http::FilterMetadataStatus Context::onResponseMetadata() {
-  if (!wasm_->onResponseMetadata_) {
+  if (!in_vm_context_created_ || !wasm_->onResponseMetadata_) {
     return Http::FilterMetadataStatus::Continue;
   }
   if (wasm_->onResponseMetadata_(this, id_).u64_ == 0) {
@@ -2445,19 +2447,19 @@ void Context::onDestroy() {
 }
 
 void Context::onDone() {
-  if (wasm_->onDone_) {
+  if (in_vm_context_created_ && wasm_->onDone_) {
     wasm_->onDone_(this, id_);
   }
 }
 
 void Context::onLog() {
-  if (wasm_->onLog_) {
+  if (in_vm_context_created_ && wasm_->onLog_) {
     wasm_->onLog_(this, id_);
   }
 }
 
 void Context::onDelete() {
-  if (wasm_->onDelete_) {
+  if (in_vm_context_created_ && wasm_->onDelete_) {
     wasm_->onDelete_(this, id_);
   }
 }

programming_language: C++
filename: wasm.h
change_type: ModificationType.MODIFY
diff: @@ -413,6 +413,8 @@ public:
   // Connection
   virtual bool isSsl();
 
+  void setInVmContextCreatedForTesting() { in_vm_context_created_ = true; }
+
 protected:
   friend class Wasm;
   friend struct AsyncClientHandler;

programming_language: C++
filename: wasm_test.cc
change_type: ModificationType.MODIFY
diff: @@ -184,7 +184,7 @@ TEST_P(WasmTest, DivByZero) {
   auto context = std::make_unique<TestContext>(wasm.get());
   EXPECT_CALL(*context, scriptLog_(spdlog::level::err, Eq("before div by zero")));
   EXPECT_TRUE(wasm->initialize(code, false));
-  wasm->setContext(context.get());
+  context->setInVmContextCreatedForTesting();
 
   if (GetParam() == "v8") {
     EXPECT_THROW_WITH_MESSAGE(
@@ -388,6 +388,7 @@ TEST_P(WasmTest, StatsHighLevel) {
       "{{ test_rundir }}/test/extensions/wasm/test_data/stats_cpp.wasm"));
   EXPECT_FALSE(code.empty());
   auto context = std::make_unique<TestContext>(wasm.get());
+  context->setInVmContextCreatedForTesting();
 
   EXPECT_CALL(*context, scriptLog_(spdlog::level::trace, Eq("get counter = 1")));
   EXPECT_CALL(*context, scriptLog_(spdlog::level::debug, Eq("get counter = 2")));

programming_language: C++