Fixed fuzz bug by further validating map entries.

Map entry key/value cannot be repeated or map.  Value cannot be group.

PiperOrigin-RevId: 505586184
pull/13171/head
Joshua Haberman 2 years ago committed by Copybara-Service
parent 37de88c212
commit 518e19dc63
  1. 6
      upb/message/test.cc
  2. 76
      upb/mini_table/decode.c
  3. 6
      upb/wire/decode.c

@ -649,4 +649,10 @@ TEST(MessageTest, MapField) {
// 0, 0);
// }
//
// TEST(FuzzTest, ExtensionWithoutExt) {
// DecodeEncodeArbitrarySchemaAndPayload({{"$ 3", "", "%#F"}, {}, "", {2, 1}},
// std::string("\022\002\010\000", 4), 0,
// 0);
// }
//
// end:google_only

@ -665,64 +665,48 @@ static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) {
d->table->size = UPB_ALIGN_UP(d->table->size, 8);
}
static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data,
size_t len) {
if (len < 2) {
upb_MtDecoder_ErrorFormat(d, "Invalid map encode length: %zu", len);
UPB_UNREACHABLE();
static void upb_MtDecoder_ValidateEntryField(upb_MtDecoder* d,
const upb_MiniTableField* f,
int expected_num) {
const char* name = expected_num == 1 ? "key" : "val";
if (f->number != expected_num) {
upb_MtDecoder_ErrorFormat(d,
"map %s did not have expected number (%d vs %d)",
name, expected_num, (int)f->number);
}
const upb_EncodedType key_type = _upb_FromBase92(data[0]);
switch (key_type) {
case kUpb_EncodedType_Fixed32:
case kUpb_EncodedType_Fixed64:
case kUpb_EncodedType_SFixed32:
case kUpb_EncodedType_SFixed64:
case kUpb_EncodedType_Int32:
case kUpb_EncodedType_UInt32:
case kUpb_EncodedType_SInt32:
case kUpb_EncodedType_Int64:
case kUpb_EncodedType_UInt64:
case kUpb_EncodedType_SInt64:
case kUpb_EncodedType_Bool:
case kUpb_EncodedType_String:
break;
default:
upb_MtDecoder_ErrorFormat(d, "Invalid map key field type: %d", key_type);
UPB_UNREACHABLE();
if (upb_IsRepeatedOrMap(f) || f->presence < 0) {
upb_MtDecoder_ErrorFormat(
d, "map %s cannot be repeated or map, or be in oneof", name);
}
upb_MtDecoder_ParseMessage(d, data, len);
upb_MtDecoder_AssignHasbits(d->table);
if (UPB_UNLIKELY(d->table->field_count != 2)) {
upb_MtDecoder_ErrorFormat(d, "%hu fields in map", d->table->field_count);
UPB_UNREACHABLE();
uint32_t not_ok_types;
if (expected_num == 1) {
not_ok_types = (1 << kUpb_FieldType_Float) | (1 << kUpb_FieldType_Double) |
(1 << kUpb_FieldType_Message) | (1 << kUpb_FieldType_Group) |
(1 << kUpb_FieldType_Bytes) | (1 << kUpb_FieldType_Enum);
} else {
not_ok_types = 1 << kUpb_FieldType_Group;
}
const int num0 = d->table->fields[0].number;
if (UPB_UNLIKELY(num0 != 1)) {
upb_MtDecoder_ErrorFormat(d, "field %d in map key", num0);
UPB_UNREACHABLE();
if ((1 << upb_MiniTableField_Type(f)) & not_ok_types) {
upb_MtDecoder_ErrorFormat(d, "map %s cannot have type %d", name,
(int)f->descriptortype);
}
}
const int num1 = d->table->fields[1].number;
if (UPB_UNLIKELY(num1 != 2)) {
upb_MtDecoder_ErrorFormat(d, "field %d in map val", num1);
UPB_UNREACHABLE();
}
static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data,
size_t len) {
upb_MtDecoder_ParseMessage(d, data, len);
upb_MtDecoder_AssignHasbits(d->table);
const int off0 = d->table->fields[0].offset;
if (UPB_UNLIKELY(off0 != kNoPresence && off0 != kHasbitPresence)) {
upb_MtDecoder_ErrorFormat(d, "bad offset %d in map key", off0);
if (UPB_UNLIKELY(d->table->field_count != 2)) {
upb_MtDecoder_ErrorFormat(d, "%hu fields in map", d->table->field_count);
UPB_UNREACHABLE();
}
const int off1 = d->table->fields[1].offset;
if (UPB_UNLIKELY(off1 != kNoPresence && off1 != kHasbitPresence)) {
upb_MtDecoder_ErrorFormat(d, "bad offset %d in map val", off1);
UPB_UNREACHABLE();
}
upb_MtDecoder_ValidateEntryField(d, &d->table->fields[0], 1);
upb_MtDecoder_ValidateEntryField(d, &d->table->fields[1], 2);
// Map entries have a pre-determined layout, regardless of types.
// NOTE: sync with mini_table/message_internal.h.

@ -31,6 +31,7 @@
#include "upb/collections/array_internal.h"
#include "upb/collections/map_internal.h"
#include "upb/mini_table/common.h"
#include "upb/mini_table/enum_internal.h"
#include "upb/wire/common_internal.h"
#include "upb/wire/decode_internal.h"
@ -581,8 +582,13 @@ static const char* _upb_Decoder_DecodeToMap(upb_Decoder* d, const char* ptr,
upb_Map** map_p = UPB_PTR_AT(msg, field->offset, upb_Map*);
upb_Map* map = *map_p;
upb_MapEntry ent;
UPB_ASSERT(upb_MiniTableField_Type(field) == kUpb_FieldType_Message);
const upb_MiniTable* entry = subs[field->submsg_index].submsg;
UPB_ASSERT(entry->field_count == 2);
UPB_ASSERT(!upb_IsRepeatedOrMap(&entry->fields[0]));
UPB_ASSERT(!upb_IsRepeatedOrMap(&entry->fields[1]));
if (!map) {
map = _upb_Decoder_CreateMap(d, entry);
*map_p = map;

Loading…
Cancel
Save