Skip to content

Commit 9e8b30c

Browse files
mkruskal-googlecopybara-github
authored andcommitted
Fix cord handling in DynamicMessage and oneofs.
This fixes a memory corruption vulnerability for anyone using cord with dynamically built descriptor pools. PiperOrigin-RevId: 676091224
1 parent aa5818d commit 9e8b30c

34 files changed

+318
-178
lines changed

.bazelrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ build:ubsan --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1
2626
# Workaround for the fact that Bazel links with $CC, not $CXX
2727
# https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748
2828
build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr
29+
# Abseil passes nullptr to memcmp with 0 size
30+
build:ubsan --copt=-fno-sanitize=nonnull-attribute
2931

3032
# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel
3133
# https://github.com/protocolbuffers/protobuf/issues/14313

ci/common.bazelrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ build:ubsan --action_env=UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1
3131
# Workaround for the fact that Bazel links with $CC, not $CXX
3232
# https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748
3333
build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr
34+
# Abseil passes nullptr to memcmp with 0 size
35+
build:ubsan --copt=-fno-sanitize=nonnull-attribute
3436

3537
# Workaround Bazel 7 remote cache issues.
3638
# See https://github.com/bazelbuild/bazel/issues/20161

python/google/protobuf/internal/descriptor_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ def CheckDescriptorMapping(self, mapping):
727727
excepted_dict['new_key'] = 'new'
728728
self.assertNotEqual(mapping, excepted_dict)
729729
self.assertRaises(KeyError, mapping.__getitem__, 'key_error')
730-
self.assertRaises(KeyError, mapping.__getitem__, len(mapping) + 1)
730+
self.assertRaises(KeyError, mapping.__getitem__, len(mapping) * 2)
731731
# TODO: Add __repr__ support for DescriptorMapping.
732732
if api_implementation.Type() == 'cpp':
733733
self.assertEqual(str(mapping)[0], '<')

python/google/protobuf/internal/field_mask_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def testDescriptorToFieldMask(self):
5353
mask = field_mask_pb2.FieldMask()
5454
msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
5555
mask.AllFieldsFromDescriptor(msg_descriptor)
56-
self.assertEqual(79, len(mask.paths))
56+
self.assertEqual(80, len(mask.paths))
5757
self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
5858
for field in msg_descriptor.fields:
5959
self.assertTrue(field.name in mask.paths)

python/google/protobuf/internal/test_util.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def SetAllNonLazyFields(message):
7777

7878
message.optional_string_piece = u'124'
7979
message.optional_cord = u'125'
80+
message.optional_bytes_cord = b'optional bytes cord'
8081

8182
#
8283
# Repeated fields.
@@ -247,6 +248,7 @@ def SetAllExtensions(message):
247248

248249
extensions[pb2.optional_string_piece_extension] = u'124'
249250
extensions[pb2.optional_cord_extension] = u'125'
251+
extensions[pb2.optional_bytes_cord_extension] = b'optional bytes cord'
250252

251253
#
252254
# Repeated fields.
@@ -423,6 +425,7 @@ def ExpectAllFieldsSet(test_case, message):
423425

424426
test_case.assertTrue(message.HasField('optional_string_piece'))
425427
test_case.assertTrue(message.HasField('optional_cord'))
428+
test_case.assertTrue(message.HasField('optional_bytes_cord'))
426429

427430
test_case.assertEqual(101, message.optional_int32)
428431
test_case.assertEqual(102, message.optional_int64)

python/google/protobuf/internal/unknown_fields_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def testCheckUnknownFieldValue(self):
212212
unknown_field_set,
213213
(17, 0, 117))
214214

215-
self.assertEqual(98, len(unknown_field_set))
215+
self.assertEqual(99, len(unknown_field_set))
216216

217217
def testCopyFrom(self):
218218
message = unittest_pb2.TestEmptyMessage()
@@ -250,7 +250,7 @@ def testClear(self):
250250
self.empty_message.Clear()
251251
# All cleared, even unknown fields.
252252
self.assertEqual(self.empty_message.SerializeToString(), b'')
253-
self.assertEqual(len(unknown_field_set), 98)
253+
self.assertEqual(len(unknown_field_set), 99)
254254

255255
@unittest.skipIf((sys.version_info.major, sys.version_info.minor) < (3, 4),
256256
'tracemalloc requires python 3.4+')
@@ -309,7 +309,7 @@ def testUnknownField(self):
309309
def testUnknownExtensions(self):
310310
message = unittest_pb2.TestEmptyMessageWithExtensions()
311311
message.ParseFromString(self.all_fields_data)
312-
self.assertEqual(len(unknown_fields.UnknownFieldSet(message)), 98)
312+
self.assertEqual(len(unknown_fields.UnknownFieldSet(message)), 99)
313313
self.assertEqual(message.SerializeToString(), self.all_fields_data)
314314

315315

src/google/protobuf/compiler/cpp/field.cc

Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* field,
130130
break;
131131
case FieldDescriptor::CPPTYPE_STRING:
132132
is_string_ = true;
133-
string_type_ = field->options().ctype();
134133
is_inlined_ = IsStringInlined(field, options);
135134
is_bytes_ = field->type() == FieldDescriptor::TYPE_BYTES;
136135
has_default_constexpr_constructor_ = is_repeated_or_map;
@@ -229,40 +228,6 @@ void FieldGeneratorBase::GenerateCopyConstructorCode(io::Printer* p) const {
229228
}
230229

231230
namespace {
232-
// Use internal types instead of ctype or string_type.
233-
enum class StringType {
234-
kView,
235-
kString,
236-
kCord,
237-
kStringPiece,
238-
};
239-
240-
StringType GetStringType(const FieldDescriptor& field) {
241-
ABSL_CHECK_EQ(field.cpp_type(), FieldDescriptor::CPPTYPE_STRING);
242-
243-
if (field.options().has_ctype()) {
244-
switch (field.options().ctype()) {
245-
case FieldOptions::CORD:
246-
return StringType::kCord;
247-
case FieldOptions::STRING_PIECE:
248-
return StringType::kStringPiece;
249-
default:
250-
return StringType::kString;
251-
}
252-
}
253-
254-
const pb::CppFeatures& cpp_features =
255-
CppGenerator::GetResolvedSourceFeatures(field).GetExtension(::pb::cpp);
256-
switch (cpp_features.string_type()) {
257-
case pb::CppFeatures::CORD:
258-
return StringType::kCord;
259-
case pb::CppFeatures::VIEW:
260-
return StringType::kView;
261-
default:
262-
return StringType::kString;
263-
}
264-
}
265-
266231
std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field,
267232
const Options& options,
268233
MessageSCCAnalyzer* scc) {
@@ -279,7 +244,7 @@ std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field,
279244
case FieldDescriptor::CPPTYPE_MESSAGE:
280245
return MakeRepeatedMessageGenerator(field, options, scc);
281246
case FieldDescriptor::CPPTYPE_STRING: {
282-
if (GetStringType(*field) == StringType::kView) {
247+
if (field->cpp_string_type() == FieldDescriptor::CppStringType::kView) {
283248
return MakeRepeatedStringViewGenerator(field, options, scc);
284249
} else {
285250
return MakeRepeatedStringGenerator(field, options, scc);
@@ -303,10 +268,10 @@ std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field,
303268
case FieldDescriptor::CPPTYPE_ENUM:
304269
return MakeSinguarEnumGenerator(field, options, scc);
305270
case FieldDescriptor::CPPTYPE_STRING: {
306-
switch (GetStringType(*field)) {
307-
case StringType::kView:
271+
switch (field->cpp_string_type()) {
272+
case FieldDescriptor::CppStringType::kView:
308273
return MakeSingularStringViewGenerator(field, options, scc);
309-
case StringType::kCord:
274+
case FieldDescriptor::CppStringType::kCord:
310275
if (field->type() == FieldDescriptor::TYPE_BYTES) {
311276
if (field->real_containing_oneof()) {
312277
return MakeOneofCordGenerator(field, options, scc);

src/google/protobuf/compiler/cpp/field.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,6 @@ class FieldGeneratorBase {
9595
// Returns true if the field API uses bytes (void) instead of chars.
9696
bool is_bytes() const { return is_bytes_; }
9797

98-
// Returns the public API string type for string fields.
99-
FieldOptions::CType string_type() const { return string_type_; }
100-
10198
// Returns true if this field is part of a oneof field.
10299
bool is_oneof() const { return is_oneof_; }
103100

@@ -217,7 +214,6 @@ class FieldGeneratorBase {
217214
bool is_lazy_ = false;
218215
bool is_weak_ = false;
219216
bool is_oneof_ = false;
220-
FieldOptions::CType string_type_ = FieldOptions::STRING;
221217
bool has_default_constexpr_constructor_ = false;
222218
};
223219

@@ -269,7 +265,6 @@ class FieldGenerator {
269265
bool is_foreign() const { return impl_->is_foreign(); }
270266
bool is_string() const { return impl_->is_string(); }
271267
bool is_bytes() const { return impl_->is_bytes(); }
272-
FieldOptions::CType string_type() const { return impl_->string_type(); }
273268
bool is_oneof() const { return impl_->is_oneof(); }
274269
bool is_inlined() const { return impl_->is_inlined(); }
275270
bool has_default_constexpr_constructor() const {

src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,6 @@ void SingularStringView::GenerateStaticMembers(io::Printer* p) const {
216216
}
217217

218218
void SingularStringView::GenerateAccessorDeclarations(io::Printer* p) const {
219-
ABSL_CHECK(!field_->options().has_ctype());
220-
221219
auto v1 = p->WithVars(AnnotatedAccessors(field_, {""}));
222220
auto v2 = p->WithVars(
223221
AnnotatedAccessors(field_, {"set_"}, AnnotationCollector::kSet));

src/google/protobuf/compiler/cpp/helpers.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1597,7 +1597,8 @@ MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) {
15971597
switch (field->type()) {
15981598
case FieldDescriptor::TYPE_STRING:
15991599
case FieldDescriptor::TYPE_BYTES: {
1600-
if (field->options().ctype() == FieldOptions::CORD) {
1600+
if (field->cpp_string_type() ==
1601+
FieldDescriptor::CppStringType::kCord) {
16011602
result.contains_cord = true;
16021603
}
16031604
break;

0 commit comments

Comments
 (0)