Wazuh: Memory leak in ossec-dbd

Created on 13 Dec 2018  路  3Comments  路  Source: wazuh/wazuh

Bug report

OS
_Any_

Wazuh version
_3.8.0_

Install type
_manager_

Install method
_Any_

Valgrind report

==4130== LEAK SUMMARY:
==4130==    definitely lost: 908 bytes in 11 blocks
==4130==    indirectly lost: 4,173 bytes in 98 blocks
==4130==      possibly lost: 675,676 bytes in 13,590 blocks
==4130==    still reachable: 155,671 bytes in 4,252 blocks

Description

There are memory leaks in ossec-dbd. The valgrind report of this is above.

bug

Most helpful comment

A PR has been created to address this issue.

@DaveVG1 Thanks for reporting this problem!

@crolopez Thanks for the additional input on this matter!

All 3 comments

Hi,

I have found this.

==13562== Invalid read of size 1
==13562==    at 0x11088F: osdb_escapestr (db_op.c:93)
==13562==    by 0x1113E9: _Rules_ReadInsertDB (rules.c:178)
==13562==    by 0x1865CE: OS_ReadXMLRules (rules_op.c:861)
==13562==    by 0x1115AF: OS_InsertRulesDB (rules.c:226)
==13562==    by 0x111E8A: main (main.c:228)
==13562==  Address 0x72e23cf is 1 bytes before a block of size 1 alloc'd
==13562==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13562==    by 0x61239B9: strdup (strdup.c:42)
==13562==    by 0x172ABA: os_LoadString (mem_op.c:93)
==13562==    by 0x1832ED: OS_ReadXMLRules (rules_op.c:304)
==13562==    by 0x1115AF: OS_InsertRulesDB (rules.c:226)
==13562==    by 0x111E8A: main (main.c:228)

After analizing the Valgrind output provided by @crolopez, it becomes clear that the issue is related to the comment member of the config_ruleinfo struct (of type RuleInfo). This variable represents a character string allocated in memory using strdup().


Valgrind log (part 1): function doing the incorrect accessing

==13562== Invalid read of size 1
==13562==    at 0x11088F: osdb_escapestr (db_op.c:93)
==13562==    by 0x1113E9: _Rules_ReadInsertDB (rules.c:178)
==13562==    by 0x1865CE: OS_ReadXMLRules (rules_op.c:861)
==13562==    by 0x1115AF: OS_InsertRulesDB (rules.c:226)
==13562==    by 0x111E8A: main (main.c:228)
==13562==  Address 0x72e23cf is 1 bytes before a block of size 1 alloc'd

According to this block from the Valgrind output, this code sequence would be the following:

https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/os_dbd/main.c#L229
https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/os_dbd/rules.c#L227
https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/shared/rules_op.c#L865
ruleact_function represents a function pointer that references _Rules_ReadInsertDB() in src/os_dbd/rules.c.
https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/os_dbd/rules.c#L179
https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/os_dbd/db_op.c#L94

An "invalid read of size 1" occurs when trying to perform a comparison on the value stored in the previous pointer position, using a simple substraction + pointer dereference. This indicates that str - 1 yields an invalid memory address.

The stored string is a duplication created through strdup() in os_LoadString():

https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/shared/mem_op.c#L94

This function can also reallocate the memory buffer to concatenate additional data to it if it is already valid. However, this is not the case.

The fact that no allocation errors are reported in the logfile and that Valgrind clearly states that the access is being performed "1 byte before a block of size 1 alloc'd", makes me think that str is, somehow, a 1-byte allocated buffer that holds a single null (\0) byte.

This would explain two things: (a) why the str - 1 substraction yields an invalid memory access after the pointer position is supposedly increased inside the loop, and (b) why an invalid memory access is not reported by Valgrind inside the while() loop in osdb_escapestr().

Truth is, even though the str pointer holds a valid memory address, the while() loop is being skipped because its condition isn't met initially - the pointer dereference *str is actually \0. A possible solution would be changing this:

https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/os_dbd/db_op.c#L78-L80

Into this:

    if (!str || !*str) {
        return;
    }

However, this would only fix the memory access issue in this function. We need to attack the real source of the problem.


Valgrind log (part 2): function that allocated the "block of size 1"

==13562==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==13562==    by 0x61239B9: strdup (strdup.c:42)
==13562==    by 0x172ABA: os_LoadString (mem_op.c:93)
==13562==    by 0x1832ED: OS_ReadXMLRules (rules_op.c:304)
==13562==    by 0x1115AF: OS_InsertRulesDB (rules.c:226)
==13562==    by 0x111E8A: main (main.c:228)

According to this block from the Valgrind output, this code sequence would be the following:

https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/os_dbd/main.c#L229
https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/os_dbd/rules.c#L227
https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/shared/rules_op.c#L304-L306
https://github.com/wazuh/wazuh/blob/688157e869f371271395da30cc490d45cd6d5753/src/shared/mem_op.c#L94

The comment member of the config_ruleinfo struct is initially set to NULL, thus making the os_LoadString() function use strdup() on it instead of reallocating the variable, just like it was mentioned before.

Even though expanding the condition in osdb_escapestr() can help avoid problems in that function, the real cause of the memory leak is here.

We need to make os_LoadString() check if the data to duplicate/concatenate is actually valid before proceeding. A slightly modified version of the code block for osdb_escapestr() should to the trick:

char *os_LoadString(char *at, const char *str)
{
    if (at == NULL) {
        if (!str || !*str) {
            return (NULL);
        }

        at = strdup(str);
        if (!at) {
            merror(MEM_ERROR, errno, strerror(errno));
        }
        return (at);
    } else { /* at is not null. Need to reallocate its memory and copy str to it */
        if (!str || !*str) {
            return (at);
        }

        char *newat;
        size_t strsize = strlen(str);
        size_t finalsize = strsize + strlen(at) + 1;

        newat = (char *) realloc(at, finalsize * sizeof(char));
        if (newat == NULL) {
            free(at);
            merror(MEM_ERROR, errno, strerror(errno));
            return (NULL);
        }
        at = newat;

        strncat(at, str, strsize);
        at[finalsize - 1] = '\0';

        return (at);
    }

    return (NULL);
}

A PR has been created to address this issue.

@DaveVG1 Thanks for reporting this problem!

@crolopez Thanks for the additional input on this matter!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

rnbwkat picture rnbwkat  路  3Comments

manuasir picture manuasir  路  3Comments

Zenidd picture Zenidd  路  3Comments

iasdeoupxe picture iasdeoupxe  路  4Comments

soulmaster43 picture soulmaster43  路  4Comments