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

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: add test and rebase Created 3 years, 5 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
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 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 const gpu::MailboxHolder& mailbox) { 349 const gpu::MailboxHolder& mailbox) {
350 TRACE_EVENT0("gpu", "VrShellGl::SubmitWebVRFrame"); 350 TRACE_EVENT0("gpu", "VrShellGl::SubmitWebVRFrame");
351 351
352 // submit_client_ could be null when we exit presentation, if there were 352 // submit_client_ could be null when we exit presentation, if there were
353 // pending SubmitFrame messages queued. VRDisplayClient::OnExitPresent 353 // pending SubmitFrame messages queued. VRDisplayClient::OnExitPresent
354 // will clean up state in blink, so it doesn't wait for 354 // will clean up state in blink, so it doesn't wait for
355 // OnSubmitFrameTransferred or OnSubmitFrameRendered. 355 // OnSubmitFrameTransferred or OnSubmitFrameRendered.
356 if (!submit_client_.get()) 356 if (!submit_client_.get())
357 return; 357 return;
358 358
359 if (frame_index < 0 ||
360 !webvr_frame_oustanding_[frame_index % kPoseRingBufferSize]) {
361 mojo::ReportBadMessage("SubmitFrame called with an invalid frame_index");
362 binding_.Close();
363 return;
364 }
365
359 webvr_time_js_submit_[frame_index % kPoseRingBufferSize] = 366 webvr_time_js_submit_[frame_index % kPoseRingBufferSize] =
360 base::TimeTicks::Now(); 367 base::TimeTicks::Now();
361 368
362 // Swapping twice on a Surface without calling updateTexImage in 369 // Swapping twice on a Surface without calling updateTexImage in
363 // between can lose frames, so don't draw+swap if we already have 370 // between can lose frames, so don't draw+swap if we already have
364 // a pending frame we haven't consumed yet. 371 // a pending frame we haven't consumed yet.
365 bool swapped = false; 372 bool swapped = false;
366 if (pending_frames_.empty()) { 373 if (pending_frames_.empty()) {
367 swapped = mailbox_bridge_->CopyMailboxToSurfaceAndSwap(mailbox); 374 swapped = mailbox_bridge_->CopyMailboxToSurfaceAndSwap(mailbox);
368 if (swapped) { 375 if (swapped) {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 browser_->ToggleCardboardGamepad(true); 432 browser_->ToggleCardboardGamepad(true);
426 } 433 }
427 } 434 }
428 435
429 void VrShellGl::InitializeRenderer() { 436 void VrShellGl::InitializeRenderer() {
430 gvr_api_->InitializeGl(); 437 gvr_api_->InitializeGl();
431 gfx::Transform head_pose; 438 gfx::Transform head_pose;
432 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); 439 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose);
433 webvr_head_pose_.assign(kPoseRingBufferSize, head_pose); 440 webvr_head_pose_.assign(kPoseRingBufferSize, head_pose);
434 webvr_time_pose_.assign(kPoseRingBufferSize, base::TimeTicks()); 441 webvr_time_pose_.assign(kPoseRingBufferSize, base::TimeTicks());
442 webvr_frame_oustanding_.assign(kPoseRingBufferSize, false);
435 webvr_time_js_submit_.assign(kPoseRingBufferSize, base::TimeTicks()); 443 webvr_time_js_submit_.assign(kPoseRingBufferSize, base::TimeTicks());
436 444
437 std::vector<gvr::BufferSpec> specs; 445 std::vector<gvr::BufferSpec> specs;
438 // For kFramePrimaryBuffer (primary VrShell and WebVR content) 446 // For kFramePrimaryBuffer (primary VrShell and WebVR content)
439 specs.push_back(gvr_api_->CreateBufferSpec()); 447 specs.push_back(gvr_api_->CreateBufferSpec());
440 gvr::Sizei render_size_primary = specs[kFramePrimaryBuffer].GetSize(); 448 gvr::Sizei render_size_primary = specs[kFramePrimaryBuffer].GetSize();
441 render_size_primary_ = {render_size_primary.width, 449 render_size_primary_ = {render_size_primary.width,
442 render_size_primary.height}; 450 render_size_primary.height};
443 render_size_vrshell_ = render_size_primary_; 451 render_size_vrshell_ = render_size_primary_;
444 452
(...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after
830 838
831 // When using async reprojection, we need to know which pose was 839 // When using async reprojection, we need to know which pose was
832 // used in the WebVR app for drawing this frame and supply it when 840 // used in the WebVR app for drawing this frame and supply it when
833 // submitting. Technically we don't need a pose if not reprojecting, 841 // submitting. Technically we don't need a pose if not reprojecting,
834 // but keeping it uninitialized seems likely to cause problems down 842 // but keeping it uninitialized seems likely to cause problems down
835 // the road. Copying it is cheaper than fetching a new one. 843 // the road. Copying it is cheaper than fetching a new one.
836 if (ShouldDrawWebVr()) { 844 if (ShouldDrawWebVr()) {
837 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), 845 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize),
838 "kPoseRingBufferSize must be a power of 2"); 846 "kPoseRingBufferSize must be a power of 2");
839 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; 847 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize];
848 webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = false;
840 } else { 849 } else {
841 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose); 850 device::GvrDelegate::GetGvrPoseWithNeckModel(gvr_api_.get(), &head_pose);
842 } 851 }
843 852
844 // Update the render position of all UI elements (including desktop). 853 // Update the render position of all UI elements (including desktop).
845 scene_->OnBeginFrame(current_time); 854 scene_->OnBeginFrame(current_time);
846 855
847 { 856 {
848 // TODO(crbug.com/704690): Acquire controller state in a way that's timely 857 // TODO(crbug.com/704690): Acquire controller state in a way that's timely
849 // for both the gamepad API and UI input handling. 858 // for both the gamepad API and UI input handling.
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after
1346 if (needs_init) { 1355 if (needs_init) {
1347 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); 1356 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this)));
1348 OnVSync(); 1357 OnVSync();
1349 } 1358 }
1350 } 1359 }
1351 1360
1352 void VrShellGl::ForceExitVr() { 1361 void VrShellGl::ForceExitVr() {
1353 browser_->ForceExitVr(); 1362 browser_->ForceExitVr();
1354 } 1363 }
1355 1364
1365 namespace {
1366 bool ValidateRect(const gfx::RectF& bounds) {
1367 // Bounds should be between 0 and 1, with positive width/height.
1368 // We simply clamp to [0,1], but still validate that the bounds are not NAN.
1369 return !std::isnan(bounds.width()) && !std::isnan(bounds.height()) &&
1370 !std::isnan(bounds.x()) && !std::isnan(bounds.y());
1371 }
1372
1373 gfx::RectF ClampRect(gfx::RectF bounds) {
1374 bounds.AdjustToFit(gfx::RectF(0, 0, 1, 1));
1375 return bounds;
1376 }
1377
1378 } // namespace
1379
1356 void VrShellGl::UpdateLayerBounds(int16_t frame_index, 1380 void VrShellGl::UpdateLayerBounds(int16_t frame_index,
1357 const gfx::RectF& left_bounds, 1381 const gfx::RectF& left_bounds,
1358 const gfx::RectF& right_bounds, 1382 const gfx::RectF& right_bounds,
1359 const gfx::Size& source_size) { 1383 const gfx::Size& source_size) {
1384 if (!ValidateRect(left_bounds) || !ValidateRect(right_bounds)) {
1385 mojo::ReportBadMessage("UpdateLayerBounds called with invalid bounds");
1386 binding_.Close();
1387 return;
1388 }
1389
1390 if (frame_index >= 0 &&
1391 !webvr_frame_oustanding_[frame_index % kPoseRingBufferSize]) {
1392 mojo::ReportBadMessage("UpdateLayerBounds called with invalid frame_index");
1393 binding_.Close();
1394 return;
1395 }
1396
1360 if (frame_index < 0) { 1397 if (frame_index < 0) {
1361 webvr_left_viewport_->SetSourceUv(UVFromGfxRect(left_bounds)); 1398 webvr_left_viewport_->SetSourceUv(UVFromGfxRect(ClampRect(left_bounds)));
1362 webvr_right_viewport_->SetSourceUv(UVFromGfxRect(right_bounds)); 1399 webvr_right_viewport_->SetSourceUv(UVFromGfxRect(ClampRect(right_bounds)));
1363 CreateOrResizeWebVRSurface(source_size); 1400 CreateOrResizeWebVRSurface(source_size);
1401
1402 // clear all pending bounds
1403 pending_bounds_ = std::queue<std::pair<uint8_t, WebVrBounds>>();
1364 } else { 1404 } else {
1365 pending_bounds_.emplace( 1405 pending_bounds_.emplace(
1366 frame_index, WebVrBounds(left_bounds, right_bounds, source_size)); 1406 frame_index, WebVrBounds(left_bounds, right_bounds, source_size));
1367 } 1407 }
1368 } 1408 }
1369 1409
1370 int64_t VrShellGl::GetPredictedFrameTimeNanos() { 1410 int64_t VrShellGl::GetPredictedFrameTimeNanos() {
1371 int64_t frame_time_micros = vsync_interval_.InMicroseconds(); 1411 int64_t frame_time_micros = vsync_interval_.InMicroseconds();
1372 // If we aim to submit at vsync, that frame will start scanning out 1412 // If we aim to submit at vsync, that frame will start scanning out
1373 // one vsync later. Add a half frame to split the difference between 1413 // one vsync later. Add a half frame to split the difference between
(...skipping 16 matching lines...) Expand all
1390 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index); 1430 TRACE_EVENT1("input", "VrShellGl::SendVSync", "frame", frame_index);
1391 1431
1392 int64_t prediction_nanos = GetPredictedFrameTimeNanos(); 1432 int64_t prediction_nanos = GetPredictedFrameTimeNanos();
1393 1433
1394 gfx::Transform head_mat; 1434 gfx::Transform head_mat;
1395 device::mojom::VRPosePtr pose = 1435 device::mojom::VRPosePtr pose =
1396 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat, 1436 device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat,
1397 prediction_nanos); 1437 prediction_nanos);
1398 1438
1399 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; 1439 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat;
1440 webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = true;
1400 webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now(); 1441 webvr_time_pose_[frame_index % kPoseRingBufferSize] = base::TimeTicks::Now();
1401 1442
1402 std::move(callback).Run( 1443 std::move(callback).Run(
1403 std::move(pose), time, frame_index, 1444 std::move(pose), time, frame_index,
1404 device::mojom::VRPresentationProvider::VSyncStatus::SUCCESS); 1445 device::mojom::VRPresentationProvider::VSyncStatus::SUCCESS);
1405 } 1446 }
1406 1447
1407 void VrShellGl::CreateVRDisplayInfo( 1448 void VrShellGl::CreateVRDisplayInfo(
1408 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, 1449 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback,
1409 uint32_t device_id) { 1450 uint32_t device_id) {
(...skipping 13 matching lines...) Expand all
1423 // pending callbacks, so instead of providing a VSync, tell the requester 1464 // pending callbacks, so instead of providing a VSync, tell the requester
1424 // the connection is closing. 1465 // the connection is closing.
1425 base::ResetAndReturn(&callback_) 1466 base::ResetAndReturn(&callback_)
1426 .Run(nullptr, base::TimeDelta(), -1, 1467 .Run(nullptr, base::TimeDelta(), -1,
1427 device::mojom::VRPresentationProvider::VSyncStatus::CLOSING); 1468 device::mojom::VRPresentationProvider::VSyncStatus::CLOSING);
1428 } 1469 }
1429 binding_.Close(); 1470 binding_.Close();
1430 } 1471 }
1431 1472
1432 } // namespace vr_shell 1473 } // namespace vr_shell
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698