Skip to content

Commit 7661e80

Browse files
bwillcoxbwillcoxpubfork
authored andcommitted
dns: parser reads into garbage on misreported packet size (mfontanini#468)
Co-authored-by: Bill Willcox <[email protected]>
1 parent 633caad commit 7661e80

File tree

3 files changed

+64
-6
lines changed

3 files changed

+64
-6
lines changed

include/tins/dns.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,7 +1034,8 @@ class TINS_API DNS : public PDU {
10341034
uint32_t compose_name(const uint8_t* ptr, char* out_ptr) const;
10351035
void convert_records(const uint8_t* ptr,
10361036
const uint8_t* end,
1037-
resources_type& res) const;
1037+
resources_type& res,
1038+
const uint16_t rr_count) const;
10381039
void skip_to_section_end(Memory::InputMemoryStream& stream,
10391040
const uint32_t num_records) const;
10401041
void skip_to_dname_end(Memory::InputMemoryStream& stream) const;

src/dns.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,10 +414,11 @@ void DNS::inline_convert_v4(uint32_t value, char* output) {
414414
// Parses records in some section.
415415
void DNS::convert_records(const uint8_t* ptr,
416416
const uint8_t* end,
417-
resources_type& res) const {
417+
resources_type& res,
418+
const uint16_t rr_count) const {
418419
InputMemoryStream stream(ptr, end - ptr);
419420
char dname[256], small_addr_buf[256];
420-
while (stream) {
421+
while (stream && (res.size() < rr_count)) {
421422
string data;
422423
bool used_small_buffer = false;
423424
// Retrieve the record's domain name.
@@ -577,7 +578,8 @@ DNS::resources_type DNS::answers() const {
577578
convert_records(
578579
&records_data_[0] + answers_idx_,
579580
&records_data_[0] + authority_idx_,
580-
res
581+
res,
582+
answers_count()
581583
);
582584
}
583585
return res;
@@ -589,7 +591,8 @@ DNS::resources_type DNS::authority() const {
589591
convert_records(
590592
&records_data_[0] + authority_idx_,
591593
&records_data_[0] + additional_idx_,
592-
res
594+
res,
595+
authority_count()
593596
);
594597
}
595598
return res;
@@ -601,7 +604,8 @@ DNS::resources_type DNS::additional() const {
601604
convert_records(
602605
&records_data_[0] + additional_idx_,
603606
&records_data_[0] + records_data_.size(),
604-
res
607+
res,
608+
additional_count()
605609
);
606610
}
607611
return res;

tests/src/dns_test.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,3 +602,56 @@ TEST_F(DNSTest, BadLabelSize) {
602602
SUCCEED();
603603
}
604604
}
605+
606+
TEST_F(DNSTest, BadPacketLength) {
607+
608+
// valid response packet with RR's in all sections
609+
const uint8_t payload[] = {
610+
0x74,0xa9,0x85,0x80,0x00,0x01,0x00,0x02,0x00,0x01,0x00,0x04,0x08,0x5f,0x73,0x65,0x72,
611+
0x76,0x69,0x63,0x65,0x04,0x5f,0x74,0x63,0x70,0x05,0x77,0x69,0x66,0x69,0x36,0x03,
612+
0x6c,0x61,0x6e,0x00,0x00,0x21,0x00,0x01,0xc0,0x0c,0x00,0x21,0x00,0x01,0x00,0x01,
613+
0x51,0x80,0x00,0x16,0x00,0x00,0x00,0x03,0x00,0x09,0x04,0x66,0x61,0x73,0x74,0x05,
614+
0x77,0x69,0x66,0x69,0x36,0x03,0x6c,0x61,0x6e,0x00,0xc0,0x0c,0x00,0x21,0x00,0x01,
615+
0x00,0x01,0x51,0x80,0x00,0x16,0x00,0x00,0x00,0x01,0x00,0x09,0x04,0x73,0x6c,0x6f,
616+
0x77,0x05,0x77,0x69,0x66,0x69,0x36,0x03,0x6c,0x61,0x6e,0x00,0xc0,0x62,0x00,0x02,
617+
0x00,0x01,0x00,0x01,0x51,0x80,0x00,0x05,0x02,0x70,0x69,0xc0,0x62,0xc0,0x5d,0x00,
618+
0x01,0x00,0x01,0x00,0x01,0x51,0x80,0x00,0x04,0x0a,0x18,0x00,0x02,0xc0,0x3b,0x00,
619+
0x01,0x00,0x01,0x00,0x01,0x51,0x80,0x00,0x04,0x0a,0x18,0x00,0x02,0xc0,0x79,0x00,
620+
0x01,0x00,0x01,0x00,0x01,0x51,0x80,0x00,0x04,0x0a,0x18,0x00,0x02,0x00,0x00,0x29,
621+
0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x00,0x0a,0x00,0x18,0x86,0x1f,0x14,0x0f,
622+
0x41,0xfa,0xf3,0x95,0x48,0x6e,0x79,0x61,0x61,0x78,0x32,0x0f,0x44,0x5d,0x21,0x47,
623+
0x85,0x83,0x9a,0x95
624+
};
625+
626+
// valid DNS message but misreport packet size;
627+
// before fix, parser headed into uncharted waters on requesting additional section
628+
629+
// buffer with space for valid packet plus garbage bytes
630+
const size_t bigsz{512};
631+
uint8_t big_packet[bigsz];
632+
633+
// copy valid packet
634+
std::copy(payload,
635+
payload + sizeof(payload),
636+
big_packet);
637+
638+
// fill additional bytes with junk
639+
std::fill(big_packet + sizeof(payload),
640+
big_packet + bigsz,
641+
0x5A);
642+
643+
// initial packet parse ok
644+
const DNS packet(big_packet, bigsz);
645+
646+
// RR's parse ok now
647+
EXPECT_EQ(packet.questions_count(), 1);
648+
EXPECT_EQ(packet.answers_count(), 2);
649+
EXPECT_EQ(packet.authority_count(), 1);
650+
EXPECT_EQ(packet.additional_count(), 4);
651+
EXPECT_EQ(packet.queries().size(), 1U);
652+
EXPECT_EQ(packet.answers().size(), 2U);
653+
EXPECT_EQ(packet.authority().size(), 1U);
654+
EXPECT_EQ(packet.additional().size(), 4U);
655+
}
656+
657+

0 commit comments

Comments
 (0)