[PATCH v2] libelf: {de,}compress: ensure zlib resource cleanup

2020-03-20 Thread Matthias Maennich via Elfutils-devel
__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 
---
 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);
 }
 
   Elf_Data cdata;
@@ -197,13 +197,13 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int 
ei_data,
 }
   while (flush != Z_FINISH); /* More data blocks.  */
 
-  zrc = deflateEnd (&z);
-  if (zrc != Z_OK)
+  if (zrc != Z_STREAM_END)
 {
   __libelf_seterrno (ELF_E_COMPRESS_ERROR);
   return deflate_cleanup (NULL, NULL);
 }
 
+  deflateEnd (&z);
   *new_size = used;
   return out_buf;
 }
@@ -251,16 +251,15 @@ __libelf_decompress (void *buf_in, size_t size_in, size_t 
size_out)
}
   zrc = inflateReset (&z);
 }
-  if (likely (zrc == Z_OK))
-zrc = inflateEnd (&z);
 
   if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0))
 {
   free (buf_out);
+  buf_out = NULL;
   __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
-  return NULL;
 }
 
+  inflateEnd(&z);
   return buf_out;
 }
 
-- 
2.25.1.696.g5e7596f4ac-goog



Re: [PATCH v2] libelf: {de,}compress: ensure zlib resource cleanup

2020-03-20 Thread Mark Wielaard
Hi Matthias,

On Fri, 2020-03-20 at 12:17 +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.

It was that last condition I had missed.
Added a ChangeLog entry and pushed to master.

Thanks,

Mark


Re: [PATCH] libelf: handle PN_XNUM in elf_getphdrnum before shdr 0 is cached

2020-03-20 Thread Mark Wielaard
Hi Omar,

On Wed, Mar 18, 2020 at 01:18:51PM -0700, Omar Sandoval wrote:
> __elf_getphdrnum_rdlock() handles PN_XNUM by getting sh_info from
> elf->state.elf{32,64}.scns.data[0].shdr.e{32,64}. However, that is only
> a cache that may or may not have been populated by elf_begin() or
> elf{32,64}_getshdr(); if it hasn't been cached yet, elf_getphdrnum()
> returns 65535 (the value of PN_XNUM) instead. We should explicitly get
> the shdr if it isn't cached.

I believe this analysis is correct. But how did you find this?  This
seems to only happen if e_phnum was PN_XNUM and for some reason the
scns cache wasn't initialized. Do you happen to have a testcase?

Thanks,

Mark


PR25369 rfc slice 2: debuginfod get_url

2020-03-20 Thread Frank Ch. Eigler via Elfutils-devel
Hi -

Slice 2/3, the debuginfod_client get_url function.  This new
version works during or after the progressfn callback.

Author: Frank Ch. Eigler 
Date:   Fri Mar 20 21:33:52 2020 -0400

debuginfod client API: add get_url function

This function lets a client know, during or after a progressfn
callback, what the url of the winning outgoing download is/was.

Signed-off-by: Frank Ch. Eigler 

diff --git a/debuginfod/debuginfod-client.c b/debuginfod/debuginfod-client.c
index 2730dbf7aee5..2a1c267b712c 100644
--- a/debuginfod/debuginfod-client.c
+++ b/debuginfod/debuginfod-client.c
@@ -82,6 +82,9 @@ struct debuginfod_client
   /* Stores user data. */
   void* user_data;
 
+  /* Stores current/last url. */
+  char url[PATH_MAX];
+
   /* Can contain all other context, like cache_path, server_urls,
  timeout or other info gotten from environment variables, the
  handle data, etc. So those don't have to be reparsed and
@@ -128,6 +131,9 @@ struct handle_data
   /* This handle.  */
   CURL *handle;
 
+  /* The client object whom we're serving. */
+  debuginfod_client *client;
+
   /* Pointer to handle that should write to fd. Initially points to NULL,
  then points to the first handle that begins writing the target file
  to the cache. Used to ensure that a file is not downloaded from
@@ -144,7 +150,11 @@ debuginfod_write_callback (char *ptr, size_t size, size_t 
nmemb, void *data)
 
   /* Indicate to other handles that they can abort their transfer.  */
   if (*d->target_handle == NULL)
-*d->target_handle = d->handle;
+{
+  *d->target_handle = d->handle;
+  /* update the client object */
+  strncpy(d->client->url, d->url, sizeof(d->client->url));
+}
 
   /* If this handle isn't the target handle, abort transfer.  */
   if (*d->target_handle != d->handle)
@@ -410,6 +420,9 @@ debuginfod_query_server (debuginfod_client *c,
   char build_id_bytes[MAX_BUILD_ID_BYTES * 2 + 1];
   int rc;
 
+  /* Clear the saved url. */
+  c->url[0] = '\0';
+
   /* Is there any server we can query?  If not, don't do any work,
  just return with ENOSYS.  Don't even access the cache.  */
   urls_envvar = getenv(server_urls_envvar);
@@ -620,6 +633,7 @@ debuginfod_query_server (debuginfod_client *c,
   data[i].fd = fd;
   data[i].target_handle = &target_handle;
   data[i].handle = curl_easy_init();
+  data[i].client = c;
 
   if (data[i].handle == NULL)
 {
@@ -877,12 +891,20 @@ debuginfod_query_server (debuginfod_client *c,
 static int
 default_progressfn (debuginfod_client *c, long a, long b)
 {
-  (void) c;
-
-  dprintf(STDERR_FILENO,
-  "Downloading from debuginfod %ld/%ld%s", a, b,
-  ((a == b) ? "\n" : "\r"));
-  /* XXX: include URL - stateful */
+  const char* url = debuginfod_get_url (c);
+  assert (url != NULL); /* undocumented guarantee, might change later */
+
+  if (b == 0 || url[0]=='\0') /* early stage */
+dprintf(STDERR_FILENO,
+"Downloading %c\r", "-/|\\"[a % 4]);
+  else if (b < 0) /* download in progress but unknown total length */
+dprintf(STDERR_FILENO,
+"Downloading %s %ld\r",
+url, a);
+  else /* download in progress, and known total length */
+dprintf(STDERR_FILENO,
+"Downloading %s %ld/%ld\r",
+url, a, b);
 
   return 0;
 }
@@ -894,13 +916,11 @@ debuginfod_begin (void)
 {
   debuginfod_client *client;
   size_t size = sizeof (struct debuginfod_client);
-  client = (debuginfod_client *) malloc (size);
+  client = (debuginfod_client *) calloc (1, size);
   if (client != NULL)
 {
   if (getenv(DEBUGINFOD_PROGRESS_ENV_VAR))
client->progressfn = default_progressfn;
-  else
-   client->progressfn = NULL;
 }
   return client;
 }
@@ -918,6 +938,12 @@ debuginfod_get_user_data(debuginfod_client *client)
   return client->user_data;
 }
 
+const char *
+debuginfod_get_url(debuginfod_client *client)
+{
+  return client->url;
+}
+
 void
 debuginfod_end (debuginfod_client *client)
 {
diff --git a/debuginfod/debuginfod.h b/debuginfod/debuginfod.h
index fe72f16e9bd8..2ace5f350488 100644
--- a/debuginfod/debuginfod.h
+++ b/debuginfod/debuginfod.h
@@ -81,6 +81,9 @@ void debuginfod_set_user_data (debuginfod_client *client, 
void *value);
 /* Get the user parameter.  */
 void* debuginfod_get_user_data (debuginfod_client *client);
 
+/* Get the current or last active URL, if known.  */
+const char* debuginfod_get_url (debuginfod_client *client);
+
 /* Release debuginfod client connection context handle.  */
 void debuginfod_end (debuginfod_client *client);
 
diff --git a/debuginfod/libdebuginfod.map b/debuginfod/libdebuginfod.map
index a919630dacce..d84e8924f7f8 100644
--- a/debuginfod/libdebuginfod.map
+++ b/debuginfod/libdebuginfod.map
@@ -12,4 +12,5 @@ ELFUTILS_0.179 {
   global:
   debuginfod_set_user_data;
   debuginfod_get_user_data;
+  debuginfod_get_url;
 };
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 87d1fee03302.