美文网首页
"WAVM: Incorrect bounds che

"WAVM: Incorrect bounds che

作者: learnforever01 | 来源:发表于2018-05-31 12:31 被阅读66次

    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>>();
       }
    };
    

    这是一个调用包含reference类型native函数的结构,例如

    void printi128( const int128_t* value );
    

    这个api就会用这个结构进行调用。

    出问题的代码如下,下面是已经修复的代码:

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

    原来的代码如下:

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

    即没有加(U32)将int转换成unsigned int,而sizeof(T)是一个unsigned long,在64位平台上占用8个字节。所以当ptr和sizeof(T)相加时,编译器会将ptr扩展为8个字节,但是扩展的方式是和ptr的有signed和unsigned有关的,例如int类型的-1扩展成8字节的unsigned long时,实际上在内存中的表示就从0xffffffff变成0xffffffffffffffff,而如果是先将int类型的-1转成unsigned int,在这里是(U32)ptr,这样编译器在对其进行扩展的时候就会变成0x00000000ffffffff,即高位补0,所以(U32)ptr+sizeof(T)和ptr+sizeof(T)的结果是不一样的。

    这样,当没有加U32强制转换时,一个负的ptr就有可能绕过检测,而调用下面的代码:

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

    现己修复成

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

    这样会造成覆盖不在wasm空间之内的内存,造成程序的数据的破坏。

    相关文章

      网友评论

          本文标题:"WAVM: Incorrect bounds che

          本文链接:https://www.haomeiwen.com/subject/gskqsftx.html