Commit 9969257b authored by Nico Weber's avatar Nico Weber Committed by Commit Bot

mac: Fix out-of-bounds access in GetAlteredLibraryData.

With a chance of 1/256, we'd read past the end of kValidLiteralValues.
In practice, that read would return zeroes, which we'd write to
kTestLibData -- but zeroes aren't valid literal values, so that would
then make TestShader() crash when it tried to link the program.

Not sure if this is related to crbug.com/1051923, but it's in the
same area at least.

Add a components/metal_util:unit_tests target. Covering code is useful
even if the test doesn't verify a lot, because then the ASan bots can
find stuff like this for us. (...but in this case, asan doesn't find
the out-of-bounds read because we build with `-asan-globals=0` on
macOS because of https://crbug.com/352073 .
But the test also checks for non-0 and runs the code often enough
that the test consistently fails before the fix and consistently passes
with it.)

Drive-by no-op cleanups while here:
- Remove EXPORTs on enums, they don't have any effect
- Remove redundant is_ios block in components/BUILD.gn

Bug: 1147027,1051923,1085899
Cq-Include-Trybots: luci.chromium.try:mac_chromium_asan_rel_ng
Change-Id: Ia7f9735e450c70eb64b826a499dc60690714112e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2526161
Auto-Submit: Nico Weber <thakis@chromium.org>
Reviewed-by: default avatarccameron <ccameron@chromium.org>
Commit-Queue: Nico Weber <thakis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#825730}
parent 790a3149
...@@ -224,7 +224,7 @@ test("components_unittests") { ...@@ -224,7 +224,7 @@ test("components_unittests") {
"//components/translate/ios/browser:unit_tests", "//components/translate/ios/browser:unit_tests",
"//components/ukm/ios:unit_tests", "//components/ukm/ios:unit_tests",
] ]
} else { # !iOS } else { # !is_ios
deps += [ deps += [
"//components/autofill/content/browser:unit_tests", "//components/autofill/content/browser:unit_tests",
"//components/autofill/content/renderer:unit_tests", "//components/autofill/content/renderer:unit_tests",
...@@ -284,6 +284,7 @@ test("components_unittests") { ...@@ -284,6 +284,7 @@ test("components_unittests") {
"//components/safe_browsing/content/triggers:unit_tests", "//components/safe_browsing/content/triggers:unit_tests",
"//components/safe_browsing/content/web_ui:unit_tests", "//components/safe_browsing/content/web_ui:unit_tests",
"//components/safe_browsing/core/common:unit_tests", "//components/safe_browsing/core/common:unit_tests",
"//components/safe_browsing/core/realtime:unit_tests",
"//components/safe_browsing/core/triggers:unit_tests", "//components/safe_browsing/core/triggers:unit_tests",
"//components/safety_check:unit_tests", "//components/safety_check:unit_tests",
"//components/security_interstitials/content:unit_tests", "//components/security_interstitials/content:unit_tests",
...@@ -306,6 +307,8 @@ test("components_unittests") { ...@@ -306,6 +307,8 @@ test("components_unittests") {
"//components/web_cache/browser:unit_tests", "//components/web_cache/browser:unit_tests",
"//components/web_package:unit_tests", "//components/web_package:unit_tests",
"//components/webcrypto:unit_tests", "//components/webcrypto:unit_tests",
"//components/webrtc_logging/browser:unit_tests",
"//components/webrtc_logging/common:unit_tests",
] ]
if (!is_win) { # !iOS and !Windows if (!is_win) { # !iOS and !Windows
...@@ -415,6 +418,10 @@ test("components_unittests") { ...@@ -415,6 +418,10 @@ test("components_unittests") {
] ]
} }
if (is_mac) {
deps += [ "//components/metal_util:unit_tests" ]
}
if (toolkit_views) { if (toolkit_views) {
deps += [ "//components/constrained_window:unit_tests" ] deps += [ "//components/constrained_window:unit_tests" ]
} }
...@@ -452,14 +459,6 @@ test("components_unittests") { ...@@ -452,14 +459,6 @@ test("components_unittests") {
deps += [ "//components/safe_browsing/content/renderer/phishing_classifier:unit_tests" ] deps += [ "//components/safe_browsing/content/renderer/phishing_classifier:unit_tests" ]
} }
if (!is_ios) {
deps += [
"//components/safe_browsing/core/realtime:unit_tests",
"//components/webrtc_logging/browser:unit_tests",
"//components/webrtc_logging/common:unit_tests",
]
}
if (use_dbus) { if (use_dbus) {
deps += [ deps += [
"//components/dbus/menu:unit_tests", "//components/dbus/menu:unit_tests",
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
assert(is_mac)
import("//testing/test.gni") import("//testing/test.gni")
component("metal_util") { component("metal_util") {
...@@ -42,3 +44,13 @@ component("metal_util") { ...@@ -42,3 +44,13 @@ component("metal_util") {
"MetalKit.framework", "MetalKit.framework",
] ]
} }
source_set("unit_tests") {
testonly = true
sources = [ "test_shader_unittest.cc" ]
deps = [
":metal_util",
"//base",
"//testing/gtest",
]
}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef COMPONENTS_METAL_UTIL_TEST_SHADER_H_ #ifndef COMPONENTS_METAL_UTIL_TEST_SHADER_H_
#define COMPONENTS_METAL_UTIL_TEST_SHADER_H_ #define COMPONENTS_METAL_UTIL_TEST_SHADER_H_
#include <vector>
#include "base/callback.h" #include "base/callback.h"
#include "base/task_runner.h" #include "base/task_runner.h"
#include "base/time/time.h" #include "base/time/time.h"
...@@ -12,14 +13,14 @@ ...@@ -12,14 +13,14 @@
namespace metal { namespace metal {
enum class METAL_UTIL_EXPORT TestShaderComponent { enum class TestShaderComponent {
// Test a shader compile from source. // Test a shader compile from source.
kCompile, kCompile,
// Test linking a precompiled shader. // Test linking a precompiled shader.
kLink, kLink,
}; };
enum class METAL_UTIL_EXPORT TestShaderResult { enum class TestShaderResult {
// Not attempted (e.g, because macOS version does not support Metal). // Not attempted (e.g, because macOS version does not support Metal).
kNotAttempted, kNotAttempted,
// Shader compile succeeded. // Shader compile succeeded.
...@@ -55,10 +56,16 @@ constexpr base::TimeDelta kTestShaderDelay = base::TimeDelta::FromMinutes(3); ...@@ -55,10 +56,16 @@ constexpr base::TimeDelta kTestShaderDelay = base::TimeDelta::FromMinutes(3);
// that |callback| will be called either on another thread or inside the // that |callback| will be called either on another thread or inside the
// TestShader function call. // TestShader function call.
// https://crbug.com/974219 // https://crbug.com/974219
void METAL_UTIL_EXPORT METAL_UTIL_EXPORT void TestShader(
TestShader(TestShaderCallback callback, TestShaderCallback callback,
const base::TimeDelta& delay = kTestShaderDelay, const base::TimeDelta& delay = kTestShaderDelay,
const base::TimeDelta& timeout = kTestShaderTimeForever); const base::TimeDelta& timeout = kTestShaderTimeForever);
// Exposed for testing.
METAL_UTIL_EXPORT extern const size_t kTestLibSize;
METAL_UTIL_EXPORT extern const size_t kLiteralOffset;
METAL_UTIL_EXPORT extern const size_t kLiteralSize;
METAL_UTIL_EXPORT std::vector<uint8_t> GetAlteredLibraryData();
} // namespace metal } // namespace metal
......
...@@ -50,8 +50,11 @@ const char* kTestShaderSource = ...@@ -50,8 +50,11 @@ const char* kTestShaderSource =
" return %f * in.color;\n" " return %f * in.color;\n"
"}\n" "}\n"
""; "";
} // namesspace
size_t kTestLibSize = 0x1766; const size_t kTestLibSize = 0x1766;
namespace {
uint8_t kTestLibData[] = { uint8_t kTestLibData[] = {
0x4d, 0x54, 0x4c, 0x42, 0x01, 0x80, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4d, 0x54, 0x4c, 0x42, 0x01, 0x80, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x66, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
...@@ -553,11 +556,14 @@ uint8_t kTestLibData[] = { ...@@ -553,11 +556,14 @@ uint8_t kTestLibData[] = {
0x70, 0x6c, 0x65, 0x2d, 0x6d, 0x61, 0x63, 0x6f, 0x73, 0x78, 0x31, 0x30, 0x70, 0x6c, 0x65, 0x2d, 0x6d, 0x61, 0x63, 0x6f, 0x73, 0x78, 0x31, 0x30,
0x2e, 0x31, 0x34, 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x31, 0x34, 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00}; 0x00, 0x00};
} // namespace
// There exists a 4-byte literal at this offset, which can be changed to any // There exists a 4-byte literal at this offset, which can be changed to any
// value in kValidLiteral to defeat caching. // value in kValidLiteral to defeat caching.
const size_t kLiteralOffset = 0x167c; const size_t kLiteralOffset = 0x167c;
const size_t kLiteralSize = 0x4; const size_t kLiteralSize = 0x4;
namespace {
const uint8_t kValidLiteralValues[] = { const uint8_t kValidLiteralValues[] = {
0xef, 0x4c, 0x9a, 0x68, 0xef, 0x4c, 0x9a, 0x70, 0x66, 0x6f, 0xa6, 0x74, 0xef, 0x4c, 0x9a, 0x68, 0xef, 0x4c, 0x9a, 0x70, 0x66, 0x6f, 0xa6, 0x74,
0xef, 0x4c, 0x9a, 0x78, 0x2a, 0x5e, 0x9f, 0x7a, 0x66, 0x6f, 0xa6, 0x7c, 0xef, 0x4c, 0x9a, 0x78, 0x2a, 0x5e, 0x9f, 0x7a, 0x66, 0x6f, 0xa6, 0x7c,
...@@ -658,12 +664,15 @@ crash_reporter::CrashKeyString<32>& GetLinkIndexCrashKey() { ...@@ -658,12 +664,15 @@ crash_reporter::CrashKeyString<32>& GetLinkIndexCrashKey() {
return crash_key; return crash_key;
} }
} // namespace
std::vector<uint8_t> GetAlteredLibraryData() { std::vector<uint8_t> GetAlteredLibraryData() {
// Make a copy of the shader's data. // Make a copy of the shader's data.
std::vector<uint8_t> data(kTestLibData, kTestLibData + kTestLibSize); std::vector<uint8_t> data(kTestLibData, kTestLibData + kTestLibSize);
// Alter the data at kLiteralOffset to defeat caching. // Alter the data at kLiteralOffset to defeat caching.
uint64_t index = base::RandInt(0, sizeof(kValidLiteralValues) / kLiteralSize); uint64_t index =
base::RandInt(0, sizeof(kValidLiteralValues) / kLiteralSize - 1);
for (size_t i = 0; i < kLiteralSize; ++i) for (size_t i = 0; i < kLiteralSize; ++i)
data[kLiteralOffset + i] = kValidLiteralValues[kLiteralSize * index + i]; data[kLiteralOffset + i] = kValidLiteralValues[kLiteralSize * index + i];
...@@ -677,6 +686,8 @@ std::vector<uint8_t> GetAlteredLibraryData() { ...@@ -677,6 +686,8 @@ std::vector<uint8_t> GetAlteredLibraryData() {
return data; return data;
} }
namespace {
base::ScopedDispatchObject<dispatch_data_t> GetLibraryData() { base::ScopedDispatchObject<dispatch_data_t> GetLibraryData() {
auto vector_data = GetAlteredLibraryData(); auto vector_data = GetAlteredLibraryData();
base::ScopedDispatchObject<dispatch_data_t> dispatch_data( base::ScopedDispatchObject<dispatch_data_t> dispatch_data(
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/metal_util/test_shader.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
TEST(GetAlteredLibraryDataTest, TestInvalidAccess) {
for (int j = 0; j < 4096; ++j) {
std::vector<uint8_t> data = metal::GetAlteredLibraryData();
EXPECT_EQ(data.size(), metal::kTestLibSize);
for (size_t i = 0; i < metal::kLiteralSize; ++i)
EXPECT_NE(data[metal::kLiteralOffset + i], 0);
}
}
} // namespace
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment