Changeset e9da777


Ignore:
Timestamp:
07/01/18 00:59:20 (2 years ago)
Author:
Richard Sanger <rsanger@…>
Branches:
cachetimestamps, develop, master, rc-4.0.4, ringdecrementfix, ringperformance
Children:
8f5d454
Parents:
fc6def2
Message:

Refactor pcapng to read an entire block when possible

Remove much of the duplicated read logic in pcapng. Most blocks were
processed by reading the header, and then reading the variable length
portions such as a packet or options.

Instead, this is all replaced with a single top level read which reads
the entire block. This simplifies logic and makes it easier to check
for out of bounds reads/writes. This also adds additional
sanity checks, such as checking the caplen actually matches with the
data supplied.

The one exception to this refactor are 'section' blocks which contain the
magic to determine endianness. So we don't know the endianess of a block
length until we read a 'section'.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • lib/format_pcapng.c

    rfc6def2 re9da777  
    341341}
    342342
    343 static inline int skip_block(libtrace_t *libtrace, uint32_t toread) {
    344         int err;
    345 
    346         while (toread > 0) {
    347                 char buf[4096];
    348                 int nextread;
    349 
    350                 if (toread < 4096) {
    351                         nextread = toread;
    352                 } else {
    353                         nextread = 4096;
    354                 }
    355 
    356                 err = wandio_read(libtrace->io, buf, nextread);
    357                 if (err < 0) {
    358                         trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
    359                                 "Reading section header options");
    360                         return -1;
    361                 }
    362                 if (err == 0) {
    363                         return 0;
    364                 }
    365                 toread -= err;
    366         }
    367 
    368         return 1;
    369 
    370 }
    371 
    372343static inline int pcapng_read_body(libtrace_t *libtrace, char *body,
    373344                uint32_t to_read) {
     
    378349        if (err < 0) {
    379350                trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
    380                         "Failed to read pcapng interface options");
     351                        "Failed reading pcapng block");
    381352                return err;
    382353        }
     
    388359        if (err < (int)to_read) {
    389360                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
    390                         "Incomplete pcapng interface header block");
     361                        "Incomplete pcapng block");
    391362                return -1;
    392363        }
     
    516487        /* Read all of the options etc. -- we don't need them for now, but
    517488         * we have to skip forward to the next useful header. */
    518         bodyptr = packet->buffer + sizeof(pcapng_sec_t);
     489        bodyptr = (char *) packet->buffer + sizeof(pcapng_sec_t);
    519490        err = pcapng_read_body(libtrace, bodyptr, to_read);
    520491        if (err <= 0) {
     
    532503
    533504static int pcapng_read_interface(libtrace_t *libtrace,
    534                 libtrace_packet_t *packet, uint32_t flags) {
     505                libtrace_packet_t *packet, uint32_t blocklen, uint32_t flags) {
    535506
    536507        pcapng_int_t *inthdr;
    537         int err;
    538         uint32_t to_read;
    539508        pcapng_interface_t *newint;
    540509        uint16_t optcode, optlen;
     
    542511        char *bodyptr = NULL;
    543512
    544         err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_int_t));
    545 
    546         if (err < 0) {
    547                 trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED,
    548                         "Reading pcapng interface header block");
    549                 return -1;
    550         }
    551 
    552         if (err == 0) {
    553                 return 0;
    554         }
    555 
    556         if (err < (int)sizeof(pcapng_int_t)) {
     513        if (blocklen < sizeof(pcapng_int_t) + 4) {
    557514                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
    558515                        "Incomplete pcapng interface header block");
     
    577534                newint->snaplen = byteswap32(inthdr->snaplen);
    578535                newint->linktype = byteswap16(inthdr->linktype);
    579                 to_read = byteswap32(inthdr->blocklen) - sizeof(pcapng_int_t);
    580536        } else {
    581537                assert(inthdr->blocktype == PCAPNG_INTERFACE_TYPE);
    582538                newint->snaplen = inthdr->snaplen;
    583539                newint->linktype = inthdr->linktype;
    584                 to_read = inthdr->blocklen - sizeof(pcapng_int_t);
    585540        }
    586541
     
    597552        DATA(libtrace)->nextintid += 1;
    598553
    599         bodyptr = packet->buffer + sizeof(pcapng_int_t);
    600         err = pcapng_read_body(libtrace, bodyptr, to_read);
    601         if (err <= 0) {
    602                 return err;
    603         }
     554        bodyptr = (char *) packet->buffer + sizeof(pcapng_int_t);
    604555
    605556        packet->type = TRACE_RT_PCAPNG_META;
     
    632583        } while (optcode != 0);
    633584
    634         return 1;
     585        return (int) blocklen;
    635586
    636587}
    637588
    638589static int pcapng_read_nrb(libtrace_t *libtrace, libtrace_packet_t *packet,
    639                 uint32_t flags) {
     590                uint32_t blocklen, uint32_t flags) {
    640591
    641592        /* Just read the NR records and pass them off to the caller. If
     
    644595         */
    645596        pcapng_nrb_t *hdr = NULL;
    646         int err;
    647         uint32_t to_read;
    648         char *bodyptr;
    649 
    650         err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_nrb_t));
    651 
    652         if (err < 0) {
    653                 trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng name resolution block");
    654                 return -1;
    655         }
    656 
    657         if (err == 0) {
    658                 return 0;
    659         }
    660 
    661         if (err < (int)sizeof(pcapng_nrb_t)) {
     597
     598        if (blocklen < sizeof(pcapng_nrb_t) + 4) {
    662599                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
    663600                                "Incomplete pcapng name resolution block");
     
    670607        if (DATA(libtrace)->byteswapped) {
    671608                assert(byteswap32(hdr->blocktype) == PCAPNG_NAME_RESOLUTION_TYPE);
    672                 to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_nrb_t);
    673609        } else {
    674610                assert(hdr->blocktype == PCAPNG_NAME_RESOLUTION_TYPE);
    675                 to_read = hdr->blocklen - sizeof(pcapng_nrb_t);
    676         }
    677 
    678         bodyptr = packet->buffer + sizeof(pcapng_nrb_t);
    679         err = pcapng_read_body(libtrace, bodyptr, to_read);
    680         if (err <= 0) {
    681                 return err;
    682611        }
    683612
     
    688617        }
    689618
    690         return sizeof(pcapng_nrb_t) + to_read;
     619        return (int) blocklen;
    691620
    692621}
    693622
    694623static int pcapng_read_custom(libtrace_t *libtrace, libtrace_packet_t *packet,
    695                 uint32_t flags) {
     624                uint32_t blocklen, uint32_t flags) {
    696625
    697626        /* Just read the custom records and pass them off to the caller. If
     
    700629         */
    701630        pcapng_custom_t *hdr = NULL;
    702         int err;
    703         uint32_t to_read;
    704         char *bodyptr;
    705 
    706         err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_custom_t));
    707 
    708         if (err < 0) {
    709                 trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng custom block");
    710                 return -1;
    711         }
    712 
    713         if (err == 0) {
    714                 return 0;
    715         }
    716 
    717         if (err < (int)sizeof(pcapng_custom_t)) {
     631
     632        if (blocklen < sizeof(pcapng_custom_t) + 4) {
    718633                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
    719634                                "Incomplete pcapng custom block");
     
    727642                assert(byteswap32(hdr->blocktype) == PCAPNG_CUSTOM_TYPE ||
    728643                        byteswap32(hdr->blocktype) == PCAPNG_CUSTOM_NONCOPY_TYPE);
    729                 to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_custom_t);
    730644        } else {
    731645                assert(hdr->blocktype == PCAPNG_CUSTOM_TYPE ||
    732646                        hdr->blocktype == PCAPNG_CUSTOM_NONCOPY_TYPE);
    733                 to_read = hdr->blocklen - sizeof(pcapng_custom_t);
    734         }
    735 
    736         bodyptr = packet->buffer + sizeof(pcapng_custom_t);
    737         err = pcapng_read_body(libtrace, bodyptr, to_read);
    738         if (err <= 0) {
    739                 return err;
    740647        }
    741648
     
    746653        }
    747654
    748         return sizeof(pcapng_custom_t) + to_read;
     655        return (int) blocklen;
    749656
    750657}
    751658
    752659static int pcapng_read_stats(libtrace_t *libtrace, libtrace_packet_t *packet,
    753                 uint32_t flags) {
     660                uint32_t blocklen, uint32_t flags) {
    754661        pcapng_stats_t *hdr = NULL;
    755         int err;
    756         uint32_t to_read;
    757662        uint32_t ifaceid;
    758663        uint64_t timestamp;
     
    762667        char *bodyptr;
    763668
    764         err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_stats_t));
    765 
    766         if (err < 0) {
    767                 trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng interface stats");
    768                 return -1;
    769         }
    770 
    771         if (err == 0) {
    772                 return 0;
    773         }
    774 
    775         if (err < (int)sizeof(pcapng_stats_t)) {
     669        if (blocklen < sizeof(pcapng_stats_t) + 4) {
    776670                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
    777671                                "Incomplete pcapng interface stats header");
     
    784678        if (DATA(libtrace)->byteswapped) {
    785679                assert(byteswap32(hdr->blocktype) == PCAPNG_INTERFACE_STATS_TYPE);
    786                 to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_stats_t);
    787680                ifaceid = byteswap32(hdr->interfaceid);
    788681                timestamp = ((uint64_t)(byteswap32(hdr->timestamp_high)) << 32) + byteswap32(hdr->timestamp_low);
    789682        } else {
    790683                assert(hdr->blocktype == PCAPNG_INTERFACE_STATS_TYPE);
    791                 to_read = hdr->blocklen - sizeof(pcapng_stats_t);
    792684                ifaceid = hdr->interfaceid;
    793685                timestamp = ((uint64_t)(hdr->timestamp_high) << 32) +
    794686                                hdr->timestamp_low;
    795         }
    796 
    797         bodyptr = packet->buffer + sizeof(pcapng_stats_t);
    798         err = pcapng_read_body(libtrace, bodyptr, to_read);
    799         if (err <= 0) {
    800                 return err;
    801687        }
    802688
     
    815701
    816702        if (timestamp < interface->laststats) {
    817                 return sizeof(pcapng_stats_t) + to_read;
     703                return (int) blocklen;
    818704        }
    819705
     
    869755        interface->laststats = timestamp;
    870756
    871         return sizeof(pcapng_stats_t) + to_read;
     757        return (int) blocklen;
    872758
    873759}
    874760
    875761static int pcapng_read_simple(libtrace_t *libtrace, libtrace_packet_t *packet,
    876                 uint32_t flags) {
    877 
    878         int err;
    879         uint32_t to_read;
     762                uint32_t blocklen, uint32_t flags) {
     763
    880764        uint32_t caplen;
    881765        pcapng_spkt_t *hdr = NULL;
    882766        pcapng_interface_t *interface;
    883         char *bodyptr;
    884 
    885         err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_spkt_t));
    886 
    887         if (err < 0) {
    888                 trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng simple packet");
    889                 return -1;
    890         }
    891 
    892         if (err == 0) {
    893                 return 0;
    894         }
    895 
    896         if (err < (int)sizeof(pcapng_spkt_t)) {
     767
     768        if (blocklen < sizeof(pcapng_spkt_t) + 4) {
    897769                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
    898770                                "Incomplete pcapng simple packet header");
     
    905777        if (DATA(libtrace)->byteswapped) {
    906778                assert(byteswap32(hdr->blocktype) == PCAPNG_SIMPLE_PACKET_TYPE);
    907                 to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_spkt_t);
    908                 caplen = to_read - 4;   /* account for trailing length field */
     779                caplen = byteswap32(hdr->blocklen) - sizeof(pcapng_spkt_t) - 4;
     780                         /* account for trailing length field */
    909781        } else {
    910782                assert(hdr->blocktype == PCAPNG_SIMPLE_PACKET_TYPE);
    911                 to_read = hdr->blocklen - sizeof(pcapng_spkt_t);
    912                 caplen = to_read - 4; /* account for trailing length field */
    913         }
    914 
    915         bodyptr = packet->buffer + sizeof(pcapng_spkt_t);
    916         err = pcapng_read_body(libtrace, bodyptr, to_read);
    917         if (err <= 0) {
    918                 return err;
     783                caplen = hdr->blocklen - sizeof(pcapng_spkt_t) - 4;
     784                         /* account for trailing length field */
    919785        }
    920786
     
    936802                return -1;
    937803        }
    938         return sizeof(pcapng_spkt_t) + to_read;
     804        return (int) blocklen;
    939805
    940806}
    941807
    942808static int pcapng_read_enhanced(libtrace_t *libtrace, libtrace_packet_t *packet,
    943                 uint32_t flags) {
     809                uint32_t blocklen, uint32_t flags) {
    944810        pcapng_epkt_t *hdr = NULL;
    945         int err;
    946         uint32_t to_read;
    947811        uint32_t caplen;
    948812        uint32_t ifaceid;
     
    952816        char *bodyptr;
    953817
    954         err = wandio_read(libtrace->io, packet->buffer, sizeof(pcapng_epkt_t));
    955 
    956         if (err < 0) {
    957                 trace_set_err(libtrace, TRACE_ERR_WANDIO_FAILED, "reading pcapng enhanced packet");
    958                 return -1;
    959         }
    960 
    961         if (err == 0) {
    962                 return 0;
    963         }
    964 
    965         if (err < (int)sizeof(pcapng_epkt_t)) {
     818        if (blocklen < (int)sizeof(pcapng_epkt_t) + 4) {
    966819                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
    967820                                "Incomplete pcapng enhanced packet header");
     
    975828                assert(byteswap32(hdr->blocktype) == PCAPNG_ENHANCED_PACKET_TYPE);
    976829                caplen = byteswap32(hdr->caplen);
    977                 to_read = byteswap32(hdr->blocklen) - sizeof(pcapng_epkt_t);
    978830                ifaceid = byteswap32(hdr->interfaceid);
    979831        } else {
    980832                assert(hdr->blocktype == PCAPNG_ENHANCED_PACKET_TYPE);
    981833                caplen = hdr->caplen;
    982                 to_read = hdr->blocklen - sizeof(pcapng_epkt_t);
    983834                ifaceid = hdr->interfaceid;
    984835        }
    985836
    986         bodyptr = packet->buffer + sizeof(pcapng_epkt_t);
    987         err = pcapng_read_body(libtrace, bodyptr, to_read);
    988         if (err <= 0) {
    989                 return err;
    990         }
     837        bodyptr = (char *) packet->buffer + sizeof(pcapng_epkt_t);
    991838
    992839        /* Set packet type based on interface linktype */
     
    1009856        /* Make sure to parse any useful options */
    1010857        if ((caplen % 4) == 0) {
    1011                 bodyptr = packet->payload + caplen;
    1012         } else {
    1013                 bodyptr = packet->payload + caplen + (4 - (caplen % 4));
     858                bodyptr = (char *) packet->payload + caplen;
     859        } else {
     860                bodyptr = (char *) packet->payload + caplen + (4 - (caplen % 4));
     861        }
     862        // Check the packet caplen actually fits within the block we read
     863        if ((char *) packet->buffer + blocklen < bodyptr + 4) {
     864                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
     865                                "Incomplete pcapng enhanced packet header");
     866                return -1;
    1014867        }
    1015868
     
    1033886
    1034887        } while (optcode != 0);
    1035         return sizeof(pcapng_epkt_t) + to_read;
     888        return (int) blocklen;
    1036889
    1037890}
     
    1093946                        return -1;
    1094947                }
     948                if (btype != PCAPNG_SECTION_TYPE) {
     949                        // Read the entire block, unless it is a section as our byte ordering has
     950                        // not been set yet.
     951                        err = pcapng_read_body(libtrace, packet->buffer, to_read);
     952                        if (err <= 0) {
     953                                return err;
     954                        }
     955                        if (*((uint32_t *)((char *)packet->buffer+to_read-4)) != peeker.blocklen) {
     956                                trace_set_err(libtrace, TRACE_ERR_BAD_PACKET,
     957                                              "Mismatched pcapng block sizes found, trace is invalid.");
     958                                return -1;
     959                        }
     960                }
    1095961
    1096962                switch (btype) {
     
    1103969                        /* Interface Header */
    1104970                        case PCAPNG_INTERFACE_TYPE:
    1105                                 err = pcapng_read_interface(libtrace, packet, flags);
     971                                err = pcapng_read_interface(libtrace, packet, to_read, flags);
    1106972                                gotpacket = 1;
    1107973                                break;
     
    1110976                        case PCAPNG_ENHANCED_PACKET_TYPE:
    1111977                                err = pcapng_read_enhanced(libtrace, packet,
    1112                                                 flags);
     978                                                to_read, flags);
    1113979                                gotpacket = 1;
    1114980                                break;
    1115981
    1116982                        case PCAPNG_SIMPLE_PACKET_TYPE:
    1117                                 err = pcapng_read_simple(libtrace, packet, flags);
     983                                err = pcapng_read_simple(libtrace, packet, to_read, flags);
    1118984                                gotpacket = 1;
    1119985                                break;
    1120986
    1121987                        case PCAPNG_INTERFACE_STATS_TYPE:
    1122                                 err = pcapng_read_stats(libtrace, packet, flags);
     988                                err = pcapng_read_stats(libtrace, packet, to_read, flags);
    1123989                                gotpacket = 1;
    1124990                                break;
    1125991
    1126992                        case PCAPNG_NAME_RESOLUTION_TYPE:
    1127                                 err = pcapng_read_nrb(libtrace, packet, flags);
     993                                err = pcapng_read_nrb(libtrace, packet, to_read, flags);
    1128994                                gotpacket = 1;
    1129995                                break;
     
    1131997                        case PCAPNG_CUSTOM_TYPE:
    1132998                        case PCAPNG_CUSTOM_NONCOPY_TYPE:
    1133                                 err = pcapng_read_custom(libtrace, packet, flags);
     999                                err = pcapng_read_custom(libtrace, packet, to_read, flags);
    11341000                                gotpacket = 1;
    11351001                                break;
     
    11411007                        /* Everything else -- don't care, skip it */
    11421008                        default:
    1143                                 err = skip_block(libtrace, to_read);
    11441009                                break;
    11451010                }
Note: See TracChangeset for help on using the changeset viewer.