Commit message: None
CVE: CVE-2018-6063
CWE: CWE-787
Vulnerability description: Incorrect use of mojo::WrapSharedMemoryHandle in Mojo in Google Chrome prior to 65.0.3325.146 allowed a remote attacker who had compromised the renderer process to perform an out of bounds memory write via a crafted HTML page.

Project: Chrome

void ClientDiscardableSharedMemoryManager::AllocateCompletedOnIO(
     base::SharedMemoryHandle* handle,
     base::ScopedClosureRunner closure_runner,
     mojo::ScopedSharedBufferHandle mojo_handle) {
   if (!mojo_handle.is_valid())
     return;
   auto result = mojo::UnwrapSharedMemoryHandle(std::move(mojo_handle), handle,
                                               nullptr, nullptr);
   DCHECK_EQ(result, MOJO_RESULT_OK);
 }

Project: Chrome

bool PrintRenderFrameHelper::CopyMetafileDataToSharedMem(
bool PrintRenderFrameHelper::CopyMetafileDataToReadOnlySharedMem(
     const PdfMetafileSkia& metafile,
     base::SharedMemoryHandle* shared_mem_handle) {
   uint32_t buf_size = metafile.GetDataSize();
   if (buf_size == 0)
     return false;
 
  mojo::ScopedSharedBufferHandle buffer =
      mojo::SharedBufferHandle::Create(buf_size);
  if (!buffer.is_valid())
     return false;
 
  mojo::ScopedSharedBufferMapping mapping = buffer->Map(buf_size);
  if (!mapping)
     return false;
 
  if (!metafile.GetData(mapping.get(), buf_size))
     return false;
 
  MojoResult result = mojo::UnwrapSharedMemoryHandle(
      buffer->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
      shared_mem_handle, nullptr, nullptr);
  DCHECK_EQ(MOJO_RESULT_OK, result);
   return true;
 }

Project: Chrome

bool PrintRenderFrameHelper::FinalizePrintReadyDocument() {
  DCHECK(!is_print_ready_metafile_sent_);
  print_preview_context_.FinalizePrintReadyDocument();

   PdfMetafileSkia* metafile = print_preview_context_.metafile();
   PrintHostMsg_DidPreviewDocument_Params preview_params;
 
  if (!CopyMetafileDataToReadOnlySharedMem(
          *metafile, &preview_params.metafile_data_handle)) {
    LOG(ERROR) << "CopyMetafileDataToReadOnlySharedMem failed";
     print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
     return false;
   }

  preview_params.data_size = metafile->GetDataSize();
  preview_params.document_cookie = print_pages_params_->params.document_cookie;
  preview_params.expected_pages_count =
      print_preview_context_.total_page_count();
  preview_params.modifiable = print_preview_context_.IsModifiable();
  preview_params.preview_request_id =
      print_pages_params_->params.preview_request_id;

  is_print_ready_metafile_sent_ = true;

  Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params));
  return true;
}

Project: Chrome

bool PrintRenderFrameHelper::PreviewPageRendered(int page_number,
                                                 PdfMetafileSkia* metafile) {
  DCHECK_GE(page_number, FIRST_PAGE_INDEX);

  if (!print_preview_context_.IsModifiable() ||
      !print_preview_context_.generate_draft_pages()) {
    DCHECK(!metafile);
    return true;
  }

  if (!metafile) {
    NOTREACHED();
    print_preview_context_.set_error(
        PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE);
    return false;
   }
 
   PrintHostMsg_DidPreviewPage_Params preview_page_params;
  if (!CopyMetafileDataToReadOnlySharedMem(
          *metafile, &preview_page_params.metafile_data_handle)) {
    LOG(ERROR) << "CopyMetafileDataToReadOnlySharedMem failed";
     print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED);
     return false;
   }

  preview_page_params.data_size = metafile->GetDataSize();
  preview_page_params.page_number = page_number;
  preview_page_params.preview_request_id =
      print_pages_params_->params.preview_request_id;

  Send(new PrintHostMsg_DidPreviewPage(routing_id(), preview_page_params));
  return true;
}

Project: Chrome

bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
                                              int page_count) {
  const PrintMsg_PrintPages_Params& params = *print_pages_params_;
  const PrintMsg_Print_Params& print_params = params.params;

  std::vector<int> printed_pages = GetPrintedPages(params, page_count);
  if (printed_pages.empty())
    return false;

  PdfMetafileSkia metafile(print_params.printed_doc_type);
  CHECK(metafile.Init());

  PrintHostMsg_DidPrintDocument_Params page_params;
  PrintPageInternal(print_params, printed_pages[0], page_count, frame,
                    &metafile, &page_params.page_size,
                    &page_params.content_area);
  for (size_t i = 1; i < printed_pages.size(); ++i) {
    PrintPageInternal(print_params, printed_pages[i], page_count, frame,
                      &metafile, nullptr, nullptr);
  }

  FinishFramePrinting();
 
   metafile.FinishDocument();
 
  if (!CopyMetafileDataToReadOnlySharedMem(metafile,
                                           &page_params.metafile_data_handle)) {
     return false;
   }
 
  page_params.data_size = metafile.GetDataSize();
  page_params.document_cookie = print_params.document_cookie;
#if defined(OS_WIN)
  page_params.physical_offsets = printer_printable_area_.origin();
#endif
  Send(new PrintHostMsg_DidPrintDocument(routing_id(), page_params));
  return true;
}

Project: Chrome

bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
                                              int page_count) {
  const PrintMsg_PrintPages_Params& params = *print_pages_params_;
  const PrintMsg_Print_Params& print_params = params.params;

  std::vector<int> printed_pages = GetPrintedPages(params, page_count);
  if (printed_pages.empty())
    return false;

  PdfMetafileSkia metafile(print_params.printed_doc_type);
  CHECK(metafile.Init());

  for (int page_number : printed_pages) {
    PrintPageInternal(print_params, page_number, page_count, frame, &metafile,
                      nullptr, nullptr);
  }

  FinishFramePrinting();

  metafile.FinishDocument();

#if defined(OS_ANDROID)
  int sequence_number = -1;
  base::FileDescriptor fd;

  Send(new PrintHostMsg_AllocateTempFileForPrinting(routing_id(), &fd,
                                                    &sequence_number));
  if (!SaveToFD(metafile, fd))
    return false;

  Send(new PrintHostMsg_TempFileForPrintingWritten(
      routing_id(), sequence_number, printed_pages.size()));
   return true;
 #else
   PrintHostMsg_DidPrintDocument_Params page_params;
  if (!CopyMetafileDataToReadOnlySharedMem(metafile,
                                           &page_params.metafile_data_handle)) {
     return false;
   }
 
  page_params.data_size = metafile.GetDataSize();
  page_params.document_cookie = print_params.document_cookie;
  Send(new PrintHostMsg_DidPrintDocument(routing_id(), page_params));
  return true;
#endif  // defined(OS_ANDROID)
}

Project: Chrome

   void CallCompositorWithSuccess(mojom::PdfCompositorPtr ptr) {
     auto handle = CreateMSKPInSharedMemory();
     ASSERT_TRUE(handle.IsValid());
    mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
        handle, handle.GetSize(),
        mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
     ASSERT_TRUE(buffer_handle->is_valid());
     EXPECT_CALL(*this, CallbackOnSuccess(testing::_)).Times(1);
     ptr->CompositePdf(std::move(buffer_handle),
                      base::BindOnce(&PdfCompositorServiceTest::OnCallback,
                                     base::Unretained(this)));
    run_loop_->Run();
  }

Project: Chrome

  base::SharedMemoryHandle CreateMSKPInSharedMemory() {
    SkDynamicMemoryWStream stream;
    sk_sp<SkDocument> doc = SkMakeMultiPictureDocument(&stream);
    cc::SkiaPaintCanvas canvas(doc->beginPage(800, 600));
    SkRect rect = SkRect::MakeXYWH(10, 10, 250, 250);
    cc::PaintFlags flags;
    flags.setAntiAlias(false);
    flags.setColor(SK_ColorRED);
    flags.setStyle(cc::PaintFlags::kFill_Style);
    canvas.drawRect(rect, flags);
    doc->endPage();
    doc->close();

    size_t len = stream.bytesWritten();
    base::SharedMemoryCreateOptions options;
    options.size = len;
    options.share_read_only = true;

     base::SharedMemory shared_memory;
     if (shared_memory.Create(options) && shared_memory.Map(len)) {
       stream.copyTo(shared_memory.memory());
      return shared_memory.GetReadOnlyHandle();
     }
     return base::SharedMemoryHandle();
   }

Project: Chrome

void PdfCompositorClient::Composite(
    service_manager::Connector* connector,
    base::SharedMemoryHandle handle,
    size_t data_size,
    mojom::PdfCompositor::CompositePdfCallback callback,
    scoped_refptr<base::SequencedTaskRunner> callback_task_runner) {
  DCHECK(data_size);

   if (!compositor_)
     Connect(connector);
 
  mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
      handle, data_size,
      mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
 
   compositor_->CompositePdf(
       std::move(buffer_handle),
      base::BindOnce(&OnCompositePdf, base::Passed(&compositor_),
                     std::move(callback), callback_task_runner));
}

Project: Chrome

std::unique_ptr<base::SharedMemory> GetShmFromMojoHandle(
     mojo::ScopedSharedBufferHandle handle) {
   base::SharedMemoryHandle memory_handle;
   size_t memory_size = 0;
  mojo::UnwrappedSharedMemoryHandleProtection protection;
 
   const MojoResult result = mojo::UnwrapSharedMemoryHandle(
      std::move(handle), &memory_handle, &memory_size, &protection);
   if (result != MOJO_RESULT_OK)
     return nullptr;
   DCHECK_GT(memory_size, 0u);
 
  const bool read_only =
      protection == mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly;
   std::unique_ptr<base::SharedMemory> shm =
      std::make_unique<base::SharedMemory>(memory_handle, read_only);
   if (!shm->Map(memory_size)) {
     DLOG(ERROR) << "Map shared memory failed.";
     return nullptr;
  }
  return shm;
}

Project: Chrome

uint32_t ClientSharedBitmapManager::NotifyAllocatedSharedBitmap(
    base::SharedMemory* memory,
    const SharedBitmapId& id) {
  base::SharedMemoryHandle handle_to_send =
      base::SharedMemory::DuplicateHandle(memory->handle());
  if (!base::SharedMemory::IsHandleValid(handle_to_send)) {
    LOG(ERROR) << "Failed to duplicate shared memory handle for bitmap.";
    return 0;
   }
 
   mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
      handle_to_send, memory->mapped_size(),
      mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
 
   {
     base::AutoLock lock(lock_);
    (*shared_bitmap_allocation_notifier_)
        ->DidAllocateSharedBitmap(std::move(buffer_handle), id);
    return ++last_sequence_number_;
  }
}

Project: Chrome

void BrowserChildProcessHostImpl::ShareMetricsAllocatorToProcess() {
  if (metrics_allocator_) {
    HistogramController::GetInstance()->SetHistogramMemory<ChildProcessHost>(
         GetHost(),
         mojo::WrapSharedMemoryHandle(
             metrics_allocator_->shared_memory()->handle().Duplicate(),
            metrics_allocator_->shared_memory()->mapped_size(),
            mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite));
   } else {
     HistogramController::GetInstance()->SetHistogramMemory<ChildProcessHost>(
         GetHost(), mojo::ScopedSharedBufferHandle());
  }
}

Project: Chrome

void RenderProcessHostImpl::CreateSharedRendererHistogramAllocator() {
  if (!base::GlobalHistogramAllocator::Get()) {
    if (is_initialized_) {
      HistogramController::GetInstance()->SetHistogramMemory<RenderProcessHost>(
          this, mojo::ScopedSharedBufferHandle());
    }
    return;
  }

  base::ProcessHandle destination = GetHandle();
  if (destination == base::kNullProcessHandle)
    return;

  if (!metrics_allocator_) {
    std::unique_ptr<base::SharedMemory> shm(new base::SharedMemory());
    if (!shm->CreateAndMapAnonymous(2 << 20))  // 2 MiB
      return;
    metrics_allocator_.reset(new base::SharedPersistentMemoryAllocator(
        std::move(shm), GetID(), "RendererMetrics", /*readonly=*/false));
  }

   HistogramController::GetInstance()->SetHistogramMemory<RenderProcessHost>(
       this, mojo::WrapSharedMemoryHandle(
                 metrics_allocator_->shared_memory()->handle().Duplicate(),
                metrics_allocator_->shared_memory()->mapped_size(),
                mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite));
 }

Project: Chrome

void MojoAudioInputIPC::StreamCreated(
    media::mojom::AudioInputStreamPtr stream,
    media::mojom::AudioInputStreamClientRequest stream_client_request,
    mojo::ScopedSharedBufferHandle shared_memory,
    mojo::ScopedHandle socket,
    bool initially_muted) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(delegate_);
  DCHECK(socket.is_valid());
  DCHECK(shared_memory.is_valid());
  DCHECK(!stream_);
  DCHECK(!stream_client_binding_.is_bound());
  stream_ = std::move(stream);
  stream_client_binding_.Bind(std::move(stream_client_request));

  base::PlatformFile socket_handle;
  auto result = mojo::UnwrapPlatformFile(std::move(socket), &socket_handle);
   DCHECK_EQ(result, MOJO_RESULT_OK);
 
   base::SharedMemoryHandle memory_handle;
  mojo::UnwrappedSharedMemoryHandleProtection protection;
   result = mojo::UnwrapSharedMemoryHandle(std::move(shared_memory),
                                          &memory_handle, nullptr, &protection);
   DCHECK_EQ(result, MOJO_RESULT_OK);
  DCHECK_EQ(protection, mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
 
   delegate_->OnStreamCreated(memory_handle, socket_handle, initially_muted);
 }

Project: Chrome

void MojoAudioOutputIPC::StreamCreated(
    mojo::ScopedSharedBufferHandle shared_memory,
    mojo::ScopedHandle socket) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(delegate_);
  DCHECK(socket.is_valid());
  DCHECK(shared_memory.is_valid());

  base::PlatformFile socket_handle;
  auto result = mojo::UnwrapPlatformFile(std::move(socket), &socket_handle);
   DCHECK_EQ(result, MOJO_RESULT_OK);
 
   base::SharedMemoryHandle memory_handle;
  mojo::UnwrappedSharedMemoryHandleProtection protection;
   size_t memory_length = 0;
   result = mojo::UnwrapSharedMemoryHandle(
      std::move(shared_memory), &memory_handle, &memory_length, &protection);
   DCHECK_EQ(result, MOJO_RESULT_OK);
  DCHECK_EQ(protection,
            mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
 
   delegate_->OnStreamCreated(memory_handle, socket_handle);
 }

Project: Chrome

void VideoCaptureImpl::OnBufferCreated(int32_t buffer_id,
                                       mojo::ScopedSharedBufferHandle handle) {
  DVLOG(1) << __func__ << " buffer_id: " << buffer_id;
  DCHECK(io_thread_checker_.CalledOnValidThread());
  DCHECK(handle.is_valid());
 
   base::SharedMemoryHandle memory_handle;
   size_t memory_size = 0;
  mojo::UnwrappedSharedMemoryHandleProtection protection;
 
   const MojoResult result = mojo::UnwrapSharedMemoryHandle(
      std::move(handle), &memory_handle, &memory_size, &protection);
   DCHECK_EQ(MOJO_RESULT_OK, result);
   DCHECK_GT(memory_size, 0u);
 
  // TODO(https://crbug.com/803136): We should also be able to assert that the
  // unwrapped handle was shared for read-only mapping. That condition is not
  // currently guaranteed to be met.

   std::unique_ptr<base::SharedMemory> shm(
       new base::SharedMemory(memory_handle, true /* read_only */));
   if (!shm->Map(memory_size)) {
    DLOG(ERROR) << "OnBufferCreated: Map failed.";
    return;
  }
  const bool inserted =
      client_buffers_
          .insert(std::make_pair(buffer_id,
                                 new ClientBuffer(std::move(shm), memory_size)))
          .second;
  DCHECK(inserted);
}

Project: Chrome

   void SimulateOnBufferCreated(int buffer_id, const base::SharedMemory& shm) {
     video_capture_impl_->OnBufferCreated(
        buffer_id, mojo::WrapSharedMemoryHandle(
                       shm.GetReadOnlyHandle(), shm.mapped_size(),
                       mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly));
   }

Project: Chrome

 mojo::ScopedSharedBufferHandle GamepadProvider::GetSharedBufferHandle() {
  return mojo::WrapSharedMemoryHandle(
      gamepad_shared_buffer_->shared_memory()->GetReadOnlyHandle(),
      sizeof(GamepadHardwareBuffer),
      mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
 }

Project: Chrome

CommandBufferProxyImpl::AllocateAndMapSharedMemory(size_t size) {
  mojo::ScopedSharedBufferHandle handle =
      mojo::SharedBufferHandle::Create(size);
  if (!handle.is_valid()) {
    DLOG(ERROR) << "AllocateAndMapSharedMemory: Create failed";
    return nullptr;
  }
 
   base::SharedMemoryHandle platform_handle;
   size_t shared_memory_size;
  mojo::UnwrappedSharedMemoryHandleProtection protection;
   MojoResult result = mojo::UnwrapSharedMemoryHandle(
      std::move(handle), &platform_handle, &shared_memory_size, &protection);
   if (result != MOJO_RESULT_OK) {
     DLOG(ERROR) << "AllocateAndMapSharedMemory: Unwrap failed";
     return nullptr;
   }
   DCHECK_EQ(shared_memory_size, size);
 
  bool read_only =
      protection == mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly;
  auto shm = std::make_unique<base::SharedMemory>(platform_handle, read_only);
   if (!shm->Map(size)) {
     DLOG(ERROR) << "AllocateAndMapSharedMemory: Map failed";
     return nullptr;
  }

  return shm;
}

Project: Chrome

SharedMemoryHandleProvider::GetHandleForInterProcessTransit(bool read_only) {
  if (read_only_flag_ && !read_only) {
     NOTREACHED();
     return mojo::ScopedSharedBufferHandle();
   }
  // TODO(https://crbug.com/803136): This does not actually obey |read_only| in
  // any capacity because it uses DuplicateHandle. In order to properly obey
  // |read_only| (when true), we need to use |SharedMemory::GetReadOnlyHandle()|
  // but that is not possible. With the base::SharedMemory API and this
  // SharedMemoryHandleProvider API as they are today, it isn't possible to know
  // whether |shared_memory_| even supports read-only duplication. Note that
  // changing |kReadWrite| to |kReadOnly| does NOT affect the ability to map
  // the handle read-write.
   return mojo::WrapSharedMemoryHandle(
       base::SharedMemory::DuplicateHandle(shared_memory_->handle()),
      mapped_size_, mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
 }

Project: Chrome

bool SharedMemoryHandleProvider::InitFromMojoHandle(
    mojo::ScopedSharedBufferHandle buffer_handle) {
#if DCHECK_IS_ON()
  DCHECK_EQ(map_ref_count_, 0);
#endif
   DCHECK(!shared_memory_);
 
   base::SharedMemoryHandle memory_handle;
  mojo::UnwrappedSharedMemoryHandleProtection protection;
  const MojoResult result = mojo::UnwrapSharedMemoryHandle(
      std::move(buffer_handle), &memory_handle, &mapped_size_, &protection);
   if (result != MOJO_RESULT_OK)
     return false;
  read_only_flag_ =
      protection == mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly;
   shared_memory_.emplace(memory_handle, read_only_flag_);
   return true;
 }

Project: Chrome

  void UnwrapAndVerifyMojoHandle(mojo::ScopedSharedBufferHandle buffer_handle,
  void UnwrapAndVerifyMojoHandle(
      mojo::ScopedSharedBufferHandle buffer_handle,
      size_t expected_size,
      mojo::UnwrappedSharedMemoryHandleProtection expected_protection) {
     base::SharedMemoryHandle memory_handle;
     size_t memory_size = 0;
    mojo::UnwrappedSharedMemoryHandleProtection protection;
    const MojoResult result = mojo::UnwrapSharedMemoryHandle(
        std::move(buffer_handle), &memory_handle, &memory_size, &protection);
     EXPECT_EQ(MOJO_RESULT_OK, result);
     EXPECT_EQ(expected_size, memory_size);
    EXPECT_EQ(expected_protection, protection);
   }

Project: Chrome

void MojoJpegDecodeAccelerator::Decode(
    const BitstreamBuffer& bitstream_buffer,
    const scoped_refptr<VideoFrame>& video_frame) {
  DCHECK(io_task_runner_->BelongsToCurrentThread());
  DCHECK(jpeg_decoder_.is_bound());

  DCHECK(
      base::SharedMemory::IsHandleValid(video_frame->shared_memory_handle()));

  base::SharedMemoryHandle output_handle =
      base::SharedMemory::DuplicateHandle(video_frame->shared_memory_handle());
  if (!base::SharedMemory::IsHandleValid(output_handle)) {
    DLOG(ERROR) << "Failed to duplicate handle of VideoFrame";
    return;
  }

   size_t output_buffer_size = VideoFrame::AllocationSize(
       video_frame->format(), video_frame->coded_size());
   mojo::ScopedSharedBufferHandle output_frame_handle =
      mojo::WrapSharedMemoryHandle(
          output_handle, output_buffer_size,
          mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
 
   jpeg_decoder_->Decode(bitstream_buffer, video_frame->coded_size(),
                        std::move(output_frame_handle),
                        base::checked_cast<uint32_t>(output_buffer_size),
                        base::Bind(&MojoJpegDecodeAccelerator::OnDecodeAck,
                                   base::Unretained(this)));
}

Project: Chrome

void MojoVideoEncodeAccelerator::Encode(const scoped_refptr<VideoFrame>& frame,
                                        bool force_keyframe) {
  DVLOG(2) << __func__ << " tstamp=" << frame->timestamp();
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK_EQ(PIXEL_FORMAT_I420, frame->format());
  DCHECK_EQ(VideoFrame::STORAGE_SHMEM, frame->storage_type());
  DCHECK(frame->shared_memory_handle().IsValid());

  const size_t allocation_size = frame->shared_memory_handle().GetSize();
 
  //
  // TODO(https://crbug.com/793446): This should be changed to wrap the frame
  // buffer handle as read-only, but VideoFrame does not seem to guarantee that
  // its shared_memory_handle() is in fact read-only.
  mojo::ScopedSharedBufferHandle handle = mojo::WrapSharedMemoryHandle(
      frame->shared_memory_handle().Duplicate(), allocation_size,
      mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
 
   const size_t y_offset = frame->shared_memory_offset();
   const size_t u_offset = y_offset + frame->data(VideoFrame::kUPlane) -
                          frame->data(VideoFrame::kYPlane);
  const size_t v_offset = y_offset + frame->data(VideoFrame::kVPlane) -
                          frame->data(VideoFrame::kYPlane);
  scoped_refptr<MojoSharedBufferVideoFrame> mojo_frame =
      MojoSharedBufferVideoFrame::Create(
          frame->format(), frame->coded_size(), frame->visible_rect(),
          frame->natural_size(), std::move(handle), allocation_size, y_offset,
          u_offset, v_offset, frame->stride(VideoFrame::kYPlane),
          frame->stride(VideoFrame::kUPlane),
          frame->stride(VideoFrame::kVPlane), frame->timestamp());

  DCHECK(vea_.is_bound());
  vea_->Encode(mojo_frame, force_keyframe,
               base::Bind(&KeepVideoFrameAlive, frame));
}

Project: Chrome

    memory_handle(const media::BitstreamBuffer& input) {
  base::SharedMemoryHandle input_handle =
      base::SharedMemory::DuplicateHandle(input.handle());
  if (!base::SharedMemory::IsHandleValid(input_handle)) {
     DLOG(ERROR) << "Failed to duplicate handle of BitstreamBuffer";
     return mojo::ScopedSharedBufferHandle();
   }

  // TODO(https://crbug.com/793446): Update this to |kReadOnly| protection once
  // BitstreamBuffer can guarantee that its handle() field always corresponds to
  // a read-only SharedMemoryHandle.
  return mojo::WrapSharedMemoryHandle(
      input_handle, input.size(),
      mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
 }

Project: Chrome

void MojoAudioInputStream::OnStreamCreated(
    int stream_id,
    const base::SharedMemory* shared_memory,
    std::unique_ptr<base::CancelableSyncSocket> foreign_socket,
    bool initially_muted) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(stream_created_callback_);
  DCHECK(shared_memory);
  DCHECK(foreign_socket);

  base::SharedMemoryHandle foreign_memory_handle =
      shared_memory->GetReadOnlyHandle();
  if (!base::SharedMemory::IsHandleValid(foreign_memory_handle)) {
    OnStreamError(/*not used*/ 0);
    return;
  }
 
   mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
       foreign_memory_handle, shared_memory->requested_size(),
      mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
   mojo::ScopedHandle socket_handle =
       mojo::WrapPlatformFile(foreign_socket->Release());
 
  DCHECK(buffer_handle.is_valid());
  DCHECK(socket_handle.is_valid());

  base::ResetAndReturn(&stream_created_callback_)
      .Run(std::move(buffer_handle), std::move(socket_handle), initially_muted);
}

Project: Chrome

  void Initialized(mojo::ScopedSharedBufferHandle shared_buffer,
                   mojo::ScopedHandle socket_handle,
                   bool initially_muted) {
    ASSERT_TRUE(shared_buffer.is_valid());
    ASSERT_TRUE(socket_handle.is_valid());

    base::PlatformFile fd;
    mojo::UnwrapPlatformFile(std::move(socket_handle), &fd);
    socket_ = std::make_unique<base::CancelableSyncSocket>(fd);
    EXPECT_NE(socket_->handle(), base::CancelableSyncSocket::kInvalidHandle);
 
     size_t memory_length;
     base::SharedMemoryHandle shmem_handle;
    mojo::UnwrappedSharedMemoryHandleProtection protection;
     EXPECT_EQ(
         mojo::UnwrapSharedMemoryHandle(std::move(shared_buffer), &shmem_handle,
                                       &memory_length, &protection),
         MOJO_RESULT_OK);
    EXPECT_EQ(protection,
              mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
    buffer_ = std::make_unique<base::SharedMemory>(shmem_handle,
                                                   true /* read_only */);
 
     GotNotification(initially_muted);
   }

Project: Chrome

void MojoAudioOutputStream::OnStreamCreated(
    int stream_id,
    const base::SharedMemory* shared_memory,
    std::unique_ptr<base::CancelableSyncSocket> foreign_socket) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(stream_created_callback_);
  DCHECK(shared_memory);
  DCHECK(foreign_socket);

  base::SharedMemoryHandle foreign_memory_handle =
      base::SharedMemory::DuplicateHandle(shared_memory->handle());
  if (!base::SharedMemory::IsHandleValid(foreign_memory_handle)) {
    OnStreamError(/*not used*/ 0);
    return;
   }
 
   mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
      foreign_memory_handle, shared_memory->requested_size(),
      mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
   mojo::ScopedHandle socket_handle =
       mojo::WrapPlatformFile(foreign_socket->Release());
 
  DCHECK(buffer_handle.is_valid());
  DCHECK(socket_handle.is_valid());

  base::ResetAndReturn(&stream_created_callback_)
      .Run(std::move(buffer_handle), std::move(socket_handle));
}

Project: Chrome

  void Initialized(mojo::ScopedSharedBufferHandle shared_buffer,
                   mojo::ScopedHandle socket_handle) {
    ASSERT_TRUE(shared_buffer.is_valid());
    ASSERT_TRUE(socket_handle.is_valid());

    base::PlatformFile fd;
    mojo::UnwrapPlatformFile(std::move(socket_handle), &fd);
    socket_ = std::make_unique<base::CancelableSyncSocket>(fd);
    EXPECT_NE(socket_->handle(), base::CancelableSyncSocket::kInvalidHandle);
 
     size_t memory_length;
     base::SharedMemoryHandle shmem_handle;
    mojo::UnwrappedSharedMemoryHandleProtection protection;
     EXPECT_EQ(
         mojo::UnwrapSharedMemoryHandle(std::move(shared_buffer), &shmem_handle,
                                       &memory_length, &protection),
         MOJO_RESULT_OK);
    EXPECT_EQ(protection,
              mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
    buffer_ = std::make_unique<base::SharedMemory>(shmem_handle,
                                                   false /* read_only */);
 
     GotNotification();
   }

Project: Chrome

void MojoVideoEncodeAcceleratorService::UseOutputBitstreamBuffer(
    int32_t bitstream_buffer_id,
    mojo::ScopedSharedBufferHandle buffer) {
  DVLOG(2) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id;
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  if (!encoder_)
    return;
  if (!buffer.is_valid()) {
    DLOG(ERROR) << __func__ << " invalid |buffer|.";
    NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
    return;
  }
  if (bitstream_buffer_id < 0) {
    DLOG(ERROR) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
                << " must be >= 0";
    NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
    return;
  }
 
   base::SharedMemoryHandle handle;
   size_t memory_size = 0;
   auto result = mojo::UnwrapSharedMemoryHandle(std::move(buffer), &handle,
                                               &memory_size, nullptr);
   if (result != MOJO_RESULT_OK || memory_size == 0u) {
     DLOG(ERROR) << __func__ << " mojo::UnwrapSharedMemoryHandle() failed";
     NotifyError(::media::VideoEncodeAccelerator::kPlatformFailureError);
    return;
  }

  if (memory_size < output_buffer_size_) {
    DLOG(ERROR) << __func__ << " bitstream_buffer_id=" << bitstream_buffer_id
                << " has a size of " << memory_size
                << "B, different from expected " << output_buffer_size_ << "B";
    NotifyError(::media::VideoEncodeAccelerator::kInvalidArgumentError);
    return;
  }

  encoder_->UseOutputBitstreamBuffer(
      BitstreamBuffer(bitstream_buffer_id, handle, memory_size));
}

Project: Chrome

MojoResult Core::UnwrapPlatformSharedBufferHandle(
    MojoHandle mojo_handle,
    MojoPlatformHandle* platform_handle,
    size_t* size,
    MojoSharedBufferGuid* guid,
    MojoPlatformSharedBufferHandleFlags* flags) {
  scoped_refptr<Dispatcher> dispatcher;
  MojoResult result = MOJO_RESULT_OK;
  {
    base::AutoLock lock(handles_->GetLock());
    result = handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher);
    if (result != MOJO_RESULT_OK)
      return result;
  }

  if (dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER) {
    dispatcher->Close();
    return MOJO_RESULT_INVALID_ARGUMENT;
  }

  SharedBufferDispatcher* shm_dispatcher =
      static_cast<SharedBufferDispatcher*>(dispatcher.get());
  scoped_refptr<PlatformSharedBuffer> platform_shared_buffer =
      shm_dispatcher->PassPlatformSharedBuffer();
  DCHECK(platform_shared_buffer);

  DCHECK(size);
  *size = platform_shared_buffer->GetNumBytes();

  base::UnguessableToken token = platform_shared_buffer->GetGUID();
  guid->high = token.GetHighForSerialization();
  guid->low = token.GetLowForSerialization();

   DCHECK(flags);
   *flags = MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE;
   if (platform_shared_buffer->IsReadOnly())
    *flags |= MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_HANDLE_IS_READ_ONLY;
 
   ScopedPlatformHandle handle = platform_shared_buffer->PassPlatformHandle();
   return ScopedPlatformHandleToMojoPlatformHandle(std::move(handle),
                                                  platform_handle);
}

Project: Chrome

MojoResult Core::WrapPlatformSharedBufferHandle(
    const MojoPlatformHandle* platform_handle,
    size_t size,
    const MojoSharedBufferGuid* guid,
    MojoPlatformSharedBufferHandleFlags flags,
    MojoHandle* mojo_handle) {
  DCHECK(size);
  ScopedPlatformHandle handle;
  MojoResult result =
      MojoPlatformHandleToScopedPlatformHandle(platform_handle, &handle);
  if (result != MOJO_RESULT_OK)
    return result;
 
   base::UnguessableToken token =
       base::UnguessableToken::Deserialize(guid->high, guid->low);
  const bool read_only =
      flags & MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_HANDLE_IS_READ_ONLY;
   scoped_refptr<PlatformSharedBuffer> platform_buffer =
       PlatformSharedBuffer::CreateFromPlatformHandle(size, read_only, token,
                                                      std::move(handle));
  if (!platform_buffer)
    return MOJO_RESULT_UNKNOWN;

  scoped_refptr<SharedBufferDispatcher> dispatcher;
  result = SharedBufferDispatcher::CreateFromPlatformSharedBuffer(
      platform_buffer, &dispatcher);
  if (result != MOJO_RESULT_OK)
    return result;

  MojoHandle h = AddDispatcher(dispatcher);
  if (h == MOJO_HANDLE_INVALID) {
    dispatcher->Close();
    return MOJO_RESULT_RESOURCE_EXHAUSTED;
  }

  *mojo_handle = h;
  return MOJO_RESULT_OK;
}

Project: Chrome

MojoResult UnwrapSharedMemoryHandle(ScopedSharedBufferHandle handle,
MojoResult UnwrapSharedMemoryHandle(
    ScopedSharedBufferHandle handle,
    base::SharedMemoryHandle* memory_handle,
    size_t* size,
    UnwrappedSharedMemoryHandleProtection* protection) {
   if (!handle.is_valid())
     return MOJO_RESULT_INVALID_ARGUMENT;
   MojoPlatformHandle platform_handle;
  platform_handle.struct_size = sizeof(MojoPlatformHandle);

  MojoPlatformSharedBufferHandleFlags flags;
  size_t num_bytes;
  MojoSharedBufferGuid mojo_guid;
  MojoResult result = MojoUnwrapPlatformSharedBufferHandle(
      handle.release().value(), &platform_handle, &num_bytes, &mojo_guid,
      &flags);
  if (result != MOJO_RESULT_OK)
    return result;

   if (size)
     *size = num_bytes;
 
  if (protection) {
    *protection =
        flags & MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_HANDLE_IS_READ_ONLY
            ? UnwrappedSharedMemoryHandleProtection::kReadOnly
            : UnwrappedSharedMemoryHandleProtection::kReadWrite;
  }
 
   base::UnguessableToken guid =
       base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low);
#if defined(OS_MACOSX) && !defined(OS_IOS)
  DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT);
  *memory_handle = base::SharedMemoryHandle(
      static_cast<mach_port_t>(platform_handle.value), num_bytes, guid);
#elif defined(OS_FUCHSIA)
  DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE);
  *memory_handle = base::SharedMemoryHandle(
      static_cast<zx_handle_t>(platform_handle.value), num_bytes, guid);
#elif defined(OS_POSIX)
  DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR);
  *memory_handle = base::SharedMemoryHandle(
      base::FileDescriptor(static_cast<int>(platform_handle.value), false),
      num_bytes, guid);
#elif defined(OS_WIN)
  DCHECK_EQ(platform_handle.type, MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE);
  *memory_handle = base::SharedMemoryHandle(
      reinterpret_cast<HANDLE>(platform_handle.value), num_bytes, guid);
#endif

  return MOJO_RESULT_OK;
}

Project: Chrome

 ScopedSharedBufferHandle WrapSharedMemoryHandle(
     const base::SharedMemoryHandle& memory_handle,
     size_t size,
    UnwrappedSharedMemoryHandleProtection protection) {
   if (!memory_handle.IsValid())
     return ScopedSharedBufferHandle();
   MojoPlatformHandle platform_handle;
  platform_handle.struct_size = sizeof(MojoPlatformHandle);
  platform_handle.type = kPlatformSharedBufferHandleType;
#if defined(OS_MACOSX) && !defined(OS_IOS)
  platform_handle.value =
      static_cast<uint64_t>(memory_handle.GetMemoryObject());
#else
  platform_handle.value =
      PlatformHandleValueFromPlatformFile(memory_handle.GetHandle());
#endif
 
   MojoPlatformSharedBufferHandleFlags flags =
       MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_NONE;
  if (protection == UnwrappedSharedMemoryHandleProtection::kReadOnly)
    flags |= MOJO_PLATFORM_SHARED_BUFFER_HANDLE_FLAG_HANDLE_IS_READ_ONLY;
 
   MojoSharedBufferGuid guid;
   guid.high = memory_handle.GetGUID().GetHighForSerialization();
  guid.low = memory_handle.GetGUID().GetLowForSerialization();
  MojoHandle mojo_handle;
  MojoResult result = MojoWrapPlatformSharedBufferHandle(
      &platform_handle, size, &guid, flags, &mojo_handle);
  CHECK_EQ(result, MOJO_RESULT_OK);

   return ScopedSharedBufferHandle(SharedBufferHandle(mojo_handle));
 }

Project: Chrome

    shared_memory_handle(const gfx::GpuMemoryBufferHandle& handle) {
  if (handle.type != gfx::SHARED_MEMORY_BUFFER &&
       handle.type != gfx::DXGI_SHARED_HANDLE &&
       handle.type != gfx::ANDROID_HARDWARE_BUFFER)
     return mojo::ScopedSharedBufferHandle();
  return mojo::WrapSharedMemoryHandle(
      handle.handle, handle.handle.GetSize(),
      mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
 }