a4f49babd8
Resolves: rhbz#1938793
280 lines
7.5 KiB
Diff
280 lines
7.5 KiB
Diff
From 6864aeffb0fa091dd2be1be339257825d7e80c54 Mon Sep 17 00:00:00 2001
|
|
From: Jaroslav Rohel <jrohel@redhat.com>
|
|
Date: Tue, 6 Apr 2021 09:17:27 +0200
|
|
Subject: [PATCH 1/3] Fix: Use "solv_free" for memory allocated by
|
|
"solv_calloc"
|
|
|
|
---
|
|
ext/solv_xfopen.c | 6 +++---
|
|
1 file changed, 3 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/ext/solv_xfopen.c b/ext/solv_xfopen.c
|
|
index b3136cbb..a5de9e62 100644
|
|
--- a/ext/solv_xfopen.c
|
|
+++ b/ext/solv_xfopen.c
|
|
@@ -199,7 +199,7 @@ static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
|
|
if (ret != LZMA_OK)
|
|
{
|
|
fclose(fp);
|
|
- free(lzfile);
|
|
+ solv_free(lzfile);
|
|
return 0;
|
|
}
|
|
return lzfile;
|
|
@@ -232,7 +232,7 @@ static int lzclose(void *cookie)
|
|
}
|
|
lzma_end(&lzfile->strm);
|
|
rc = fclose(lzfile->file);
|
|
- free(lzfile);
|
|
+ solv_free(lzfile);
|
|
return rc;
|
|
}
|
|
|
|
@@ -432,7 +432,7 @@ static int zstdclose(void *cookie)
|
|
ZSTD_freeDStream(zstdfile->dstream);
|
|
}
|
|
rc = fclose(zstdfile->file);
|
|
- free(zstdfile);
|
|
+ solv_free(zstdfile);
|
|
return rc;
|
|
}
|
|
|
|
|
|
From ee8b8b9d72b816950e411ed26063c3a000b396ed Mon Sep 17 00:00:00 2001
|
|
From: Jaroslav Rohel <jrohel@redhat.com>
|
|
Date: Mon, 29 Mar 2021 17:16:54 +0200
|
|
Subject: [PATCH 2/3] Fix: lzopen and zstdopen: don't close supplied fd
|
|
|
|
In the case of failure of some functions, the `fp` file stream has been
|
|
closed. And the stream closed the associated supplied `fd` file descriptor.
|
|
|
|
The caller then closed the closed descriptor again (eg `curlfopen` in
|
|
`repoinfo_download.c`: `if (!Fp) close (fd);`) -> double_close.
|
|
In multithreaded software risk of race conditions. Another thread open
|
|
another file and reuse just closed file descriptor. The caller
|
|
then closes the file of another thread.
|
|
---
|
|
ext/solv_xfopen.c | 45 ++++++++++++++++++++++++++-------------------
|
|
1 file changed, 26 insertions(+), 19 deletions(-)
|
|
|
|
diff --git a/ext/solv_xfopen.c b/ext/solv_xfopen.c
|
|
index a5de9e62..4258fac1 100644
|
|
--- a/ext/solv_xfopen.c
|
|
+++ b/ext/solv_xfopen.c
|
|
@@ -165,7 +165,7 @@ static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
|
|
LZFILE *lzfile;
|
|
lzma_ret ret;
|
|
|
|
- if (!path && fd < 0)
|
|
+ if ((!path && fd < 0) || (path && fd >= 0))
|
|
return 0;
|
|
for (; *mode; mode++)
|
|
{
|
|
@@ -176,14 +176,7 @@ static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
|
|
else if (*mode >= '1' && *mode <= '9')
|
|
level = *mode - '0';
|
|
}
|
|
- if (fd != -1)
|
|
- fp = fdopen(fd, encoding ? "w" : "r");
|
|
- else
|
|
- fp = fopen(path, encoding ? "w" : "r");
|
|
- if (!fp)
|
|
- return 0;
|
|
lzfile = solv_calloc(1, sizeof(*lzfile));
|
|
- lzfile->file = fp;
|
|
lzfile->encoding = encoding;
|
|
lzfile->eof = 0;
|
|
lzfile->strm = stream_init;
|
|
@@ -198,10 +191,20 @@ static LZFILE *lzopen(const char *path, const char *mode, int fd, int isxz)
|
|
ret = lzma_auto_decoder(&lzfile->strm, 100 << 20, 0);
|
|
if (ret != LZMA_OK)
|
|
{
|
|
- fclose(fp);
|
|
solv_free(lzfile);
|
|
return 0;
|
|
}
|
|
+ if (!path)
|
|
+ fp = fdopen(fd, encoding ? "w" : "r");
|
|
+ else
|
|
+ fp = fopen(path, encoding ? "w" : "r");
|
|
+ if (!fp)
|
|
+ {
|
|
+ lzma_end(&lzfile->strm);
|
|
+ solv_free(lzfile);
|
|
+ return 0;
|
|
+ }
|
|
+ lzfile->file = fp;
|
|
return lzfile;
|
|
}
|
|
|
|
@@ -346,7 +349,7 @@ static ZSTDFILE *zstdopen(const char *path, const char *mode, int fd)
|
|
FILE *fp;
|
|
ZSTDFILE *zstdfile;
|
|
|
|
- if (!path && fd < 0)
|
|
+ if ((!path && fd < 0) || (path && fd >= 0))
|
|
return 0;
|
|
for (; *mode; mode++)
|
|
{
|
|
@@ -357,12 +360,6 @@ static ZSTDFILE *zstdopen(const char *path, const char *mode, int fd)
|
|
else if (*mode >= '1' && *mode <= '9')
|
|
level = *mode - '0';
|
|
}
|
|
- if (fd != -1)
|
|
- fp = fdopen(fd, encoding ? "w" : "r");
|
|
- else
|
|
- fp = fopen(path, encoding ? "w" : "r");
|
|
- if (!fp)
|
|
- return 0;
|
|
zstdfile = solv_calloc(1, sizeof(*zstdfile));
|
|
zstdfile->encoding = encoding;
|
|
if (encoding)
|
|
@@ -372,14 +369,12 @@ static ZSTDFILE *zstdopen(const char *path, const char *mode, int fd)
|
|
if (!zstdfile->cstream)
|
|
{
|
|
solv_free(zstdfile);
|
|
- fclose(fp);
|
|
return 0;
|
|
}
|
|
if (ZSTD_isError(ZSTD_initCStream(zstdfile->cstream, level)))
|
|
{
|
|
ZSTD_freeCStream(zstdfile->cstream);
|
|
solv_free(zstdfile);
|
|
- fclose(fp);
|
|
return 0;
|
|
}
|
|
zstdfile->out.dst = zstdfile->buf;
|
|
@@ -393,13 +388,25 @@ static ZSTDFILE *zstdopen(const char *path, const char *mode, int fd)
|
|
{
|
|
ZSTD_freeDStream(zstdfile->dstream);
|
|
solv_free(zstdfile);
|
|
- fclose(fp);
|
|
return 0;
|
|
}
|
|
zstdfile->in.src = zstdfile->buf;
|
|
zstdfile->in.pos = 0;
|
|
zstdfile->in.size = 0;
|
|
}
|
|
+ if (!path)
|
|
+ fp = fdopen(fd, encoding ? "w" : "r");
|
|
+ else
|
|
+ fp = fopen(path, encoding ? "w" : "r");
|
|
+ if (!fp)
|
|
+ {
|
|
+ if (encoding)
|
|
+ ZSTD_freeCStream(zstdfile->cstream);
|
|
+ else
|
|
+ ZSTD_freeDStream(zstdfile->dstream);
|
|
+ solv_free(zstdfile);
|
|
+ return 0;
|
|
+ }
|
|
zstdfile->file = fp;
|
|
return zstdfile;
|
|
}
|
|
|
|
From 725778574dda14dfa646f9a3f97568b15cdcbb2e Mon Sep 17 00:00:00 2001
|
|
From: Jaroslav Rohel <jrohel@redhat.com>
|
|
Date: Tue, 30 Mar 2021 08:42:31 +0200
|
|
Subject: [PATCH 3/3] Fix: zchunkopen: resources leaks, don't close supplied fd
|
|
|
|
System variant:
|
|
- resource leaks when `zck_init_read` or `zck_init_write` fails
|
|
- supplied fd will be closed if `zck_create` fails
|
|
|
|
Libsolv limited zchunk implementation:
|
|
- resource leak when `strcmp(mode, "r") != 0`
|
|
- supplied fd will be closed if `solv_zchunk_open` fails (Fix is thread
|
|
unsafe. However the original version caused a double-close in the caller
|
|
function and was thread unsafe too.)
|
|
---
|
|
ext/solv_xfopen.c | 44 ++++++++++++++++++++++++++++++++++----------
|
|
1 file changed, 34 insertions(+), 10 deletions(-)
|
|
|
|
diff --git a/ext/solv_xfopen.c b/ext/solv_xfopen.c
|
|
index 4258fac1..7dca41f0 100644
|
|
--- a/ext/solv_xfopen.c
|
|
+++ b/ext/solv_xfopen.c
|
|
@@ -548,9 +548,9 @@ static void *zchunkopen(const char *path, const char *mode, int fd)
|
|
{
|
|
zckCtx *f;
|
|
|
|
- if (!path && fd < 0)
|
|
+ if ((!path && fd < 0) || (path && fd >= 0))
|
|
return 0;
|
|
- if (fd == -1)
|
|
+ if (path)
|
|
{
|
|
if (*mode != 'w')
|
|
fd = open(path, O_RDONLY);
|
|
@@ -562,18 +562,29 @@ static void *zchunkopen(const char *path, const char *mode, int fd)
|
|
f = zck_create();
|
|
if (!f)
|
|
{
|
|
- close(fd);
|
|
+ if (path)
|
|
+ close(fd);
|
|
return 0;
|
|
}
|
|
if (*mode != 'w')
|
|
{
|
|
if(!zck_init_read(f, fd))
|
|
- return 0;
|
|
+ {
|
|
+ zck_free(&f);
|
|
+ if (path)
|
|
+ close(fd);
|
|
+ return 0;
|
|
+ }
|
|
}
|
|
else
|
|
{
|
|
if(!zck_init_write(f, fd))
|
|
- return 0;
|
|
+ {
|
|
+ zck_free(&f);
|
|
+ if (path)
|
|
+ close(fd);
|
|
+ return 0;
|
|
+ }
|
|
}
|
|
return cookieopen(f, mode, cookie_zckread, cookie_zckwrite, cookie_zckclose);
|
|
}
|
|
@@ -587,19 +598,32 @@ static void *zchunkopen(const char *path, const char *mode, int fd)
|
|
{
|
|
FILE *fp;
|
|
void *f;
|
|
- if (!path && fd < 0)
|
|
+ int tmpfd;
|
|
+ if ((!path && fd < 0) || (path && fd >= 0))
|
|
return 0;
|
|
- if (fd != -1)
|
|
+ if (strcmp(mode, "r") != 0)
|
|
+ return 0;
|
|
+ if (!path)
|
|
fp = fdopen(fd, mode);
|
|
else
|
|
fp = fopen(path, mode);
|
|
if (!fp)
|
|
return 0;
|
|
- if (strcmp(mode, "r") != 0)
|
|
- return 0;
|
|
f = solv_zchunk_open(fp, 1);
|
|
if (!f)
|
|
- fclose(fp);
|
|
+ {
|
|
+ /* When 0 is returned, fd passed by user must not be closed! */
|
|
+ /* Dup (save) the original fd to a temporary variable and then back. */
|
|
+ /* It is ugly and thread unsafe hack (non atomical sequence fclose dup2). */
|
|
+ if (!path)
|
|
+ tmpfd = dup(fd);
|
|
+ fclose(fp);
|
|
+ if (!path)
|
|
+ {
|
|
+ dup2(tmpfd, fd);
|
|
+ close(tmpfd);
|
|
+ }
|
|
+ }
|
|
return cookieopen(f, mode, (ssize_t (*)(void *, char *, size_t))solv_zchunk_read, 0, (int (*)(void *))solv_zchunk_close);
|
|
}
|
|
|