]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
Fix: lzopen and zstdopen: don't close supplied fd
authorJaroslav Rohel <jrohel@redhat.com>
Mon, 29 Mar 2021 15:16:54 +0000 (17:16 +0200)
committerJaroslav Rohel <jrohel@redhat.com>
Tue, 6 Apr 2021 08:16:09 +0000 (10:16 +0200)
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

index a5de9e6253585dbee45dd6799ded811a4155f67d..4258fac1490607f46d6d4cc3ad6f81c66fde73e3 100644 (file)
@@ -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;
 }