diff options
author | Michael BrĂ¼ning <michael.bruning@qt.io> | 2019-03-22 11:33:47 +0100 |
---|---|---|
committer | Michael BrĂ¼ning <michael.bruning@qt.io> | 2019-03-27 16:13:13 +0000 |
commit | ec503eae3ed49c7f87b01b723c706b2783037a73 (patch) | |
tree | b33e0d148157763ccc111349f280c1f1e8a80a72 | |
parent | f2dfd87785ada8c5fe579886481cc41be6c36b05 (diff) | |
download | qtwebengine-chromium-ec503eae3ed49c7f87b01b723c706b2783037a73.tar.gz |
[Backport] Security bug 905509 (8/13)
Backport of original patch by: Antoine Labour <piman@chromium.org>:
Audit use of size_t in GLES2Implementation and ProgramInfoManager
- use uint32_t where appropriate.
- refactor logic around GetActiveAttrib / GetActiveUniform /
GetActiveUniformBlockName / GetTransformFeedbackVarying to avoid
underflow.
Bug: 905509
Change-Id: Ic173134db48bf667152cbfb7449fda10f98af813
Reviewed-on: https://chromium-review.googlesource.com/c/1401459
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
5 files changed, 104 insertions, 167 deletions
diff --git a/chromium/gpu/command_buffer/client/gles2_implementation.cc b/chromium/gpu/command_buffer/client/gles2_implementation.cc index b1c20ac07fc..511e087d5da 100644 --- a/chromium/gpu/command_buffer/client/gles2_implementation.cc +++ b/chromium/gpu/command_buffer/client/gles2_implementation.cc @@ -3225,6 +3225,28 @@ void GLES2Implementation::TexSubImage3DImpl(GLenum target, } } +void GLES2Implementation::GetResultNameHelper(GLsizei bufsize, + GLsizei* length, + char* name) { + // Length of string (without final \0) that we will write to the buffer. + GLsizei max_length = 0; + if (name && (bufsize > 0)) { + std::vector<int8_t> str; + GetBucketContents(kResultBucketId, &str); + if (!str.empty()) { + DCHECK_LE(str.size(), static_cast<size_t>(INT_MAX)); + // Note: both bufsize and str.size() count/include the terminating \0. + max_length = std::min(bufsize, static_cast<GLsizei>(str.size())) - 1; + } + memcpy(name, str.data(), max_length); + name[max_length] = '\0'; + } + if (length) { + *length = max_length; + } +} + + bool GLES2Implementation::GetActiveAttribHelper( GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) { @@ -3248,21 +3270,8 @@ bool GLES2Implementation::GetActiveAttribHelper( if (type) { *type = result->type; } - if (length || name) { - std::vector<int8_t> str; - // Note: this can invalidate |result|. - GetBucketContents(kResultBucketId, &str); - GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1, - std::max(static_cast<size_t>(0), - str.size() - 1)); - if (length) { - *length = max_size; - } - if (name && bufsize > 0) { - memcpy(name, &str[0], max_size); - name[max_size] = '\0'; - } - } + // Note: this can invalidate |result|. + GetResultNameHelper(bufsize, length, name); } return success; } @@ -3313,29 +3322,18 @@ bool GLES2Implementation::GetActiveUniformHelper( helper_->GetActiveUniform(program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset()); WaitForCmd(); - if (result->success) { + bool success = !!result->success; + if (success) { if (size) { *size = result->size; } if (type) { *type = result->type; } - if (length || name) { - std::vector<int8_t> str; - GetBucketContents(kResultBucketId, &str); - GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1, - std::max(static_cast<size_t>(0), - str.size() - 1)); - if (length) { - *length = max_size; - } - if (name && bufsize > 0) { - memcpy(name, &str[0], max_size); - name[max_size] = '\0'; - } - } + // Note: this can invalidate |result|. + GetResultNameHelper(bufsize, length, name); } - return result->success != 0; + return success; } void GLES2Implementation::GetActiveUniform( @@ -3385,27 +3383,12 @@ bool GLES2Implementation::GetActiveUniformBlockNameHelper( helper_->GetActiveUniformBlockName(program, index, kResultBucketId, GetResultShmId(), GetResultShmOffset()); WaitForCmd(); - if (*result) { - if (bufsize == 0) { - if (length) { - *length = 0; - } - } else if (length || name) { - std::vector<int8_t> str; - GetBucketContents(kResultBucketId, &str); - DCHECK_GT(str.size(), 0u); - GLsizei max_size = - std::min(bufsize, static_cast<GLsizei>(str.size())) - 1; - if (length) { - *length = max_size; - } - if (name) { - memcpy(name, &str[0], max_size); - name[max_size] = '\0'; - } - } + bool success = !!result; + if (success) { + // Note: this can invalidate |result|. + GetResultNameHelper(bufsize, length, name); } - return *result != 0; + return success; } void GLES2Implementation::GetActiveUniformBlockName( @@ -3720,25 +3703,8 @@ bool GLES2Implementation::GetTransformFeedbackVaryingHelper( if (type) { *type = result->type; } - if (length || name) { - std::vector<int8_t> str; - GetBucketContents(kResultBucketId, &str); - GLsizei max_size = std::min(bufsize, static_cast<GLsizei>(str.size())); - if (max_size > 0) { - --max_size; - } - if (length) { - *length = max_size; - } - if (name) { - if (max_size > 0) { - memcpy(name, &str[0], max_size); - name[max_size] = '\0'; - } else if (bufsize > 0) { - name[0] = '\0'; - } - } - } + // Note: this can invalidate |result|. + GetResultNameHelper(bufsize, length, name); } return result->success != 0; } @@ -4827,7 +4793,7 @@ void GLES2Implementation::ScheduleCALayerSharedStateCHROMIUM( const GLfloat* clip_rect, GLint sorting_context_id, const GLfloat* transform) { - size_t shm_size = 20 * sizeof(GLfloat); + uint32_t shm_size = 20 * sizeof(GLfloat); ScopedTransferBufferPtr buffer(shm_size, helper_, transfer_buffer_); if (!buffer.valid() || buffer.size() < shm_size) { SetGLError(GL_OUT_OF_MEMORY, "GLES2::ScheduleCALayerSharedStateCHROMIUM", @@ -4848,7 +4814,7 @@ void GLES2Implementation::ScheduleCALayerCHROMIUM(GLuint contents_texture_id, GLuint edge_aa_mask, const GLfloat* bounds_rect, GLuint filter) { - size_t shm_size = 8 * sizeof(GLfloat); + uint32_t shm_size = 8 * sizeof(GLfloat); ScopedTransferBufferPtr buffer(shm_size, helper_, transfer_buffer_); if (!buffer.valid() || buffer.size() < shm_size) { SetGLError(GL_OUT_OF_MEMORY, "GLES2::ScheduleCALayerCHROMIUM", @@ -6353,11 +6319,11 @@ bool GLES2Implementation::PackStringsToBucket(GLsizei count, base::CheckedNumeric<uint32_t> total_size = count; total_size += 1; total_size *= sizeof(GLint); - if (!total_size.IsValid()) { + uint32_t header_size = 0; + if (!total_size.AssignIfValid(&header_size)) { SetGLError(GL_INVALID_VALUE, func_name, "overflow"); return false; } - size_t header_size = total_size.ValueOrDefault(0); std::vector<GLint> header(count + 1); header[0] = static_cast<GLint>(count); for (GLsizei ii = 0; ii < count; ++ii) { @@ -6369,35 +6335,30 @@ bool GLES2Implementation::PackStringsToBucket(GLsizei count, } total_size += len; total_size += 1; // NULL at the end of each char array. - if (!total_size.IsValid()) { - SetGLError(GL_INVALID_VALUE, func_name, "overflow"); - return false; - } header[ii + 1] = len; } // Pack data into a bucket on the service. - helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0)); - size_t offset = 0; + uint32_t validated_size = 0; + if (!total_size.AssignIfValid(&validated_size)) { + SetGLError(GL_INVALID_VALUE, func_name, "overflow"); + return false; + } + helper_->SetBucketSize(kResultBucketId, validated_size); + uint32_t offset = 0; for (GLsizei ii = 0; ii <= count; ++ii) { const char* src = (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1]; - base::CheckedNumeric<size_t> checked_size = - (ii == 0) ? header_size : static_cast<size_t>(header[ii]); + uint32_t size = (ii == 0) ? header_size : header[ii]; if (ii > 0) { - checked_size += 1; // NULL in the end. - } - if (!checked_size.IsValid()) { - SetGLError(GL_INVALID_VALUE, func_name, "overflow"); - return false; + size += 1; // NULL in the end. } - size_t size = checked_size.ValueOrDefault(0); while (size) { ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); if (!buffer.valid() || buffer.size() == 0) { SetGLError(GL_OUT_OF_MEMORY, func_name, "too large"); return false; } - size_t copy_size = buffer.size(); + uint32_t copy_size = buffer.size(); if (ii > 0 && buffer.size() == size) --copy_size; if (copy_size) @@ -6702,9 +6663,9 @@ bool GLES2Implementation::PrepareInstancedPathCommand( const GLfloat* transform_values, ScopedTransferBufferPtr* buffer, uint32_t* out_paths_shm_id, - size_t* out_paths_offset, + uint32_t* out_paths_offset, uint32_t* out_transforms_shm_id, - size_t* out_transforms_offset) { + uint32_t* out_transforms_offset) { if (num_paths < 0) { SetGLError(GL_INVALID_VALUE, function_name, "numPaths < 0"); return false; @@ -6818,9 +6779,9 @@ void GLES2Implementation::StencilFillPathInstancedCHROMIUM( ScopedTransferBufferPtr buffer(helper_, transfer_buffer_); uint32_t paths_shm_id = 0; - size_t paths_offset = 0; + uint32_t paths_offset = 0; uint32_t transforms_shm_id = 0; - size_t transforms_offset = 0; + uint32_t transforms_offset = 0; if (!PrepareInstancedPathCommand( "glStencilFillPathInstancedCHROMIUM", num_paths, path_name_type, paths, transform_type, transform_values, &buffer, &paths_shm_id, @@ -6853,9 +6814,9 @@ void GLES2Implementation::StencilStrokePathInstancedCHROMIUM( ScopedTransferBufferPtr buffer(helper_, transfer_buffer_); uint32_t paths_shm_id = 0; - size_t paths_offset = 0; + uint32_t paths_offset = 0; uint32_t transforms_shm_id = 0; - size_t transforms_offset = 0; + uint32_t transforms_offset = 0; if (!PrepareInstancedPathCommand( "glStencilStrokePathInstancedCHROMIUM", num_paths, path_name_type, paths, transform_type, transform_values, &buffer, &paths_shm_id, @@ -6886,9 +6847,9 @@ void GLES2Implementation::CoverFillPathInstancedCHROMIUM( ScopedTransferBufferPtr buffer(helper_, transfer_buffer_); uint32_t paths_shm_id = 0; - size_t paths_offset = 0; + uint32_t paths_offset = 0; uint32_t transforms_shm_id = 0; - size_t transforms_offset = 0; + uint32_t transforms_offset = 0; if (!PrepareInstancedPathCommand( "glCoverFillPathInstancedCHROMIUM", num_paths, path_name_type, paths, transform_type, transform_values, &buffer, &paths_shm_id, @@ -6920,9 +6881,9 @@ void GLES2Implementation::CoverStrokePathInstancedCHROMIUM( ScopedTransferBufferPtr buffer(helper_, transfer_buffer_); uint32_t paths_shm_id = 0; - size_t paths_offset = 0; + uint32_t paths_offset = 0; uint32_t transforms_shm_id = 0; - size_t transforms_offset = 0; + uint32_t transforms_offset = 0; if (!PrepareInstancedPathCommand( "glCoverStrokePathInstancedCHROMIUM", num_paths, path_name_type, paths, transform_type, transform_values, &buffer, &paths_shm_id, @@ -6956,9 +6917,9 @@ void GLES2Implementation::StencilThenCoverFillPathInstancedCHROMIUM( ScopedTransferBufferPtr buffer(helper_, transfer_buffer_); uint32_t paths_shm_id = 0; - size_t paths_offset = 0; + uint32_t paths_offset = 0; uint32_t transforms_shm_id = 0; - size_t transforms_offset = 0; + uint32_t transforms_offset = 0; if (!PrepareInstancedPathCommand( "glStencilThenCoverFillPathInstancedCHROMIUM", num_paths, path_name_type, paths, transform_type, transform_values, &buffer, @@ -6995,9 +6956,9 @@ void GLES2Implementation::StencilThenCoverStrokePathInstancedCHROMIUM( ScopedTransferBufferPtr buffer(helper_, transfer_buffer_); uint32_t paths_shm_id = 0; - size_t paths_offset = 0; + uint32_t paths_offset = 0; uint32_t transforms_shm_id = 0; - size_t transforms_offset = 0; + uint32_t transforms_offset = 0; if (!PrepareInstancedPathCommand( "glStencilThenCoverStrokePathInstancedCHROMIUM", num_paths, path_name_type, paths, transform_type, transform_values, &buffer, diff --git a/chromium/gpu/command_buffer/client/gles2_implementation.h b/chromium/gpu/command_buffer/client/gles2_implementation.h index 6e108466561..151e1a28b1f 100644 --- a/chromium/gpu/command_buffer/client/gles2_implementation.h +++ b/chromium/gpu/command_buffer/client/gles2_implementation.h @@ -148,6 +148,12 @@ class GLES2_IMPL_EXPORT GLES2Implementation : public GLES2Interface, GLint GetUniformLocationHelper(GLuint program, const char* name); GLint GetFragDataIndexEXTHelper(GLuint program, const char* name); GLint GetFragDataLocationHelper(GLuint program, const char* name); + + // Writes the result bucket into a buffer pointed by name and of maximum size + // buffsize. If length is !null, it receives the number of characters written + // (excluding the final \0). This is a helper function for GetActive*Helper + // functions that return names. + void GetResultNameHelper(GLsizei bufsize, GLsizei* length, char* name); bool GetActiveAttribHelper( GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); @@ -602,9 +608,9 @@ class GLES2_IMPL_EXPORT GLES2Implementation : public GLES2Interface, const GLfloat* transform_values, ScopedTransferBufferPtr* buffer, uint32_t* out_paths_shm_id, - size_t* out_paths_offset, + uint32_t* out_paths_offset, uint32_t* out_transforms_shm_id, - size_t* out_transforms_offset); + uint32_t* out_transforms_offset); // Set to 1 to have the client fail when a GL error is generated. // This helps find bugs in the renderer since the debugger stops on the error. diff --git a/chromium/gpu/command_buffer/client/implementation_base.cc b/chromium/gpu/command_buffer/client/implementation_base.cc index 5714213c399..59ca1c5c92f 100644 --- a/chromium/gpu/command_buffer/client/implementation_base.cc +++ b/chromium/gpu/command_buffer/client/implementation_base.cc @@ -19,8 +19,8 @@ namespace gpu { #if !defined(_MSC_VER) -const size_t ImplementationBase::kMaxSizeOfSimpleResult; -const unsigned int ImplementationBase::kStartingOffset; +const uint32_t ImplementationBase::kMaxSizeOfSimpleResult; +const uint32_t ImplementationBase::kStartingOffset; #endif ImplementationBase::ImplementationBase(CommandBufferHelper* helper, diff --git a/chromium/gpu/command_buffer/client/implementation_base.h b/chromium/gpu/command_buffer/client/implementation_base.h index 58c33f9b4ec..71d912954f4 100644 --- a/chromium/gpu/command_buffer/client/implementation_base.h +++ b/chromium/gpu/command_buffer/client/implementation_base.h @@ -45,11 +45,11 @@ class GLES2_IMPL_EXPORT ImplementationBase public GpuControlClient { public: // The maximum result size from simple GL get commands. - static const size_t kMaxSizeOfSimpleResult = + static const uint32_t kMaxSizeOfSimpleResult = 16 * sizeof(uint32_t); // NOLINT. // used for testing only. If more things are reseved add them here. - static const unsigned int kStartingOffset = kMaxSizeOfSimpleResult; + static const uint32_t kStartingOffset = kMaxSizeOfSimpleResult; // Alignment of allocations. static const unsigned int kAlignment = 16; diff --git a/chromium/gpu/command_buffer/client/program_info_manager.cc b/chromium/gpu/command_buffer/client/program_info_manager.cc index bc15d41b10e..55d062b531a 100644 --- a/chromium/gpu/command_buffer/client/program_info_manager.cc +++ b/chromium/gpu/command_buffer/client/program_info_manager.cc @@ -13,14 +13,33 @@ template <typename T> static T LocalGetAs(const std::vector<int8_t>& data, uint32_t offset, size_t size) { - const int8_t* p = &data[0] + offset; - if (offset + size > data.size()) { - NOTREACHED(); - return NULL; - } + const int8_t* p = data.data() + offset; + DCHECK_LE(offset + size, data.size()); return static_cast<T>(static_cast<const void*>(p)); } +// Writes the strimg pointed by name and of maximum size buffsize. If length is +// !null, it receives the number of characters written (excluding the final \0). +// This is a helper function for GetActive*Helper functions that return names. +void FillNameAndLength(GLsizei bufsize, + GLsizei* length, + char* name, + const std::string& string) { + // Length of string (without final \0) that we will write to the + // buffer. + GLsizei max_length = 0; + if (name && (bufsize > 0)) { + DCHECK_LE(string.size(), static_cast<size_t>(INT_MAX)); + // Note: bufsize counts the terminating \0, but not string.size(). + max_length = std::min(bufsize - 1, static_cast<GLsizei>(string.size())); + memcpy(name, string.data(), max_length); + name[max_length] = '\0'; + } + if (length) { + *length = max_length; + } +} + } // namespace namespace gpu { @@ -809,18 +828,7 @@ bool ProgramInfoManager::GetActiveAttrib( if (type) { *type = attrib_info->type; } - if (length || name) { - GLsizei max_size = std::min( - static_cast<size_t>(bufsize) - 1, - std::max(static_cast<size_t>(0), attrib_info->name.size())); - if (length) { - *length = max_size; - } - if (name && bufsize > 0) { - memcpy(name, attrib_info->name.c_str(), max_size); - name[max_size] = '\0'; - } - } + FillNameAndLength(bufsize, length, name, attrib_info->name); return true; } } @@ -845,18 +853,7 @@ bool ProgramInfoManager::GetActiveUniform( if (type) { *type = uniform_info->type; } - if (length || name) { - GLsizei max_size = std::min( - static_cast<size_t>(bufsize) - 1, - std::max(static_cast<size_t>(0), uniform_info->name.size())); - if (length) { - *length = max_size; - } - if (name && bufsize > 0) { - memcpy(name, uniform_info->name.c_str(), max_size); - name[max_size] = '\0'; - } - } + FillNameAndLength(bufsize, length, name, uniform_info->name); return true; } } @@ -881,30 +878,13 @@ bool ProgramInfoManager::GetActiveUniformBlockName( GLES2Implementation* gl, GLuint program, GLuint index, GLsizei buf_size, GLsizei* length, char* name) { DCHECK_LE(0, buf_size); - if (!name) { - buf_size = 0; - } { base::AutoLock auto_lock(lock_); Program* info = GetProgramInfo(gl, program, kES3UniformBlocks); if (info) { const Program::UniformBlock* uniform_block = info->GetUniformBlock(index); if (uniform_block) { - if (buf_size == 0) { - if (length) { - *length = 0; - } - } else if (length || name) { - GLsizei max_size = std::min( - buf_size - 1, static_cast<GLsizei>(uniform_block->name.size())); - if (length) { - *length = max_size; - } - if (name) { - memcpy(name, uniform_block->name.data(), max_size); - name[max_size] = '\0'; - } - } + FillNameAndLength(buf_size, length, name, uniform_block->name); return true; } } @@ -1006,17 +986,7 @@ bool ProgramInfoManager::GetTransformFeedbackVarying( if (type) { *type = varying->type; } - if (length || name) { - GLsizei max_size = std::min( - bufsize - 1, static_cast<GLsizei>(varying->name.size())); - if (length) { - *length = static_cast<GLsizei>(max_size); - } - if (name && bufsize > 0) { - memcpy(name, varying->name.c_str(), max_size); - name[max_size] = '\0'; - } - } + FillNameAndLength(bufsize, length, name, varying->name); return true; } } |