Search code examples
cmemorymemory-managementvalgrindbuffer-overflow

Valgrind giving error but everything seems fine


This one seems like a duplicate of my previous post but it is not.....

Here Valgrind giving the following error:

 udit@udit-Dabba ~/mec $  valgrind --leak-check=full
 sendip -v -p ipv6 -f file.txt -6s ::1 -p esp -es 0x20 -eq 0x40
 -ei z30 -eI z100  -p tcp -ts 21 -td 21 ::2  

 ==4331== Memcheck, a memory error detector
 ==4331== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
 ==4331== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
 ==4331== Command: sendip -v -p ipv6 -f file.txt -6s ::1 -p esp -es 0x20
 -eq 0x40 -ei z30 -eI z100 -p tcp -ts 21 -td 21 ::2
==4331== 
esp
Added 43 options
Initializing module ipv6
Initializing module esp
Initializing module tcp
==4331== Invalid write of size 4
==4331==    at 0x4027EB8: memcpy (mc_replace_strmem.c:635)
==4331==    by 0x4032269: do_opt (esp.c:113)
==4331==    by 0x804A51D: main (sendip.c:575)
==4331==  Address 0x41ceab0 is 144 bytes inside a block of size 146 alloc'd
==4331==    at 0x402699A: realloc (vg_replace_malloc.c:525)
==4331==    by 0x4032231: do_opt (esp.c:111)
==4331==    by 0x804A51D: main (sendip.c:575)
==4331== 

valgrind: m_mallocfree.c:225 (mk_plain_bszB): Assertion 'bszB != 0' failed.
valgrind: This is probably caused by your program erroneously writing past the
end of a heap block and corrupting heap metadata.  If you fix any
invalid writes reported by Memcheck, this assertion failure will
probably go away.  Please try that before reporting this as a bug.

==4331==    at 0x380282BD: report_and_quit (m_libcassert.c:193)
==4331==    by 0x38028415: vgPlain_assert_fail (m_libcassert.c:267)
==4331==    by 0x380351E7: vgPlain_arena_malloc (m_mallocfree.c:225)
==4331==    by 0x380662C7: vgPlain_cli_malloc (replacemalloc_core.c:83)
==4331==    by 0x38001FA8: vgMemCheck_new_block (mc_malloc_wrappers.c:201)
==4331==    by 0x38002196: vgMemCheck_malloc (mc_malloc_wrappers.c:238)
==4331==    by 0x38068BF8: vgPlain_scheduler (scheduler.c:1394)
==4331==    by 0x3807A354: run_a_thread_NORETURN (syswrap-linux.c:94)

sched status:
running_tid=1

Thread 1: status = VgTs_Runnable
==4331==    at 0x40268A4: malloc (vg_replace_malloc.c:236)
==4331==    by 0x4152415: gethostbyname2 (getXXbyYY.c:103)
==4331==    by 0x402CC68: set_addr (ipv6.c:33)
==4331==    by 0x804A642: main (sendip.c:594)


Note: see also the FAQ in the source distribution.
It contains workarounds to several common problems.
In particular, if Valgrind aborted or crashed after
identifying problems in your program, there's a good chance
that fixing those problems will prevent Valgrind aborting or
crashing, especially if it happened in m_mallocfree.c.

If that doesn't help, please report this bug to: www.valgrind.org

In the bug report, send all the above text, the valgrind
version, and what OS and version you are using.  Thanks.

esp.c (line no. 113)

  case 'eI':       /* ICV data (variable length) */
                   /* For right now, we will do either random generation
                   * or a user-provided string. We put it in the header,
                   * then move it into the trailer in finalize.
                   */
            length = stringargument(arg, &temp);
            priv->icvlen = length;
            pack->alloc_len += length;
            pack->data = realloc(esp, pack->alloc_len);
            esp = (esp_header *)pack->data;                                                                              
      113:      
            memcpy(&esp->tail.ivicv[priv->ivlen],temp, priv->icvlen);
            pack->modified |= ESP_MOD_ICV;

These are the respective header files which I suppose may help in debugging ......

ip6.h

/*
 * authentication header
*/
struct ip_auth_hdr {
    u_int8_t  nexthdr;
    u_int8_t  hdrlen;       /* This one is measured in 32 bit units! */
    u_int16_t reserved;
    u_int32_t spi;
    u_int32_t seq_no;       /* Sequence number */
    u_int8_t  auth_data[0]; /* Variable len but >=4. Mind the
                               64 bit alignment! */
 #define icv     auth_data       /* rfc 4302 name */
    /* TBD - high-order sequence number */

 };

/*
 * encapsulated security payload header
 */
 struct ip_esp_hdr {
    u_int32_t spi;
    u_int32_t seq_no;       /* Sequence number */
    u_int8_t  enc_data[0];  /* Variable len but >=8. Mind the
                             64 bit alignment! */
  };

esp.h

 struct ip_esp_tail {
    u_int8_t padlen;        /* padding is pushed before tail */
    u_int8_t nexthdr;
    u_int32_t ivicv[0];     /* both IV and ICV, if any */
 };

 struct ip_esp_headtail {
    struct ip_esp_hdr hdr;
    struct ip_esp_tail tail;
  };

  typedef struct ip_esp_headtail esp_header;

  #define ESP_MIN_PADDING 4 

  typedef struct ip_esp_private { /* keep track of things privately */
    u_int32_t type;         /* type = IPPROTO_ESP */
    u_int32_t ivlen;        /* length of IV portion */
    u_int32_t icvlen;       /* length of ICV portion */
    u_int32_t keylen;       /* length of "key" (not transmitted data) */
    u_int32_t key[0];       /* key itself */
  } esp_private;

  struct ip_auth_hdr {
    u_int8_t  nexthdr;
    u_int8_t  hdrlen;       /* This one is measured in 32 bit units! */
    u_int16_t reserved;
    u_int32_t spi;
    u_int32_t seq_no;       /* Sequence number */
    u_int8_t  auth_data[0]; /* Variable len but >=4. Mind the
                               64 bit alignment! */
  #define icv     auth_data       /* rfc 4302 name */
    /* TBD - high-order sequence number */

  };

 /*
  * encapsulated security payload header
  */
  struct ip_esp_hdr {
    u_int32_t spi;
    u_int32_t seq_no;       /* Sequence number */
    u_int8_t  enc_data[0];  /* Variable len but >=8. Mind the
                            64 bit alignment! */  
  };

If anyone getting any clue where is the leakage going on ??? and how to patch it ??


Solution

  • As Chris said valgrind tells you that you program is trying to write to memory that is outside of the allocated region:

    Invalid write of size 4
       at 0x4027EB8: memcpy (mc_replace_strmem.c:635)
       by 0x4032269: do_opt (esp.c:113)
       by 0x804A51D: main (sendip.c:575)
     Address 0x41ceab0 is 144 bytes inside a block of size 146 alloc'd
       at 0x402699A: realloc (vg_replace_malloc.c:525)
       by 0x4032231: do_opt (esp.c:111)
       by 0x804A51D: main (sendip.c:575)
    

    It tells you that in do_opt (in the file esp.c at line 111) you have called realloc to allocate 146 bytes of memory and now the function memcpy is trying to do a 4-byte write starting at 144 bytes from the start of that memory block, which will cause a write outside of the allocated region (144 + 4 > 146). It also tells you that memcpy was called from the do_opt function.

    So either you are allocating to little memory or you are using wrong offset when copying to the memory. So next step would be to inspect the code in the locations reported by valgrind.

    But what to do if the problem isn't obvious when looking at the code?

    One option is to use valgrind's --db-attach option, which allows you to enter gdb. That will allow you to look around and check things like weather pack->alloc_len is the value you expect, and if &esp->tail.ivicv[priv->ivlen] points to the palace you expect it to compared to pack->data. (this could also be done the classic way by adding printf printing those values).

    Below is my guess what the problem is, but hidden if you want to try to figure it out yourself first:

    Maybe you are forgetting that ivicv is an uint32, and you have priv->ivlen measured in bytes. In that case changing it to &esp->tail.ivicv[priv->ivlen / sizeof(u_int32_t)] would help