On Sat, Apr 25, 2020 at 01:28:33AM +0200, Mark Wielaard wrote:
Hi,
On Fri, Mar 20, 2020 at 12:17:55PM +0100, Matthias Maennich via Elfutils-devel
wrote:
__libelf_decompress would only cleanup zlib resources via inflateEnd()
in case inflating was successful, but would leak memory if not. Fix this
by calling inflateEnd() unconditionally.
__libelf_decompress did this all the time already, but called
deflateEnd() twice. That is not a (known) issue, but can be cleaned up
by ensuring all error paths use 'return deflate_cleanup' and the success
path calls deflateEnd() only once. Note, the deflate() needs to return
Z_STREAM_END to indicate we are done. Hence change the condition.
Fixes: 272018bba1f2 ("libelf: Add elf_compress and elf_compress_gnu.")
Signed-off-by: Matthias Maennich <maenn...@google.com>
---
libelf/elf_compress.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c
index 244467b5e3ae..b1b896890ff7 100644
--- a/libelf/elf_compress.c
+++ b/libelf/elf_compress.c
@@ -115,7 +115,7 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
{
free (out_buf);
__libelf_seterrno (ELF_E_COMPRESS_ERROR);
- return NULL;
+ return deflate_cleanup(NULL, NULL);
}
I was sure this was correct. But we both missed that deflate_cleanup
is a macro that passes out_buf and frees it. So now it is freed
twice... Oops.
GCC10 (not released yet, but already in Fedora 32 beta) has a new
-fanalyzer option which does catch this:
elf_compress.c: In function ‘__libelf_compress’:
elf_compress.c:50:3: error: double-‘free’ of ‘out_buf’ [CWE-415]
[-Werror=analyzer-double-free]
50 | free (out_buf);
| ^~~~~~~~~~~~~~
‘__libelf_compress’: events 1-10
|
| 50 | free (out_buf);
| | ~~~~~~~~~~~~~~
| | |
| | (10) second ‘free’ here; first ‘free’ was at (9)
|......
| 79 | if (data == NULL)
| | ^
| | |
| | (1) following ‘false’ branch (when ‘data’ is non-NULL)...
|......
| 86 | Elf_Data *next_data = elf_getdata (scn, data);
| | ~~~~~~~~
| | |
| | (2) ...to here
|......
| 91 | *orig_addralign = data->d_align;
| | ~
| | |
| | (3) allocated here
|......
| 100 | if (out_buf == NULL)
| | ~
| | |
| | (4) assuming ‘out_buf’ is non-NULL
| | (5) following ‘false’ branch (when ‘out_buf’ is non-NULL)...
|......
| 107 | size_t used = hsize;
| | ~~~~~~
| | |
| | (6) ...to here
|......
| 114 | if (zrc != Z_OK)
| | ~
| | |
| | (7) following ‘true’ branch (when ‘zrc != 0’)...
| 115 | {
| 116 | free (out_buf);
| | ~~~~
| | |
| | (8) ...to here
| | (9) first ‘free’ here
|
Fixed by removing the free (out_buf) on line 116 as attached.
Hi Mark!
Thanks for catching and fixing that!
Cheers,
Mark
From 0b2fc95c46dabf85d053b2f0c6aab217b9c5a9b8 Mon Sep 17 00:00:00 2001
From: Mark Wielaard <m...@klomp.org>
Date: Sat, 25 Apr 2020 01:21:12 +0200
Subject: [PATCH] libelf: Fix double free in __libelf_compress on error path.
In commit 2092865a7e589ff805caa47e69ac9630f34d4f2a
"libelf: {de,}compress: ensure zlib resource cleanup" we added a
call to deflate_cleanup to make sure all resources were freed.
As GCC10 -fanalyzer points out that could cause a double free
of out_buf. Fix by removing the free (out_buf) in __libelf_compress.
Signed-off-by: Mark Wielaard <m...@klomp.org>
---
libelf/ChangeLog | 4 ++++
libelf/elf_compress.c | 1 -
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 8f79a625..56f5354c 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,7 @@
+2020-04-25 Mark Wielaard <m...@klomp.org>
+
+ * elf_compress.c (__libelf_compress): Remove free (out_buf).
+
2020-03-18 Omar Sandoval <osan...@fb.com>
* elf_getphdrnum.c (__elf_getphdrnum_rdlock): Call
diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c
index b1b89689..e5d3d2e0 100644
--- a/libelf/elf_compress.c
+++ b/libelf/elf_compress.c
@@ -113,7 +113,6 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
int zrc = deflateInit (&z, Z_BEST_COMPRESSION);
if (zrc != Z_OK)
{
- free (out_buf);
Maybe add a comment to the deflate_cleanup macro call then?
Cheers,
Matthias
__libelf_seterrno (ELF_E_COMPRESS_ERROR);
return deflate_cleanup(NULL, NULL);
}
--
2.26.0