On Thu, Mar 27, 2025 at 04:51:46PM +0530, shivam tiwari wrote:
> Dear Wget Developers,
> 
> This patch fixes a Heap-use-after-free vulnerability in the
> hash_table_destroy function.

Note:

    diff --git a/src/hash.c b/src/hash.c
    index 670ec1cf..00e07eef 100644
    --- a/src/hash.c
    +++ b/src/hash.c
    @@ -305,8 +305,13 @@ hash_table_new (int items,
     void
     hash_table_destroy (struct hash_table *ht)
     {
    -  xfree (ht->cells);
    -  xfree (ht);
    +  if (ht)
    +  {
    +    xfree (ht->cells);
    +    ht->cells = NULL;
    +    xfree (ht);
    +    ht = NULL;
    +  }
     }

The line:

    ht = NULL;

is ineffectual.  In this function, ht is a local (function scope) copy
of the pointer.  For the intended thing to happen, you need this:

void
hash_table_destroy(struct hash_table **ht)
{
    if (ht && *ht)
    {
        xfree(*ht->cells);
        *ht->cells = NULL;
        xfree(*ht);
        *ht = NULL;
    }
}

And then everywhere it's called, you need to change:

    struct hash_table *foo;
    ...
    hash_table_destroy(foo);
    
to:

    hash_table_destroy(&foo);

Alternatively, you could remove the assignment, and use a macro
similar to:

#define hash_table_free(htp) do { hash_table destroy(htp); htp = NULL; } while 
(0);

(The solution with the least code changes would be to rename the
function and give the macro its original name...)


And for the sake of completeness, a short example to demonstrate this:

$ cat free.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

struct hash_table {
    void *cells;
};

void hash_table_destroy(struct hash_table *ht)
{
    if (ht)
    {
        free(ht->cells);
        /* don't need to check ht->cells, free(NULL) is a no-op on all 
non-broken systems */
        ht->cells = NULL;
        free(ht);
        ht = NULL;
    }
}

int main(int argc, char **argv)
{
    struct hash_table *foo;
    foo = (struct hash_table *)malloc(sizeof *foo);
    foo->cells = NULL;
    printf("Address of *foo is %p\n", foo);
    hash_table_destroy(foo);
    printf("Address of *foo is %p\n", foo);
    return 0;
}

$ gcc -o free free.c
$ ./free
Address of *foo is 0x6243cfb262a0
Address of *foo is 0x6243cfb262a0



Reply via email to