Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Side by Side Diff: chrome/browser/android/vr_shell/vr_shell_gl.cc

Issue 2950233002: Validate untrusted VR mojo inputs into browser process (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/android/vr_shell/vr_shell_gl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/android/vr_shell/vr_shell_gl.h" 5 #include "chrome/browser/android/vr_shell/vr_shell_gl.h"
6 6
7 #include <chrono> 7 #include <chrono>
8 #include <limits> 8 #include <limits>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 const gpu::MailboxHolder& mailbox) { 371 const gpu::MailboxHolder& mailbox) {
372 TRACE_EVENT0("gpu", "VrShellGl::SubmitWebVRFrame"); 372 TRACE_EVENT0("gpu", "VrShellGl::SubmitWebVRFrame");
373 373
374 // submit_client_ could be null when we exit presentation, if there were 374 // submit_client_ could be null when we exit presentation, if there were
375 // pending SubmitFrame messages queued. VRDisplayClient::OnExitPresent 375 // pending SubmitFrame messages queued. VRDisplayClient::OnExitPresent
376 // will clean up state in blink, so it doesn't wait for 376 // will clean up state in blink, so it doesn't wait for
377 // OnSubmitFrameTransferred or OnSubmitFrameRendered. 377 // OnSubmitFrameTransferred or OnSubmitFrameRendered.
378 if (!submit_client_.get()) 378 if (!submit_client_.get())
379 return; 379 return;
380 380
381 if (frame_index < 0 ||
382 !webvr_frame_oustanding_[frame_index % kPoseRingBufferSize]) {
383 mojo::ReportBadMessage("SubmitFrame called with an invalid frame_index");
384 binding_.Close();
385 return;
386 }
387
381 webvr_time_js_submit_[frame_index % kPoseRingBufferSize] = 388 webvr_time_js_submit_[frame_index % kPoseRingBufferSize] =
382 base::TimeTicks::Now(); 389 base::TimeTicks::Now();
383 390
384 // Swapping twice on a Surface without calling updateTexImage in 391 // Swapping twice on a Surface without calling updateTexImage in
385 // between can lose frames, so don't draw+swap if we already have 392 // between can lose frames, so don't draw+swap if we already have
386 // a pending frame we haven't consumed yet. 393 // a pending frame we haven't consumed yet.
387 bool swapped = false; 394 bool swapped = false;
388 if (pending_frames_.empty()) { 395 if (pending_frames_.empty()) {
389 swapped = mailbox_bridge_->CopyMailboxToSurfaceAndSwap(mailbox); 396 swapped = mailbox_bridge_->CopyMailboxToSurfaceAndSwap(mailbox);
390 if (swapped) { 397 if (swapped) {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
448 browser_->ToggleCardboardGamepad(true); 455 browser_->ToggleCardboardGamepad(true);
449 } 456 }
450 } 457 }
451 458
452 void VrShellGl::InitializeRenderer() { 459 void VrShellGl::InitializeRenderer() {
453 gvr_api_->InitializeGl(); 460 gvr_api_->InitializeGl();
454 gfx::Transform head_pose; 461 gfx::Transform head_pose;
455 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); 462 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose);
456 webvr_head_pose_.assign(kPoseRingBufferSize, head_pose); 463 webvr_head_pose_.assign(kPoseRingBufferSize, head_pose);
457 webvr_time_pose_.assign(kPoseRingBufferSize, base::TimeTicks()); 464 webvr_time_pose_.assign(kPoseRingBufferSize, base::TimeTicks());
465 webvr_frame_oustanding_.assign(kPoseRingBufferSize, false);
458 webvr_time_js_submit_.assign(kPoseRingBufferSize, base::TimeTicks()); 466 webvr_time_js_submit_.assign(kPoseRingBufferSize, base::TimeTicks());
459 467
460 std::vector<gvr::BufferSpec> specs; 468 std::vector<gvr::BufferSpec> specs;
461 // For kFramePrimaryBuffer (primary VrShell and WebVR content) 469 // For kFramePrimaryBuffer (primary VrShell and WebVR content)
462 specs.push_back(gvr_api_->CreateBufferSpec()); 470 specs.push_back(gvr_api_->CreateBufferSpec());
463 gvr::Sizei render_size_primary = specs[kFramePrimaryBuffer].GetSize(); 471 gvr::Sizei render_size_primary = specs[kFramePrimaryBuffer].GetSize();
464 render_size_primary_ = {render_size_primary.width, 472 render_size_primary_ = {render_size_primary.width,
465 render_size_primary.height}; 473 render_size_primary.height};
466 render_size_vrshell_ = render_size_primary_; 474 render_size_vrshell_ = render_size_primary_;
467 475
(...skipping 592 matching lines...) Expand 10 before | Expand all | Expand 10 after
1060 1068
1061 // When using async reprojection, we need to know which pose was 1069 // When using async reprojection, we need to know which pose was
1062 // used in the WebVR app for drawing this frame and supply it when 1070 // used in the WebVR app for drawing this frame and supply it when
1063 // submitting. Technically we don't need a pose if not reprojecting, 1071 // submitting. Technically we don't need a pose if not reprojecting,
1064 // but keeping it uninitialized seems likely to cause problems down 1072 // but keeping it uninitialized seems likely to cause problems down
1065 // the road. Copying it is cheaper than fetching a new one. 1073 // the road. Copying it is cheaper than fetching a new one.
1066 if (ShouldDrawWebVr()) { 1074 if (ShouldDrawWebVr()) {
1067 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), 1075 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize),
1068 "kPoseRingBufferSize must be a power of 2"); 1076 "kPoseRingBufferSize must be a power of 2");
1069 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; 1077 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize];
1078 webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = false;
1070 } else { 1079 } else {
1071 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); 1080 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose);
1072 } 1081 }
1073 1082
1074 // Update the render position of all UI elements (including desktop). 1083 // Update the render position of all UI elements (including desktop).
1075 scene_->OnBeginFrame(current_time); 1084 scene_->OnBeginFrame(current_time);
1076 1085
1077 { 1086 {
1078 // TODO(crbug.com/704690): Acquire controller state in a way that's timely 1087 // TODO(crbug.com/704690): Acquire controller state in a way that's timely
1079 // for both the gamepad API and UI input handling. 1088 // for both the gamepad API and UI input handling.
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after
1568 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); 1577 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000);
1569 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); 1578 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds);
1570 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); 1579 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this)));
1571 OnVSync(); 1580 OnVSync();
1572 } 1581 }
1573 1582
1574 void VrShellGl::ForceExitVr() { 1583 void VrShellGl::ForceExitVr() {
1575 browser_->ForceExitVr(); 1584 browser_->ForceExitVr();
1576 } 1585 }
1577 1586
1587 namespace {
1588 bool ValidateRect(const gfx::RectF& bounds) {
1589 // Bounds should be between 0 and 1, with positive width/height
1590 constexpr gfx::SizeF max_size(1, 1);
1591 constexpr gfx::SizeF min_size(0, 0);
1592
1593 return bounds.x() < bounds.right() && bounds.y() < bounds.bottom() &&
mthiesse 2017/06/22 05:59:47 You can hugely simplify this. I think the set of c
billorr 2017/07/10 18:59:23 Done.
1594 bounds.x() <= max_size.width() && bounds.x() >= min_size.width() &&
1595 bounds.right() <= max_size.width() &&
1596 bounds.right() >= min_size.width() &&
1597 bounds.y() <= max_size.height() && bounds.y() >= min_size.height() &&
1598 bounds.bottom() <= max_size.height() &&
1599 bounds.bottom() >= min_size.height();
1600 }
1601
1602 bool ValidateSize(const gfx::Size& size) {
1603 // Size should be between at least 2 in each direction and less than 5000.
billorr 2017/06/22 00:28:34 arbitrary values - what should we use? Or are we
mthiesse 2017/06/22 05:59:46 Not sure. The only problem I can see is intentiona
1604 constexpr gfx::Size max_size(5000, 5000);
1605 constexpr gfx::Size min_size(2, 2);
1606
1607 return size.width() <= max_size.width() &&
1608 size.height() <= max_size.height() &&
1609 size.width() >= min_size.width() && size.height() >= min_size.height();
1610 }
1611 } // namespace
1612
1578 void VrShellGl::UpdateLayerBounds(int16_t frame_index, 1613 void VrShellGl::UpdateLayerBounds(int16_t frame_index,
1579 const gfx::RectF& left_bounds, 1614 const gfx::RectF& left_bounds,
1580 const gfx::RectF& right_bounds, 1615 const gfx::RectF& right_bounds,
1581 const gfx::Size& source_size) { 1616 const gfx::Size& source_size) {
1617 if (!ValidateRect(left_bounds) || !ValidateRect(right_bounds) ||
1618 !ValidateSize(source_size)) {
1619 mojo::ReportBadMessage("UpdateLayerBounds called with invalid bounds");
mthiesse 2017/06/22 05:59:46 So I don't think we want to ReportBadMessage in th
1620 binding_.Close();
1621 return;
1622 }
1623
1624 if (frame_index >= 0 &&
1625 !webvr_frame_oustanding_[frame_index % kPoseRingBufferSize]) {
1626 mojo::ReportBadMessage("UpdateLayerBounds called with invalid frame_index");
1627 binding_.Close();
1628 return;
1629 }
1630
1582 if (frame_index < 0) { 1631 if (frame_index < 0) {
1583 webvr_left_viewport_->SetSourceUv(UVFromGfxRect(left_bounds)); 1632 webvr_left_viewport_->SetSourceUv(UVFromGfxRect(left_bounds));
1584 webvr_right_viewport_->SetSourceUv(UVFromGfxRect(right_bounds)); 1633 webvr_right_viewport_->SetSourceUv(UVFromGfxRect(right_bounds));
1585 CreateOrResizeWebVRSurface(source_size); 1634 CreateOrResizeWebVRSurface(source_size);
1586 } else { 1635 } else {
1587 pending_bounds_.emplace( 1636 pending_bounds_.emplace(
1588 frame_index, WebVrBounds(left_bounds, right_bounds, source_size)); 1637 frame_index, WebVrBounds(left_bounds, right_bounds, source_size));
1589 } 1638 }
1590 } 1639 }
1591 1640
(...skipping 20 matching lines...) Expand all
1612 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index); 1661 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index);
1613 1662
1614 int64_t prediction_nanos = GetPredictedFrameTimeNanos(); 1663 int64_t prediction_nanos = GetPredictedFrameTimeNanos();
1615 1664
1616 gfx::Transform head_mat; 1665 gfx::Transform head_mat;
1617 device::mojom::VRPosePtr pose = 1666 device::mojom::VRPosePtr pose =
1618 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat, 1667 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat,
1619 prediction_nanos); 1668 prediction_nanos);
1620 1669
1621 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; 1670 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat;
1671 webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = true;
1622 webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now(); 1672 webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now();
1623 1673
1624 std::move(callback).Run( 1674 std::move(callback).Run(
1625 std::move(pose), time, frame_index, 1675 std::move(pose), time, frame_index,
1626 device::mojom::VRPresentationProvider::VSyncStatus::SUCCESS); 1676 device::mojom::VRPresentationProvider::VSyncStatus::SUCCESS);
1627 } 1677 }
1628 1678
1629 void VrShellGl::CreateVRDisplayInfo( 1679 void VrShellGl::CreateVRDisplayInfo(
1630 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, 1680 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback,
1631 uint32_t device_id) { 1681 uint32_t device_id) {
1632 // This assumes that the initial webvr_surface_size_ was set to the 1682 // This assumes that the initial webvr_surface_size_ was set to the
1633 // appropriate recommended render resolution as the default size during 1683 // appropriate recommended render resolution as the default size during
1634 // InitializeGl. Revisit if the initialization order changes. 1684 // InitializeGl. Revisit if the initialization order changes.
1635 device::mojom::VRDisplayInfoPtr info = 1685 device::mojom::VRDisplayInfoPtr info =
1636 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(), 1686 device::GvrDelegate::CreateVRDisplayInfo(gvr_api_.get(),
1637 webvr_surface_size_, device_id); 1687 webvr_surface_size_, device_id);
1638 browser_->RunVRDisplayInfoCallback(callback, &info); 1688 browser_->RunVRDisplayInfoCallback(callback, &info);
1639 } 1689 }
1640 1690
1641 } // namespace vr_shell 1691 } // namespace vr_shell
OLDNEW
« no previous file with comments | « chrome/browser/android/vr_shell/vr_shell_gl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698