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