Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chromium issues #79

Open
xinali opened this issue Jun 23, 2022 · 0 comments
Open

chromium issues #79

xinali opened this issue Jun 23, 2022 · 0 comments

Comments

@xinali
Copy link
Owner

xinali commented Jun 23, 2022

chromium issues

主要记录我阅读或者复现过的一些浏览器漏洞,如果复现复杂会单独开文章,个人对这方面积累有限,难免会存在错误,欢迎批评指正。

阅读这些漏洞不一定是为了深挖什么,然后挖掘相关的漏洞,更多的是为了自己通过对以前漏洞熟悉,然后去了解浏览器的各方面知识,浏览器涉及的内容,实在太多了,直接入手会让人很迷茫,了解漏洞,然后去了解修复的原理,该部分的一些设计模式,代码编写习惯等等。

其中很多术语,感觉中文翻译后可能会存在歧义,我一般会使用原始英文术语

1174551

issue1174551

这个漏洞是直接fuzz出来的,poc没有权限拿到,所以直接来看修复代码,修复的review 2653810

看修复代码前,首先需要理解javascript两个概念,ArrayBuffersSharedArrayBuffers,我在后面提供了一个相关知识链接,可以通过阅读它来做简要的了解。

主线程和web workers属于不同的线程,对于javascript来说,不同的线程不会共享内存

简单点说,ArrayBuffers就是javascript提供的一个能够存储原始数据的对象,对于存储的数据,它没有作任何的标识,就是单纯的二进制数据,如果需要类型化,可能需要typed arraysArrayBuffers不支持线程间共享,如果想实现线程共享,比如主线程和web workers线程想同时访问它,只能通过postMessage进transferring memory,但是有个缺点就是transfer之后,原始线程不能再访问该数据,已经被detached,可以参见mdn Transferable objects

Transferrable objects* are commonly used to share resources that can only be safely exposed to a single JavaScript thread at a time. For example, an ArrayBuffer is a transferrable object that owns a block of memory. When such a buffer is transferred between threads, the associated memory resource is detached from the original buffer and attached to the buffer object created in the new thread. The buffer object in the original thread is no longer usable because it no longer owns a memory resource.

SharedArrayBuffers则弥补了这部分的缺点,postMessage之后线程间依然可以读写该数据,但需要注意读写锁的控制。

再回头来看1174551review代码,主要修复在这里

Maybe<bool> ValueSerializer::WriteJSArrayBuffer(
    Handle<JSArrayBuffer> array_buffer) {
  if (array_buffer->is_shared()) {
    if (!delegate_) {
      ThrowDataCloneError(MessageTemplate::kDataCloneError, array_buffer);
      return Nothing<bool>();
    }
    v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
    Maybe<uint32_t> index = delegate_->GetSharedArrayBufferId(
        v8_isolate, Utils::ToLocalShared(array_buffer));
    RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
    WriteTag(SerializationTag::kSharedArrayBuffer);
    WriteVarint(index.FromJust());
    return ThrowIfOutOfMemory();
  }
  
  ->>>>>>
  if (!array_buffer->is_detachable()) { // 因为使用的是ArrayBuffer,所以需要增加对是否detached的判断
    ThrowDataCloneError(
        MessageTemplate::kDataCloneErrorNonDetachableArrayBuffer);
    return Nothing<bool>();
  }
  <<<<<<-
  

1166012

issue 1166012

clusterfuzz测试出来的,基础信息是这样的

Crash Type: Heap-buffer-overflow READ 8
Crash Address: 0x6040002d4288
Crash State:
  ash::ScrollableShelfView::ShouldCountActivatedInkDrop
  ash::ScrollableShelfView::CreateScopedActiveInkDropCount
  ash::ScrollableShelfView::CreateScopedActiveInkDropCount

修复的描述是这样的

[Shelf] Handle the edge case of no tappable icon

It is a crash reported by fuzz. Based on ScrollableShelfView::CalculateTappableIconIndices(), `first_tappable_app_index_` and `last_tappable_app_index_` may be both illegal. This edge case should be handled by the function where the crash occurs.

shelf中没有tappable icon,理解这个含义,需要大概知道shelf具体怎么组成的,然后如果没有应用的情况下,会怎么呈现。

具体参见:https://support.google.com/chromebook/answer/3113576?hl=en

大概了解之后,来跟一下调用栈

如果没有修复代码

bool ScrollableShelfView::ShouldCountActivatedInkDrop(
    const views::View* sender) const {
  bool should_count = false;

  // When scrolling shelf by gestures, the shelf icon's ink drop ripple may be
  // activated accidentally. So ignore the ink drop activity during animation.
  if (during_scroll_animation_)
    return should_count;


 <---- 修复代码
  if (first_tappable_app_index_ == -1 || last_tappable_app_index_ == -1) {
    // Verify that `first_tappable_app_index_` and `last_tappable_app_index_`
    // may be both illegal. In that case, return early.
    DCHECK_EQ(first_tappable_app_index_, last_tappable_app_index_);
    return false;
  }
  -----> 

  // The ink drop needs to be clipped only if |sender| is the app at one of the
  // corners of the shelf. This happens if it is either the first or the last
  // tappable app and no arrow is showing on its side.
  if (shelf_view_->view_model()->view_at(first_tappable_app_index_) == sender) {
    should_count = !(layout_strategy_ == kShowButtons ||
                     layout_strategy_ == kShowLeftArrowButton);
  } else if (shelf_view_->view_model()->view_at(last_tappable_app_index_) ==
             sender) {
    should_count = !(layout_strategy_ == kShowButtons ||
                     layout_strategy_ == kShowRightArrowButton);

正常调用栈应该是这样

ash/shelf/scrollable_shelf_view.cc
    -> ScrollableShelfView::ShouldCountActivatedInkDrop
        -> shelf_view_->view_model()->view_at(first_tappable_app_index_) 	

shelf_view定义在

ash/shelf/scrollable_shelf_view.h
     -> ShelfView* shelf_view_ = nullptr; 

ShelfView定义在

ash/shelf/shelf_view.h
   -> const views::ViewModel* view_model() const { return view_model_.get(); }
       -> std::unique_ptr<views::ViewModel> view_model_;
            -> T* view_at(size_t index) const { return static_cast<T*>(ViewAtBase(index)); }

ViewAtBase函数ui/views/view_model.h

View* ViewAtBase(size_t index) const {
    check_index(index);
    return entries_[index].view;
 }

check_index位于ui/views/view_model.h

void check_index(size_t index) const { DCHECK_LT(index, entries_.size()); }

其中Entries

using Entries = std::vector<Entry>;

到这里整个调用栈就清晰了,但是根据这个调用栈再加上自己的测试,感觉不会想clusterfuzz那样成功触发崩溃,因为check_index-1不会小于size(),在这里就会返回。因为没有poc没有办法具体分析,这个issue大概就这样了。

参考

A cartoon intro to ArrayBuffers and SharedArrayBuffers

Transferable objects

@xinali xinali added the browser label Jun 23, 2022
@xinali xinali removed the Chromium label Mar 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant