summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhenyao Mo <zmo@chromium.org>2019-07-18 22:40:55 +0000
committerJüri Valdmann <juri.valdmann@qt.io>2019-08-08 10:34:31 +0000
commitdebc89cea4a5c61a53c1544e83f090552507b3dc (patch)
tree19adffcd2c61bbedfe34332ea32c023e7c571776
parent79d32f4cf1d730fdf623a6bec2bca8e63efdca86 (diff)
downloadqtwebengine-chromium-debc89cea4a5c61a53c1544e83f090552507b3dc.tar.gz
[Backport] Security bug 983938
Fix a base_level/max_level bug in validating command buffer Currently we didn't clamp level values when computing which level actually have images, therefore leading to out-of-bounds access. BUG=983938 TEST=gpu_unittests R=piman@chromium.org Change-Id: Ia4c143f271cfc5142a34ade5f3163e29d9be7033 Reviewed-by: Antoine Labour <piman@chromium.org> Commit-Queue: Zhenyao Mo <zmo@chromium.org> Cr-Commit-Position: refs/heads/master@{#678877} Reviewed-by: Michal Klocek <michal.klocek@qt.io>
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc24
-rw-r--r--chromium/gpu/command_buffer/service/texture_manager.cc51
-rw-r--r--chromium/gpu/command_buffer/service/texture_manager.h5
3 files changed, 66 insertions, 14 deletions
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
index b94cd64e5a4..36662a93b71 100644
--- a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_textures.cc
@@ -5044,6 +5044,30 @@ TEST_P(GLES3DecoderTest, ImmutableTextureBaseLevelMaxLevelClamping) {
}
}
+TEST_P(GLES3DecoderTest, ClearRenderableLevelsWithOutOfRangeBaseLevel) {
+ // Regression test for https://crbug.com/983938
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0,
+ 0);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ TextureManager* manager = group().texture_manager();
+ TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+ ASSERT_TRUE(texture_ref != nullptr);
+
+ {
+ EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 55));
+ TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 55);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ }
+
+ // The following call will trigger out-of-bounds access in asan build
+ // without fixing the bug.
+ manager->ClearRenderableLevels(GetDecoder(), texture_ref);
+}
+
// TODO(gman): Complete this test.
// TEST_P(GLES2DecoderTest, CompressedTexImage2DGLError) {
// }
diff --git a/chromium/gpu/command_buffer/service/texture_manager.cc b/chromium/gpu/command_buffer/service/texture_manager.cc
index abe7b8a39a5..315dc9eeb9a 100644
--- a/chromium/gpu/command_buffer/service/texture_manager.cc
+++ b/chromium/gpu/command_buffer/service/texture_manager.cc
@@ -1148,6 +1148,40 @@ void Texture::UpdateMaxLevel(GLint max_level) {
UpdateNumMipLevels();
}
+void Texture::UpdateFaceNumMipLevels(size_t face_index,
+ GLint width,
+ GLint height,
+ GLint depth) {
+ DCHECK_LT(face_index, face_infos_.size());
+ DCHECK_LE(0, base_level_);
+ Texture::FaceInfo& face_info = face_infos_[face_index];
+ if (static_cast<size_t>(base_level_) >= face_info.level_infos.size()) {
+ face_info.num_mip_levels = 0;
+ } else {
+ DCHECK_LE(1u, face_info.level_infos.size());
+ GLint safe_max_level = std::min(
+ max_level_, static_cast<GLint>(face_info.level_infos.size() - 1));
+ GLint max_num_mip_levels = std::max(0, safe_max_level - base_level_ + 1);
+ face_info.num_mip_levels = std::min(
+ max_num_mip_levels,
+ TextureManager::ComputeMipMapCount(target_, width, height, depth));
+ }
+}
+
+void Texture::UpdateFaceNumMipLevels(size_t face_index) {
+ DCHECK_LT(face_index, face_infos_.size());
+ DCHECK_LE(0, base_level_);
+ Texture::FaceInfo& face_info = face_infos_[face_index];
+ GLint width = 0, height = 0, depth = 0;
+ if (static_cast<size_t>(base_level_) < face_info.level_infos.size()) {
+ const Texture::LevelInfo& info = face_info.level_infos[base_level_];
+ width = info.width;
+ height = info.height;
+ depth = info.depth;
+ }
+ UpdateFaceNumMipLevels(face_index, width, height, depth);
+}
+
void Texture::UpdateNumMipLevels() {
if (face_infos_.empty())
return;
@@ -1164,16 +1198,8 @@ void Texture::UpdateNumMipLevels() {
base_level_ = unclamped_base_level_;
max_level_ = unclamped_max_level_;
}
- GLint max_num_mip_levels = std::max(0, max_level_ - base_level_ + 1);
- for (size_t ii = 0; ii < face_infos_.size(); ++ii) {
- Texture::FaceInfo& face_info = face_infos_[ii];
- if (static_cast<size_t>(base_level_) >= face_info.level_infos.size())
- continue;
- const Texture::LevelInfo& info = face_info.level_infos[base_level_];
- face_info.num_mip_levels = std::min(
- max_num_mip_levels, TextureManager::ComputeMipMapCount(
- target_, info.width, info.height, info.depth));
- }
+ for (size_t ii = 0; ii < face_infos_.size(); ++ii)
+ UpdateFaceNumMipLevels(ii);
// mipmap-completeness needs to be re-evaluated.
completeness_dirty_ = true;
@@ -1218,10 +1244,7 @@ void Texture::SetLevelInfo(GLenum target,
info.width != width || info.height != height || info.depth != depth ||
info.format != format || info.type != type || info.internal_workaround) {
if (level == base_level_) {
- // Calculate the mip level count.
- face_infos_[face_index].num_mip_levels = std::min(
- std::max(0, max_level_ - base_level_ + 1),
- TextureManager::ComputeMipMapCount(target_, width, height, depth));
+ UpdateFaceNumMipLevels(face_index, width, height, depth);
// Update NPOT face count for the first level.
bool prev_npot = TextureIsNPOT(info.width, info.height, info.depth);
diff --git a/chromium/gpu/command_buffer/service/texture_manager.h b/chromium/gpu/command_buffer/service/texture_manager.h
index d42699ee403..1b6915336c6 100644
--- a/chromium/gpu/command_buffer/service/texture_manager.h
+++ b/chromium/gpu/command_buffer/service/texture_manager.h
@@ -585,6 +585,11 @@ class GPU_GLES2_EXPORT Texture final : public TextureBase {
void UpdateBaseLevel(GLint base_level, const FeatureInfo* feature_info);
void UpdateMaxLevel(GLint max_level);
+ void UpdateFaceNumMipLevels(size_t face_index,
+ GLint width,
+ GLint height,
+ GLint depth);
+ void UpdateFaceNumMipLevels(size_t face_index);
void UpdateNumMipLevels();
// Increment the generation counter for all managers that have a reference to