From: Jaroslav Rohel Date: Mon, 29 Mar 2021 15:16:54 +0000 (+0200) Subject: Fix: lzopen and zstdopen: don't close supplied fd X-Git-Tag: 0.7.19~2^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ee8b8b9d72b816950e411ed26063c3a000b396ed;p=thirdparty%2Flibsolv.git 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. --- 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; }