@@ -82,6 +82,9 @@ typedef struct rpki_rtr_pdu_ipv6_prefix_ {
8282typedef struct rpki_rtr_pdu_error_report_ {
8383 rpki_rtr_pdu pdu_header ;
8484 u_char encapsulated_pdu_length [4 ]; /* Encapsulated PDU length */
85+ /* Copy of Erroneous PDU (variable, optional) */
86+ /* Length of Error Text (4 octets in network byte order) */
87+ /* Arbitrary Text of Error Diagnostic Message (variable, optional) */
8588} rpki_rtr_pdu_error_report ;
8689
8790/*
@@ -171,24 +174,47 @@ indent_string (u_int indent)
171174/*
172175 * Print a single PDU.
173176 */
174- static int
175- rpki_rtr_pdu_print (netdissect_options * ndo , const u_char * tptr , u_int indent )
177+ static u_int
178+ rpki_rtr_pdu_print (netdissect_options * ndo , const u_char * tptr , const u_int len ,
179+ const u_char recurse , const u_int indent )
176180{
177181 const rpki_rtr_pdu * pdu_header ;
178182 u_int pdu_type , pdu_len , hexdump ;
179183 const u_char * msg ;
180184
185+ /* Protocol Version */
186+ ND_TCHECK_8BITS (tptr );
187+ if (* tptr != 0 ) {
188+ /* Skip the rest of the input buffer because even if this is
189+ * a well-formed PDU of a future RPKI-Router protocol version
190+ * followed by a well-formed PDU of RPKI-Router protocol
191+ * version 0, there is no way to know exactly how to skip the
192+ * current PDU.
193+ */
194+ ND_PRINT ((ndo , "%sRPKI-RTRv%u (unknown)" , indent_string (8 ), * tptr ));
195+ return len ;
196+ }
197+ if (len < sizeof (rpki_rtr_pdu )) {
198+ ND_PRINT ((ndo , "(%u bytes is too few to decode)" , len ));
199+ goto invalid ;
200+ }
201+ ND_TCHECK2 (* tptr , sizeof (rpki_rtr_pdu ));
181202 pdu_header = (const rpki_rtr_pdu * )tptr ;
182203 pdu_type = pdu_header -> pdu_type ;
183204 pdu_len = EXTRACT_32BITS (pdu_header -> length );
184- ND_TCHECK2 (* tptr , pdu_len );
205+ /* Do not check bounds with pdu_len yet, do it in the case blocks
206+ * below to make it possible to decode at least the beginning of
207+ * a truncated Error Report PDU or a truncated encapsulated PDU.
208+ */
185209 hexdump = FALSE;
186210
187211 ND_PRINT ((ndo , "%sRPKI-RTRv%u, %s PDU (%u), length: %u" ,
188212 indent_string (8 ),
189213 pdu_header -> version ,
190214 tok2str (rpki_rtr_pdu_values , "Unknown" , pdu_type ),
191215 pdu_type , pdu_len ));
216+ if (pdu_len < sizeof (rpki_rtr_pdu ) || pdu_len > len )
217+ goto invalid ;
192218
193219 switch (pdu_type ) {
194220
@@ -198,6 +224,9 @@ rpki_rtr_pdu_print (netdissect_options *ndo, const u_char *tptr, u_int indent)
198224 case RPKI_RTR_SERIAL_NOTIFY_PDU :
199225 case RPKI_RTR_SERIAL_QUERY_PDU :
200226 case RPKI_RTR_END_OF_DATA_PDU :
227+ if (pdu_len != sizeof (rpki_rtr_pdu ) + 4 )
228+ goto invalid ;
229+ ND_TCHECK2 (* tptr , pdu_len );
201230 msg = (const u_char * )(pdu_header + 1 );
202231 ND_PRINT ((ndo , "%sSession ID: 0x%04x, Serial: %u" ,
203232 indent_string (indent + 2 ),
@@ -210,13 +239,19 @@ rpki_rtr_pdu_print (netdissect_options *ndo, const u_char *tptr, u_int indent)
210239 */
211240 case RPKI_RTR_RESET_QUERY_PDU :
212241 case RPKI_RTR_CACHE_RESET_PDU :
242+ if (pdu_len != sizeof (rpki_rtr_pdu ))
243+ goto invalid ;
244+ /* no additional boundary to check */
213245
214246 /*
215247 * Zero payload PDUs.
216248 */
217249 break ;
218250
219251 case RPKI_RTR_CACHE_RESPONSE_PDU :
252+ if (pdu_len != sizeof (rpki_rtr_pdu ))
253+ goto invalid ;
254+ /* no additional boundary to check */
220255 ND_PRINT ((ndo , "%sSession ID: 0x%04x" ,
221256 indent_string (indent + 2 ),
222257 EXTRACT_16BITS (pdu_header -> u .session_id )));
@@ -226,6 +261,9 @@ rpki_rtr_pdu_print (netdissect_options *ndo, const u_char *tptr, u_int indent)
226261 {
227262 const rpki_rtr_pdu_ipv4_prefix * pdu ;
228263
264+ if (pdu_len != sizeof (rpki_rtr_pdu ) + 12 )
265+ goto invalid ;
266+ ND_TCHECK2 (* tptr , pdu_len );
229267 pdu = (const rpki_rtr_pdu_ipv4_prefix * )tptr ;
230268 ND_PRINT ((ndo , "%sIPv4 Prefix %s/%u-%u, origin-as %u, flags 0x%02x" ,
231269 indent_string (indent + 2 ),
@@ -239,6 +277,9 @@ rpki_rtr_pdu_print (netdissect_options *ndo, const u_char *tptr, u_int indent)
239277 {
240278 const rpki_rtr_pdu_ipv6_prefix * pdu ;
241279
280+ if (pdu_len != sizeof (rpki_rtr_pdu ) + 24 )
281+ goto invalid ;
282+ ND_TCHECK2 (* tptr , pdu_len );
242283 pdu = (const rpki_rtr_pdu_ipv6_prefix * )tptr ;
243284 ND_PRINT ((ndo , "%sIPv6 Prefix %s/%u-%u, origin-as %u, flags 0x%02x" ,
244285 indent_string (indent + 2 ),
@@ -253,52 +294,76 @@ rpki_rtr_pdu_print (netdissect_options *ndo, const u_char *tptr, u_int indent)
253294 const rpki_rtr_pdu_error_report * pdu ;
254295 u_int encapsulated_pdu_length , text_length , tlen , error_code ;
255296
297+ tlen = sizeof (rpki_rtr_pdu );
298+ /* Do not test for the "Length of Error Text" data element yet. */
299+ if (pdu_len < tlen + 4 )
300+ goto invalid ;
301+ ND_TCHECK2 (* tptr , tlen + 4 );
302+ /* Safe up to and including the "Length of Encapsulated PDU"
303+ * data element, more data elements may be present.
304+ */
256305 pdu = (const rpki_rtr_pdu_error_report * )tptr ;
257306 encapsulated_pdu_length = EXTRACT_32BITS (pdu -> encapsulated_pdu_length );
258- ND_TCHECK2 (* tptr , encapsulated_pdu_length );
259- tlen = pdu_len ;
307+ tlen += 4 ;
260308
261309 error_code = EXTRACT_16BITS (pdu -> pdu_header .u .error_code );
262310 ND_PRINT ((ndo , "%sError code: %s (%u), Encapsulated PDU length: %u" ,
263311 indent_string (indent + 2 ),
264312 tok2str (rpki_rtr_error_codes , "Unknown" , error_code ),
265313 error_code , encapsulated_pdu_length ));
266314
267- tptr += sizeof (* pdu );
268- tlen -= sizeof (* pdu );
269-
270- /*
271- * Recurse if there is an encapsulated PDU.
272- */
273- if (encapsulated_pdu_length &&
274- (encapsulated_pdu_length <= tlen )) {
275- ND_PRINT ((ndo , "%s-----encapsulated PDU-----" , indent_string (indent + 4 )));
276- if (rpki_rtr_pdu_print (ndo , tptr , indent + 2 ))
277- goto trunc ;
315+ if (encapsulated_pdu_length ) {
316+ /* Section 5.10 of RFC 6810 says:
317+ * "An Error Report PDU MUST NOT be sent for an Error Report PDU."
318+ *
319+ * However, as far as the protocol encoding goes Error Report PDUs can
320+ * happen to be nested in each other, however many times, in which case
321+ * the decoder should still print such semantically incorrect PDUs.
322+ *
323+ * That said, "the Erroneous PDU field MAY be truncated" (ibid), thus
324+ * to keep things simple this implementation decodes only the two
325+ * outermost layers of PDUs and makes bounds checks in the outer and
326+ * the inner PDU independently.
327+ */
328+ if (pdu_len < tlen + encapsulated_pdu_length )
329+ goto invalid ;
330+ if (! recurse ) {
331+ ND_TCHECK2 (* tptr , tlen + encapsulated_pdu_length );
332+ }
333+ else {
334+ ND_PRINT ((ndo , "%s-----encapsulated PDU-----" , indent_string (indent + 4 )));
335+ rpki_rtr_pdu_print (ndo , tptr + tlen ,
336+ encapsulated_pdu_length , 0 , indent + 2 );
337+ }
338+ tlen += encapsulated_pdu_length ;
278339 }
279340
280- tptr += encapsulated_pdu_length ;
281- tlen -= encapsulated_pdu_length ;
341+ if (pdu_len < tlen + 4 )
342+ goto invalid ;
343+ ND_TCHECK2 (* tptr , tlen + 4 );
344+ /* Safe up to and including the "Length of Error Text" data element,
345+ * one more data element may be present.
346+ */
282347
283348 /*
284349 * Extract, trail-zero and print the Error message.
285350 */
286- text_length = 0 ;
287- if (tlen > 4 ) {
288- text_length = EXTRACT_32BITS (tptr );
289- tptr += 4 ;
290- tlen -= 4 ;
291- }
292- ND_TCHECK2 (* tptr , text_length );
293- if (text_length && (text_length <= tlen )) {
351+ text_length = EXTRACT_32BITS (tptr + tlen );
352+ tlen += 4 ;
353+
354+ if (text_length ) {
355+ if (pdu_len < tlen + text_length )
356+ goto invalid ;
357+ /* fn_printn() makes the bounds check */
294358 ND_PRINT ((ndo , "%sError text: " , indent_string (indent + 2 )));
295- if (fn_printn (ndo , tptr , text_length , ndo -> ndo_snapend ))
359+ if (fn_printn (ndo , tptr + tlen , text_length , ndo -> ndo_snapend ))
296360 goto trunc ;
297361 }
298362 }
299363 break ;
300364
301365 default :
366+ ND_TCHECK2 (* tptr , pdu_len );
302367
303368 /*
304369 * Unknown data, please hexdump.
@@ -310,57 +375,29 @@ rpki_rtr_pdu_print (netdissect_options *ndo, const u_char *tptr, u_int indent)
310375 if (ndo -> ndo_vflag > 1 || (ndo -> ndo_vflag && hexdump )) {
311376 print_unknown_data (ndo ,tptr ,"\n\t " , pdu_len );
312377 }
313- return 0 ;
378+ return pdu_len ;
314379
380+ invalid :
381+ ND_PRINT ((ndo , "%s" , istr ));
382+ ND_TCHECK2 (* tptr , len );
383+ return len ;
315384trunc :
316- return 1 ;
385+ ND_PRINT ((ndo , "\n\t%s" , tstr ));
386+ return len ;
317387}
318388
319389void
320390rpki_rtr_print (netdissect_options * ndo , register const u_char * pptr , register u_int len )
321391{
322- u_int tlen , pdu_type , pdu_len ;
323- const u_char * tptr ;
324- const rpki_rtr_pdu * pdu_header ;
325-
326- tptr = pptr ;
327- tlen = len ;
328-
329392 if (!ndo -> ndo_vflag ) {
330393 ND_PRINT ((ndo , ", RPKI-RTR" ));
331394 return ;
332395 }
333-
334- while (tlen >= sizeof (rpki_rtr_pdu )) {
335-
336- ND_TCHECK2 (* tptr , sizeof (rpki_rtr_pdu ));
337-
338- pdu_header = (const rpki_rtr_pdu * )tptr ;
339- pdu_type = pdu_header -> pdu_type ;
340- pdu_len = EXTRACT_32BITS (pdu_header -> length );
341- ND_TCHECK2 (* tptr , pdu_len );
342-
343- /* infinite loop check */
344- if (!pdu_type || !pdu_len ) {
345- break ;
346- }
347-
348- if (tlen < pdu_len ) {
349- goto trunc ;
350- }
351-
352- /*
353- * Print the PDU.
354- */
355- if (rpki_rtr_pdu_print (ndo , tptr , 8 ))
356- goto trunc ;
357-
358- tlen -= pdu_len ;
359- tptr += pdu_len ;
396+ while (len ) {
397+ u_int pdu_len = rpki_rtr_pdu_print (ndo , pptr , len , 1 , 8 );
398+ len -= pdu_len ;
399+ pptr += pdu_len ;
360400 }
361- return ;
362- trunc :
363- ND_PRINT ((ndo , "\n\t%s" , tstr ));
364401}
365402
366403/*
0 commit comments