@@ -841,6 +841,8 @@ pub(crate) struct DnsIncoming {
841841}
842842
843843impl DnsIncoming {
844+ const HEADER_LEN : usize = 12 ;
845+
844846 pub ( crate ) fn new ( data : Vec < u8 > ) -> Result < Self > {
845847 let mut incoming = Self {
846848 offset : 0 ,
@@ -870,7 +872,7 @@ impl DnsIncoming {
870872 }
871873
872874 fn read_header ( & mut self ) -> Result < ( ) > {
873- if self . data . len ( ) < 12 {
875+ if self . data . len ( ) < Self :: HEADER_LEN {
874876 return Err ( Error :: Msg ( format ! (
875877 "DNS incoming: header is too short: {} bytes" ,
876878 self . data. len( )
@@ -885,7 +887,7 @@ impl DnsIncoming {
885887 self . num_authorities = u16_from_be_slice ( & data[ 8 ..10 ] ) ;
886888 self . num_additionals = u16_from_be_slice ( & data[ 10 ..12 ] ) ;
887889
888- self . offset = 12 ;
890+ self . offset = Self :: HEADER_LEN ;
889891
890892 debug ! (
891893 "read_header: id {}, {} questions {} answers {} authorities {} additionals" ,
@@ -954,6 +956,16 @@ impl DnsIncoming {
954956 for _ in 0 ..n {
955957 let name = self . read_name ( ) ?;
956958 let slice = & self . data [ self . offset ..] ;
959+
960+ // Muse have at least TYPE, CLASS, TTL, RDLENGTH fields: 10 bytes.
961+ if slice. len ( ) < 10 {
962+ return Err ( Error :: Msg ( format ! (
963+ "read_others: RR '{}' is too short after name: {} bytes" ,
964+ & name,
965+ slice. len( )
966+ ) ) ) ;
967+ }
968+
957969 let ty = u16_from_be_slice ( & slice[ ..2 ] ) ;
958970 let class = u16_from_be_slice ( & slice[ 2 ..4 ] ) ;
959971 let ttl = u32_from_be_slice ( & slice[ 4 ..8 ] ) ;
@@ -1113,7 +1125,18 @@ impl DnsIncoming {
11131125 0x00 => {
11141126 // regular utf8 string with length
11151127 offset += 1 ;
1116- name += str:: from_utf8 ( & data[ offset..( offset + length as usize ) ] )
1128+ let ending = offset + length as usize ;
1129+
1130+ // Never read beyond the whole data length.
1131+ if ending > data. len ( ) {
1132+ return Err ( Error :: Msg ( format ! (
1133+ "read_name: ending {} exceeds data length {}" ,
1134+ ending,
1135+ data. len( )
1136+ ) ) ) ;
1137+ }
1138+
1139+ name += str:: from_utf8 ( & data[ offset..ending] )
11171140 . map_err ( |e| Error :: Msg ( format ! ( "read_name: from_utf8: {}" , e) ) ) ?;
11181141 name += "." ;
11191142 offset += length as usize ;
@@ -1176,7 +1199,10 @@ fn get_expiration_time(created: u64, ttl: u32, percent: u32) -> u64 {
11761199
11771200#[ cfg( test) ]
11781201mod tests {
1179- use super :: { DnsIncoming , DnsOutgoing , FLAGS_QR_QUERY , TYPE_PTR } ;
1202+ use super :: {
1203+ DnsIncoming , DnsOutgoing , DnsSrv , CLASS_IN , CLASS_UNIQUE , FLAGS_QR_QUERY ,
1204+ FLAGS_QR_RESPONSE , TYPE_PTR ,
1205+ } ;
11801206
11811207 #[ test]
11821208 fn test_read_name_invalid_length ( ) {
@@ -1186,7 +1212,9 @@ mod tests {
11861212 let data = out. to_packet_data ( ) ;
11871213
11881214 // construct invalid data.
1215+ let max_len = data. len ( ) as u8 ;
11891216 let mut data_with_invalid_name_length = data. clone ( ) ;
1217+ let mut data_with_larger_name_length = data. clone ( ) ;
11901218 let name_length_offset = 12 ;
11911219
11921220 // 0x9 is the length of `name`
@@ -1203,5 +1231,43 @@ mod tests {
12031231 if let Err ( e) = invalid {
12041232 println ! ( "error: {}" , e) ;
12051233 }
1234+
1235+ // Another error case: `length`` is larger than the actual string length.
1236+ data_with_larger_name_length[ name_length_offset] = max_len + 1 ;
1237+ let invalid = DnsIncoming :: new ( data_with_larger_name_length) ;
1238+ assert ! ( invalid. is_err( ) ) ;
1239+ if let Err ( e) = invalid {
1240+ println ! ( "error: {}" , e) ;
1241+ }
1242+ }
1243+
1244+ /// Tests DnsIncoming::read_others()
1245+ #[ test]
1246+ fn test_rr_too_short_after_name ( ) {
1247+ let name = "test_rr_too_short._udp.local." ;
1248+ let mut response = DnsOutgoing :: new ( FLAGS_QR_RESPONSE ) ;
1249+ response. add_additional_answer ( Box :: new ( DnsSrv :: new (
1250+ name,
1251+ CLASS_IN | CLASS_UNIQUE ,
1252+ 1 ,
1253+ 1 ,
1254+ 1 ,
1255+ 9000 ,
1256+ "instance1" . to_string ( ) ,
1257+ ) ) ) ;
1258+ let data = response. to_packet_data ( ) ;
1259+ let mut data_too_short = data. clone ( ) ;
1260+
1261+ // verify the original data is good.
1262+ let incoming = DnsIncoming :: new ( data) ;
1263+ assert ! ( incoming. is_ok( ) ) ;
1264+
1265+ // verify that truncated data will cause an error.
1266+ data_too_short. truncate ( DnsIncoming :: HEADER_LEN + name. len ( ) + 2 ) ;
1267+ let invalid = DnsIncoming :: new ( data_too_short) ;
1268+ assert ! ( invalid. is_err( ) ) ;
1269+ if let Err ( e) = invalid {
1270+ println ! ( "error: {}" , e) ;
1271+ }
12061272 }
12071273}
0 commit comments