Issue metadata
Sign in to add a comment
|
Security: Possible double-reads in GPU command buffer code. |
||||||||||||||||||||||
Issue description
This template is ONLY for reporting security bugs. If you are reporting a
Download Protection Bypass bug, please use the "Security - Download
Protection" template. For all other reports, please use a different
template.
Please see the following link for instructions on filing security bugs:
http://www.chromium.org/Home/chromium-security/reporting-security-bugs
VULNERABILITY DETAILS
Several instances of potential double-reads in the GPU command buffer service code. For the builds that I have checked, it seems that the compiler generates safe code (linux x64, chromeos ARM, windows x86), to various degrees - the windows code is the closest to being vulnerable, probably due to limited registers on x86; the windows build does have double-reads in most of these places, but missing the most interesting double-read on args.data_memory_size in HandleGetBucketStart, probably due to the ordering of the || statement. Most of the other issues require the unsafe_es3_apis_enabled flag, so don't affect default configuration.
I'm not 100% sure that the compiler is anyway required to generate safe code for any of the GPU command buffer handler functions even with the use of local variables; I'm not a compiler expert, but I suspect that the command structures should be declared volatile const & before reading struct members into locals, or explicitly memcpy'd out of shared memory into local copies, so that the compiler knows that it is not ok to assume it can just read the unchanged values back out of the shared memory page.
Reporting without applying deadline since these all appear to be "safe" in the official chrome production builds that I have checked, but with security flag since this may not be true for all chromium builds, especially if someone is still releasing a 32-bit linux chromium build...
--------------------------------------------------------------------------------
error::Error CommonDecoder::HandleGetBucketStart(uint32_t immediate_data_size,
const void* cmd_data) {
const cmd::GetBucketStart& args =
*static_cast<const cmd::GetBucketStart*>(cmd_data);
uint32_t bucket_id = args.bucket_id;
uint32_t* result = GetSharedMemoryAs<uint32_t*>(
args.result_memory_id, args.result_memory_offset, sizeof(*result));
int32_t data_memory_id = args.data_memory_id;
uint32_t data_memory_offset = args.data_memory_offset;
uint32_t data_memory_size = args.data_memory_size;
uint8_t* data = NULL;
if (data_memory_size != 0 || data_memory_id != 0 || data_memory_offset != 0) {
data = GetSharedMemoryAs<uint8_t*>(
args.data_memory_id, args.data_memory_offset, args.data_memory_size); // <---- double-read on args.data_memory_id, args.data_memory_offset and args.data_memory_size
if (!data) {
return error::kInvalidArguments;
}
}
if (!result) {
return error::kInvalidArguments;
}
// Check that the client initialized the result.
if (*result != 0) {
return error::kInvalidArguments;
}
Bucket* bucket = GetBucket(bucket_id);
if (!bucket) {
return error::kInvalidArguments;
}
uint32_t bucket_size = bucket->size();
*result = bucket_size;
if (data) {
uint32_t size = std::min(data_memory_size, bucket_size);
memcpy(data, bucket->GetData(0, size), size); // <---- size could be out of sync here if args.data_memory_size is reduced in between the two reads
}
return error::kNoError;
}
--------------------------------------------------------------------------------
error::Error GLES2DecoderImpl::HandleVertexAttribIPointer(
uint32_t immediate_data_size,
const void* cmd_data) {
if (!unsafe_es3_apis_enabled())
return error::kUnknownCommand;
const gles2::cmds::VertexAttribIPointer& c =
*static_cast<const gles2::cmds::VertexAttribIPointer*>(cmd_data);
if (!state_.bound_array_buffer.get() ||
state_.bound_array_buffer->IsDeleted()) {
if (state_.vertex_attrib_manager.get() ==
state_.default_vertex_attrib_manager.get()) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION,
"glVertexAttribIPointer", "no array buffer bound");
return error::kNoError;
} else if (c.offset != 0) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION,
"glVertexAttribIPointer", "client side arrays are not allowed");
return error::kNoError;
}
}
GLuint indx = c.indx;
GLint size = c.size;
GLenum type = c.type;
GLsizei stride = c.stride;
GLsizei offset = c.offset; // <---- possible double-read
--------------------------------------------------------------------------------
error::Error GLES2DecoderImpl::HandleVertexAttribPointer(
uint32_t immediate_data_size,
const void* cmd_data) {
const gles2::cmds::VertexAttribPointer& c =
*static_cast<const gles2::cmds::VertexAttribPointer*>(cmd_data);
if (!state_.bound_array_buffer.get() ||
state_.bound_array_buffer->IsDeleted()) {
if (state_.vertex_attrib_manager.get() ==
state_.default_vertex_attrib_manager.get()) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION,
"glVertexAttribPointer", "no array buffer bound");
return error::kNoError;
} else if (c.offset != 0) {
LOCAL_SET_GL_ERROR(
GL_INVALID_OPERATION,
"glVertexAttribPointer", "client side arrays are not allowed");
return error::kNoError;
}
}
GLuint indx = c.indx;
GLint size = c.size;
GLenum type = c.type;
GLboolean normalized = static_cast<GLboolean>(c.normalized);
GLsizei stride = c.stride;
GLsizei offset = c.offset; // <---- possible double-read
error::Error GLES2DecoderImpl::HandleWaitSyncTokenCHROMIUM(
uint32_t immediate_data_size,
const void* cmd_data) {
const gles2::cmds::WaitSyncTokenCHROMIUM& c =
*static_cast<const gles2::cmds::WaitSyncTokenCHROMIUM*>(cmd_data);
const gpu::CommandBufferNamespace kMinNamespaceId =
gpu::CommandBufferNamespace::INVALID;
const gpu::CommandBufferNamespace kMaxNamespaceId =
gpu::CommandBufferNamespace::NUM_COMMAND_BUFFER_NAMESPACES;
const gpu::CommandBufferNamespace namespace_id =
((c.namespace_id >= static_cast<int32_t>(kMinNamespaceId)) &&
(c.namespace_id < static_cast<int32_t>(kMaxNamespaceId))) // <---- possible double-read
? static_cast<gpu::CommandBufferNamespace>(c.namespace_id) // <---- possible double-read
: gpu::CommandBufferNamespace::INVALID;
error::Error GLES2DecoderImpl::HandleMapBufferRange(
uint32_t immediate_data_size, const void* cmd_data) {
if (!unsafe_es3_apis_enabled()) {
return error::kUnknownCommand;
}
const gles2::cmds::MapBufferRange& c =
*static_cast<const gles2::cmds::MapBufferRange*>(cmd_data);
GLenum target = static_cast<GLenum>(c.target);
GLbitfield access = static_cast<GLbitfield>(c.access);
GLintptr offset = static_cast<GLintptr>(c.offset);
GLsizeiptr size = static_cast<GLsizeiptr>(c.size);
typedef cmds::MapBufferRange::Result Result;
Result* result = GetSharedMemoryAs<Result*>(
c.result_shm_id, c.result_shm_offset, sizeof(*result));
if (!result) {
return error::kOutOfBounds;
}
if (*result != 0) {
*result = 0;
return error::kInvalidArguments;
}
int8_t* mem =
GetSharedMemoryAs<int8_t*>(c.data_shm_id, c.data_shm_offset, size);
if (!mem) {
return error::kOutOfBounds;
}
GLbitfield mask = GL_MAP_INVALIDATE_BUFFER_BIT;
if ((access & mask) == mask) {
// TODO(zmo): To be on the safe side, always map
// GL_MAP_INVALIDATE_BUFFER_BIT to GL_MAP_INVALIDATE_RANGE_BIT.
access = (access & ~GL_MAP_INVALIDATE_BUFFER_BIT);
access = (access | GL_MAP_INVALIDATE_RANGE_BIT);
}
// TODO(zmo): Always filter out GL_MAP_UNSYNCHRONIZED_BIT to get rid of
// undefined behaviors.
mask = GL_MAP_READ_BIT | GL_MAP_UNSYNCHRONIZED_BIT;
if ((access & mask) == mask) {
LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "MapBufferRange",
"incompatible access bits");
return error::kNoError;
}
access = (access & ~GL_MAP_UNSYNCHRONIZED_BIT);
if ((access & GL_MAP_WRITE_BIT) == GL_MAP_WRITE_BIT &&
(access & GL_MAP_INVALIDATE_RANGE_BIT) == 0) {
access = (access | GL_MAP_READ_BIT);
}
void* ptr = glMapBufferRange(target, offset, size, access);
if (ptr == nullptr) {
return error::kNoError;
}
Buffer* buffer = buffer_manager()->GetBufferInfoForTarget(&state_, target);
DCHECK(buffer);
buffer->SetMappedRange(offset, size, access, ptr,
GetSharedMemoryBuffer(c.data_shm_id)); // <---- possible double-read
VERSION
Chrome Version: latest
Operating System: [Please indicate OS, version, and service pack level]
REPRODUCTION CASE
Please include a demonstration of the security bug, such as an attached
HTML or binary file that reproduces the bug when loaded in Chrome. PLEASE
make the file as small as possible and remove any content not required to
demonstrate the bug.
FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION
Type of crash: [tab, browser, etc.]
Crash State: [see link above: stack trace, registers, exception record]
Client ID (if relevant): [see link above]
,
Mar 24 2016
These are great finds. Yes agreed about volatile, also mentioned in https://bugs.chromium.org/p/chromium/issues/detail?id=597625
,
Mar 24 2016
Should I land a oneliner for this issue (together with the ones from 597625)?
I hacked on the autogenerator for a bit but ended up noticing that the fixed size arrays ('PUT' handler type) are mostly benign, with the exception of Tex/SamplerParameter maybe (where what we told the driver could then mismatch our tracking).
So maybe that makes more sense to combine with a bigger change in the script that deals with Gen/Delete.
,
Mar 24 2016
> Should I land a oneliner for this issue (together with the ones from 597625)? wrong bug: 597625 is the other bug.
,
Mar 25 2016
,
Mar 25 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/ff5407f8d6d71116e01d6ea18db75a4f8d1e0692 commit ff5407f8d6d71116e01d6ea18db75a4f8d1e0692 Author: sievers <sievers@chromium.org> Date: Fri Mar 25 22:07:52 2016 gpu: Pull some variables onto the stack in the decoder CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel BUG= 597636 , 597625 Review URL: https://codereview.chromium.org/1836603002 Cr-Commit-Position: refs/heads/master@{#383379} [modify] https://crrev.com/ff5407f8d6d71116e01d6ea18db75a4f8d1e0692/gpu/command_buffer/service/common_decoder.cc [modify] https://crrev.com/ff5407f8d6d71116e01d6ea18db75a4f8d1e0692/gpu/command_buffer/service/gles2_cmd_decoder.cc
,
Mar 26 2016
Please mark security bugs as fixed as soon as the fix lands, and before requesting merges. - Your friendly ClusterFuzz
,
Mar 26 2016
,
Mar 26 2016
Your change meets the bar and is auto-approved for M50 (branch: 2661)
,
Mar 28 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/1feead4b00c2c275af33c7b9d161c92647f7e4ab commit 1feead4b00c2c275af33c7b9d161c92647f7e4ab Author: sievers <sievers@chromium.org> Date: Mon Mar 28 19:32:16 2016 gpu: Fix glitch with https://codereview.chromium.org/1836603002/ BUG= 597636 , 597625 CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel;tryserver.chromium.mac:mac_optional_gpu_tests_rel NOTRY=True Review URL: https://codereview.chromium.org/1835333002 Cr-Commit-Position: refs/heads/master@{#383539} [modify] https://crrev.com/1feead4b00c2c275af33c7b9d161c92647f7e4ab/gpu/command_buffer/service/gles2_cmd_decoder.cc
,
Mar 31 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/fa022ffa4d5e7006d6bf9e59c8496118c08b084a commit fa022ffa4d5e7006d6bf9e59c8496118c08b084a Author: Daniel Sievers <sievers@chromium.org> Date: Thu Mar 31 18:46:50 2016 gpu: Pull some variables onto the stack in the decoder CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel BUG= 597636 , 597625 Review URL: https://codereview.chromium.org/1836603002 Cr-Commit-Position: refs/heads/master@{#383379} (cherry picked from commit ff5407f8d6d71116e01d6ea18db75a4f8d1e0692) Review URL: https://codereview.chromium.org/1843663007 . Cr-Commit-Position: refs/branch-heads/2661@{#449} Cr-Branched-From: ef6f6ae5e4c96622286b563658d5cd62a6cf1197-refs/heads/master@{#378081} [modify] https://crrev.com/fa022ffa4d5e7006d6bf9e59c8496118c08b084a/gpu/command_buffer/service/common_decoder.cc [modify] https://crrev.com/fa022ffa4d5e7006d6bf9e59c8496118c08b084a/gpu/command_buffer/service/gles2_cmd_decoder.cc
,
Mar 31 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/770a1a07c0b04c1a40df1384fff41d227b38b7ae commit 770a1a07c0b04c1a40df1384fff41d227b38b7ae Author: Daniel Sievers <sievers@chromium.org> Date: Thu Mar 31 18:51:35 2016 gpu: Fix glitch with https://codereview.chromium.org/1836603002/ BUG= 597636 , 597625 CQ_INCLUDE_TRYBOTS=tryserver.chromium.win:win_optional_gpu_tests_rel;tryserver.chromium.mac:mac_optional_gpu_tests_rel NOTRY=True Review URL: https://codereview.chromium.org/1835333002 Cr-Commit-Position: refs/heads/master@{#383539} (cherry picked from commit 1feead4b00c2c275af33c7b9d161c92647f7e4ab) Review URL: https://codereview.chromium.org/1845273003 . Cr-Commit-Position: refs/branch-heads/2661@{#450} Cr-Branched-From: ef6f6ae5e4c96622286b563658d5cd62a6cf1197-refs/heads/master@{#378081} [modify] https://crrev.com/770a1a07c0b04c1a40df1384fff41d227b38b7ae/gpu/command_buffer/service/gles2_cmd_decoder.cc
,
May 16 2016
,
Jul 2 2016
This bug has been closed for more than 14 weeks. Removing security view restrictions. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Aug 24 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/a17d2bcbccfda0480ed429897f243ca908dd6c15 commit a17d2bcbccfda0480ed429897f243ca908dd6c15 Author: piman <piman@chromium.org> Date: Wed Aug 24 03:05:29 2016 Command buffers: ensure we only read immediate data once Fizes various issues where we may be reading some immediate data twice: - Gen*, Delete* - InvalidateFramebuffer and friends - DrawBuffersEXT - Some Uniform* and VertexAttrib* - Mailbox functions BUG= 597625 , 597636 CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel Review-Url: https://codereview.chromium.org/2264253003 Cr-Commit-Position: refs/heads/master@{#413962} [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/build_gles2_cmd_buffer.py [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/context_group.cc [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder.cc [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc [modify] https://crrev.com/a17d2bcbccfda0480ed429897f243ca908dd6c15/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc
,
Sep 6 2016
The following revision refers to this bug: https://chromium.googlesource.com/chromium/src.git/+/a728ad1c1b56c5c81c516ad11fead19e569b046e commit a728ad1c1b56c5c81c516ad11fead19e569b046e Author: piman <piman@chromium.org> Date: Tue Sep 06 16:48:08 2016 Make command buffer commands and immediate data volatile Because command buffer commands and immediate data live in shared memory that can be modified by an untrusted process, the data must be tagged as volatile to ensure that compiler does not optimize the service-side checks in a way that could cause double reads / TOCTOU issues. Additionally, this provides a good indication that pointers reference attacker-controlled memory. BUG= 597625 , 597636 CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel Review-Url: https://codereview.chromium.org/2275203002 Cr-Commit-Position: refs/heads/master@{#416646} [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/build_gles2_cmd_buffer.py [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/client/ring_buffer_test.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/common/cmd_buffer_common.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/common/gles2_cmd_format_autogen.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/common/gles2_cmd_utils.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/common/mailbox.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/cmd_parser.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/cmd_parser.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/common_decoder.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/common_decoder.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/common_decoder_unittest.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_mock.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/mocks.cc [modify] https://crrev.com/a728ad1c1b56c5c81c516ad11fead19e569b046e/gpu/command_buffer/service/mocks.h
,
Oct 1 2016
This bug has been closed for more than 14 weeks. Removing security view restrictions. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Oct 2 2016
This bug has been closed for more than 14 weeks. Removing security view restrictions. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Oct 2 2016
,
Jul 28
|
|||||||||||||||||||||||
►
Sign in to add a comment |
|||||||||||||||||||||||
Comment 1 by wfh@chromium.org
, Mar 24 2016Components: Internals>GPU>Internals Internals>GPU
Labels: Security_Severity-Low Security_Impact-Stable
Owner: siev...@chromium.org
Status: Assigned (was: Unconfirmed)