"WAVM: Incorrect bounds check " 漏洞分析

WAVM: Incorrect bounds check when translating a reference type can results in buffer overrun

出問題的代碼如下:
libraries/chain/include/eosio/chain/webassembly/wavm.hpp

/**
 * Specialization for transcribing  a reference type in the native method signature
 *    This type transcribes into an int32  pointer checks the validity of that memory
 *    range before dispatching to the native method
 *
 * @tparam Ret - the return type of the native method
 * @tparam Inputs - the remaining native parameters to transcribe
 * @tparam Translated - the list of transcribed wasm parameters
 */
template<typename T, typename Ret, typename... Inputs, typename ...Translated>
struct intrinsic_invoker_impl<Ret, std::tuple<T &, Inputs...>, std::tuple<Translated...>> {
   using next_step = intrinsic_invoker_impl<Ret, std::tuple<Inputs...>, std::tuple<Translated..., I32>>;
   using then_type = Ret (*)(running_instance_context &, T &, Inputs..., Translated...);

   template<then_type Then, typename U=T>
   static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t<std::is_const<U>::value, Ret> {
      // references cannot be created for null pointers
      FC_ASSERT((U32)ptr != 0);
      MemoryInstance* mem = ctx.memory;
      if(!mem || (U32)ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem))
         Runtime::causeException(Exception::Cause::accessViolation);
      T &base = *(T*)(getMemoryBaseAddress(mem)+(U32)ptr);
      if ( reinterpret_cast<uintptr_t>(&base) % alignof(T) != 0 ) {
         wlog( "misaligned const reference" );
         std::remove_const_t<T> copy;
         T* copy_ptr = &copy;
         memcpy( (void*)copy_ptr, (void*)&base, sizeof(T) );
         return Then(ctx, *copy_ptr, rest..., translated...);
      }
      return Then(ctx, base, rest..., translated...);
   }

   template<then_type Then, typename U=T>
   static auto translate_one(running_instance_context& ctx, Inputs... rest, Translated... translated, I32 ptr) -> std::enable_if_t<!std::is_const<U>::value, Ret> {
      // references cannot be created for null pointers
      FC_ASSERT((U32)ptr != 0);
      MemoryInstance* mem = ctx.memory;
      if(!mem || (U32)ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem))
         Runtime::causeException(Exception::Cause::accessViolation);
      T &base = *(T*)(getMemoryBaseAddress(mem)+(U32)ptr);
      if ( reinterpret_cast<uintptr_t>(&base) % alignof(T) != 0 ) {
         wlog( "misaligned reference" );
         std::remove_const_t<T> copy;
         T* copy_ptr = &copy;
         memcpy( (void*)copy_ptr, (void*)&base, sizeof(T) );
         Ret ret = Then(ctx, *copy_ptr, rest..., translated...);
         memcpy( (void*)&base, (void*)copy_ptr, sizeof(T) );
         return ret;
      }
      return Then(ctx, base, rest..., translated...);
   }

   template<then_type Then>
   static const auto fn() {
      return next_step::template fn<translate_one<Then>>();
   }
};

這是一個調(diào)用包含reference類型native函數(shù)的結(jié)構(gòu),例如

void printi128( const int128_t* value );

這個api就會用這個結(jié)構(gòu)進行調(diào)用。

出問題的代碼如下,下面是已經(jīng)修復的代碼:

      if(!mem || (U32)ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem))

原來的代碼如下:

      if(!mem || ptr+sizeof(T) >= IR::numBytesPerPage*Runtime::getMemoryNumPages(mem))

即沒有加(U32)將int轉(zhuǎn)換成unsigned int,而sizeof(T)是一個unsigned long,在64位平臺上占用8個字節(jié)。所以當ptr和sizeof(T)相加時,編譯器會將ptr擴展為8個字節(jié),但是擴展的方式是和ptr的有signed和unsigned有關的,例如int類型的-1擴展成8字節(jié)的unsigned long時,實際上在內(nèi)存中的表示就從0xffffffff變成0xffffffffffffffff,而如果是先將int類型的-1轉(zhuǎn)成unsigned int,在這里是(U32)ptr,這樣編譯器在對其進行擴展的時候就會變成0x00000000ffffffff,即高位補0,所以(U32)ptr+sizeof(T)和ptr+sizeof(T)的結(jié)果是不一樣的。

這樣,當沒有加U32強制轉(zhuǎn)換時,一個負的ptr就有可能繞過檢測,而調(diào)用下面的代碼:

      T &base = *(T*)(getMemoryBaseAddress(mem)+ptr);

現(xiàn)己修復成

      T &base = *(T*)(getMemoryBaseAddress(mem)+(U32)ptr);

這樣會造成覆蓋不在wasm空間之內(nèi)的內(nèi)存,造成程序的數(shù)據(jù)的破壞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容