invalid read of size 1

1

After seeing many similar threads, I can not properly resolve this error message from Valgrind (memcheck):

==397018== Invalid read of size 1
==397018==    at 0x527689D: JUMP_TO_L3_EXT_HEADER(unsigned char const*, unsigned char, unsigned long) (ip_proto.h:628)
==397018==    by 0x5276A2B: JUMP_TO_L3_FRAG_HEADER(unsigned char const*, unsigned long) (ip_proto.h:654)
==397018==    by 0x5276B1D: GET_L3_FRAG_INFO_IPV6(unsigned char const*, unsigned int&, unsigned short&, unsigned char&, unsigned char&, unsigned long, unsigned char*) (ip_proto.h:668)
==397018==    by 0x5277744: packetinfo::L3PacketHandler::fill(unsigned char const*, unsigned int) (L3PacketHandler.h:170)
==397018==    by 0x5277CA4: packetinfo::PacketInfo::fill(unsigned char const*, unsigned int, bool) (PacketInfo.h:292)
==397018==    by 0x5277E68: cdpi::protoengine::PacketInfoCache::fill(unsigned char*, unsigned int, bool) (PacketInfoCache.h:73)
==397018==    by 0x51621D3: cdpi::protoengine::ProtoEngine::initPacketPath(bool, unsigned char*, unsigned int, unsigned int) (ProtoEngine.cc:3412)
==397018==    by 0x5224436: cdpi::FlowManager::FlowManagerPriv::getFlow(bool, unsigned char*, unsigned int, unsigned int, generic_addr const&, cdpi::ClassificationResult&, cdpi::L4Data*, cdpi::User*) (FlowManagerPriv.cc:205)
==397018==    by 0x5223D9E: cdpi::FlowManager::getFlow(bool, unsigned char*, unsigned int, unsigned int, generic_addr const&, cdpi::ClassificationResult&, cdpi::L4Data*, cdpi::User*) (FlowManager.cc:41)
==397018==    by 0x61C4B7: dpisim::CDPIFlavour::processPDUs(dpisim::DPIsimPolicyDecisor*, dpisim::DPIsimPacket&, dpisim::DPIsimPacketResult&, cdpi::ClassificationResult&, cdpi::AnalyzerContext&, int, dpisim::DPIsimUser&) (CDPIFlavour.cc:280)
==397018==    by 0x61C224: dpisim::CDPIFlavour::processPacket(dpisim::DPIsimPacket&, dpisim::DPIsimPacketResult&, dpisim::DPIsimUser&) (CDPIFlavour.cc:248)
==397018==    by 0x614D46: dpisim::DPIAdapter::processPacket(dpisim::DPIsimPacket&, dpisim::DPIsimPacketResult&, dpisim::DPIsimUser&) (DPIAdapter.cc:282)
==397018==  Address 0x7bdc5ef is 7 bytes after a block of size 56 alloc'd
==397018==    at 0x4A08982: operator new[](unsigned long) (vg_replace_malloc.c:385)
==397018==    by 0x5BAEAD: dpisim::DPIsimPacket::initialize(pcap_pkthdr const*, unsigned char const*, unsigned int) (DPIsimPacket.cc:215)
==397018==    by 0x5BA45F: dpisim::DPIsimPacket::DPIsimPacket(pcap_pkthdr const*, unsigned char const*, unsigned int) (DPIsimPacket.cc:42)
==397018==    by 0x5DF4A6: dpisim::DPIsimPacketManager::manipulatePacket(unsigned int, pcap_pkthdr*, unsigned char const*, unsigned int) (DPIsimPacketManager.cc:102)
==397018==    by 0x5ADEC6: dpisim::DPIsimTracePcap::run() (DPIsimTracePcap.cc:134)
==397018==    by 0x5DEAC6: boost::_mfi::mf0<void, dpisim::DPIsimTrace>::operator()(dpisim::DPIsimTrace*) const (mem_fn_template.hpp:49)
==397018==    by 0x5DE969: void boost::_bi::list1<boost::_bi::value<dpisim::DPIsimTrace*> >::operator()<boost::_mfi::mf0<void, dpisim::DPIsimTrace>, boost::_bi::list0>(boost::_bi::type<void>, boost::_mfi::mf0<void, dpisim::DPIsimTrace>&, boost::_bi::list0&, int) (bind.hpp:255)
==397018==    by 0x5DE89C: boost::_bi::bind_t<void, boost::_mfi::mf0<void, dpisim::DPIsimTrace>, boost::_bi::list1<boost::_bi::value<dpisim::DPIsimTrace*> > >::operator()() (bind_template.hpp:20)
==397018==    by 0x5DE817: boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mfi::mf0<void, dpisim::DPIsimTrace>, boost::_bi::list1<boost::_bi::value<dpisim::DPIsimTrace*> > > >::run() (thread.hpp:116)
==397018==    by 0x6089D49: thread_proxy (in /lab/dpi/building-deps/boost/boost_1_59_0/lib/libboost_thread.so.1.59.0)
==397018==    by 0x3D45807AA0: start_thread (in /lib64/libpthread-2.12.so)
==397018==    by 0x3D454E893C: clone (in /lib64/libc-2.12.so)

The code that causes the error is the line indicated in the comment:

inline const unsigned char* JUMP_TO_L3_EXT_HEADER(const unsigned char*     packet, uint8_t extHeader,size_t packetlen = 0) {
if(VERSION_IPv4 == IP_VERSION(packet)) {
return packet;
} else {
uint8_t current_header = IPPROTO_IPV6;

// Check packetlen
uint32_t size = 0;

while((extHeader!= current_header && (IPPROTO_IPV6 == current_header || IPPROTO_FRAGMENT == current_header ||
                                     IPPROTO_HOPOPTS == current_header || IPPROTO_ROUTING == current_header ||
                                     IPPROTO_DSTOPTS == current_header || IPPROTO_AH == current_header))) {

  if (packetlen!=0 && size>packetlen)
  {
     // Error calculating extension header size. Exit
    return NULL;
  }

  uint8_t next_header=IPPROTO_IPV6;
  switch(current_header) {
  case IPPROTO_IPV6:
    next_header = ((const ip6_hdr*)packet)->ip6_ctlun.ip6_un1.ip6_un1_nxt;
    packet += sizeof(const ip6_hdr);
    size += sizeof(const ip6_hdr);
    break;
  case IPPROTO_HOPOPTS:
  case IPPROTO_ROUTING:
  case IPPROTO_DSTOPTS:
    /* All these headers have the first 16 bits equal, so we can group them */
    next_header = ((const ip6_ext*)packet)->ip6e_nxt;
    packet +=  8 + ((((const ip6_ext*)packet)->ip6e_len)<<3); /* +1 because according to RFC size does not include the first 8 bytes */
    size += 8 + ((((const ip6_ext*)packet)->ip6e_len)<<3);//AQUÍ INDICA VALGRIND EL ACCESO INDEBIDO!!!
    break;        
  case IPPROTO_FRAGMENT:
    next_header = ((const ip6_ext*)packet)->ip6e_nxt;
    packet += sizeof(ip6_frag);
    size += sizeof(ip6_frag);
    break;
  case IPPROTO_AH:
    /* Authentication header does include the size in a different format that the rest of headers ... 
       Very smart thing to do in a standard! 
       The size is a 16 bit network-order word, which give you the number of 4-bytes words in size, minus 8*/
    next_header = ((const ip6_ext*)packet)->ip6e_nxt;
    packet += 8 + ((be16toh( ((*(packet+1))<<8) + *(packet+2)))<<2);
    size +=  8 + ((be16toh( ((*(packet+1))<<8) + *(packet+2)))<<2);
    break;
  }
  current_header = next_header;
} 
return (extHeader == current_header) ? packet : NULL;
}
}

I put a printf to try to detect the fault. Give the following output:

size=48, ip6e_len=0, ip6e_len<<3=0

Any suggestions will be well accepted.

    
asked by Pataliebre_mesetario 30.06.2016 в 10:13
source

1 answer

3

Based on the code that you expose the problem is here:

const unsigned char* packet;

Where does that pointer point to? to nowhere or to a random position, as you prefer to say it.

After declaring that variable you try to manipulate the pointer:

next_header = ((const ip6_ext*)packet)->ip6e_nxt;

But of course, if packet does not point to anything in particular ... What do you expect to recover from packet->ip6e_next ? In the best case you will recover garbage and at worst the program will be aborted by the operating system for trying to access memory that does not correspond to you.

EDIT:

packet +=  8 + ((((const ip6_ext*)packet)->ip6e_len)<<3); /* +1 because according to RFC size does not include the first 8 bytes */
size += 8 + ((((const ip6_ext*)packet)->ip6e_len)<<3);//AQUÍ INDICA VALGRIND EL ACCESO INDEBIDO!!!

in the first instruction you modify the pointer packet and in the second you try to read ... the same as in the first instruction? As you have modified the pointer, the reading will be different.

If you notice, the increase of packet will match always with the value of size . I think you can save the variable size and calculate it with pointer arithmetic:

uint8_t current_header = IPPROTO_IPV6;

const char* init = packet;

// ...

if (packetlen!=0 && (packet-init)>packetlen)

Either that or store the increment a in a local variable and then apply that value to both variables.

Greetings.

    
answered by 30.06.2016 / 10:18
source