|
|
c53a52 |
diff --git a/ChangeLog b/ChangeLog
|
|
|
c53a52 |
index d46caaa0d..41d6e99d9 100644
|
|
|
c53a52 |
--- a/ChangeLog
|
|
|
c53a52 |
+++ b/ChangeLog
|
|
|
c53a52 |
@@ -1,3 +1,8 @@
|
|
|
c53a52 |
+2020-12-08 16:24 Christos Zoulas <christos@zoulas.com>
|
|
|
c53a52 |
+
|
|
|
c53a52 |
+ * fix multithreaded decompression file descriptor issue
|
|
|
c53a52 |
+ by using close-on-exec (Denys Vlasenko)
|
|
|
c53a52 |
+
|
|
|
c53a52 |
2020-06-14 20:02 Christos Zoulas <christos@zoulas.com>
|
|
|
c53a52 |
|
|
|
c53a52 |
* release 5.39
|
|
|
c53a52 |
diff --git a/configure.ac b/configure.ac
|
|
|
c53a52 |
index 64c9f42e3..521dc12db 100644
|
|
|
c53a52 |
--- a/configure.ac
|
|
|
c53a52 |
+++ b/configure.ac
|
|
|
c53a52 |
@@ -166,7 +166,7 @@ else
|
|
|
c53a52 |
fi])
|
|
|
c53a52 |
|
|
|
c53a52 |
dnl Checks for functions
|
|
|
c53a52 |
-AC_CHECK_FUNCS(strndup mkstemp mkostemp utimes utime wcwidth strtof newlocale uselocale freelocale memmem)
|
|
|
c53a52 |
+AC_CHECK_FUNCS(strndup mkstemp mkostemp utimes utime wcwidth strtof newlocale uselocale freelocale memmem pipe2)
|
|
|
c53a52 |
|
|
|
c53a52 |
dnl Provide implementation of some required functions if necessary
|
|
|
c53a52 |
AC_REPLACE_FUNCS(getopt_long asprintf vasprintf strlcpy strlcat getline ctime_r asctime_r localtime_r gmtime_r pread strcasestr fmtcheck dprintf)
|
|
|
c53a52 |
diff --git a/src/compress.c b/src/compress.c
|
|
|
c53a52 |
index cbc2ce19b..9f65e4fa1 100644
|
|
|
c53a52 |
--- a/src/compress.c
|
|
|
c53a52 |
+++ b/src/compress.c
|
|
|
c53a52 |
@@ -35,7 +35,7 @@
|
|
|
c53a52 |
#include "file.h"
|
|
|
c53a52 |
|
|
|
c53a52 |
#ifndef lint
|
|
|
c53a52 |
-FILE_RCSID("@(#)$File: compress.c,v 1.127 2020/05/31 00:11:06 christos Exp $")
|
|
|
c53a52 |
+FILE_RCSID("@(#)$File: compress.c,v 1.129 2020/12/08 21:26:00 christos Exp $")
|
|
|
c53a52 |
#endif
|
|
|
c53a52 |
|
|
|
c53a52 |
#include "magic.h"
|
|
|
c53a52 |
@@ -844,8 +844,23 @@ uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
|
|
|
c53a52 |
for (i = 0; i < __arraycount(fdp); i++)
|
|
|
c53a52 |
fdp[i][0] = fdp[i][1] = -1;
|
|
|
c53a52 |
|
|
|
c53a52 |
- if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
|
|
|
c53a52 |
- pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
|
|
|
c53a52 |
+ /*
|
|
|
c53a52 |
+ * There are multithreaded users who run magic_file()
|
|
|
c53a52 |
+ * from dozens of threads. If two parallel magic_file() calls
|
|
|
c53a52 |
+ * analyze two large compressed files, both will spawn
|
|
|
c53a52 |
+ * an uncompressing child here, which writes out uncompressed data.
|
|
|
c53a52 |
+ * We read some portion, then close the pipe, then waitpid() the child.
|
|
|
c53a52 |
+ * If uncompressed data is larger, child shound get EPIPE and exit.
|
|
|
c53a52 |
+ * However, with *parallel* calls OTHER child may unintentionally
|
|
|
c53a52 |
+ * inherit pipe fds, thus keeping pipe open and making writes in
|
|
|
c53a52 |
+ * our child block instead of failing with EPIPE!
|
|
|
c53a52 |
+ * (For the bug to occur, two threads must mutually inherit their pipes,
|
|
|
c53a52 |
+ * and both must have large outputs. Thus it happens not that often).
|
|
|
c53a52 |
+ * To avoid this, be sure to create pipes with O_CLOEXEC.
|
|
|
c53a52 |
+ */
|
|
|
c53a52 |
+ if ((fd == -1 && file_pipe_closexec(fdp[STDIN_FILENO]) == -1) ||
|
|
|
c53a52 |
+ file_pipe_closexec(fdp[STDOUT_FILENO]) == -1 ||
|
|
|
c53a52 |
+ file_pipe_closexec(fdp[STDERR_FILENO]) == -1) {
|
|
|
c53a52 |
closep(fdp[STDIN_FILENO]);
|
|
|
c53a52 |
closep(fdp[STDOUT_FILENO]);
|
|
|
c53a52 |
return makeerror(newch, n, "Cannot create pipe, %s",
|
|
|
c53a52 |
@@ -876,16 +891,20 @@ uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
|
|
|
c53a52 |
if (fdp[STDIN_FILENO][1] > 2)
|
|
|
c53a52 |
(void) close(fdp[STDIN_FILENO][1]);
|
|
|
c53a52 |
}
|
|
|
c53a52 |
+ file_clear_closexec(STDIN_FILENO);
|
|
|
c53a52 |
+
|
|
|
c53a52 |
///FIXME: if one of the fdp[i][j] is 0 or 1, this can bomb spectacularly
|
|
|
c53a52 |
if (copydesc(STDOUT_FILENO, fdp[STDOUT_FILENO][1]))
|
|
|
c53a52 |
(void) close(fdp[STDOUT_FILENO][1]);
|
|
|
c53a52 |
if (fdp[STDOUT_FILENO][0] > 2)
|
|
|
c53a52 |
(void) close(fdp[STDOUT_FILENO][0]);
|
|
|
c53a52 |
+ file_clear_closexec(STDOUT_FILENO);
|
|
|
c53a52 |
|
|
|
c53a52 |
if (copydesc(STDERR_FILENO, fdp[STDERR_FILENO][1]))
|
|
|
c53a52 |
(void) close(fdp[STDERR_FILENO][1]);
|
|
|
c53a52 |
if (fdp[STDERR_FILENO][0] > 2)
|
|
|
c53a52 |
(void) close(fdp[STDERR_FILENO][0]);
|
|
|
c53a52 |
+ file_clear_closexec(STDERR_FILENO);
|
|
|
c53a52 |
|
|
|
c53a52 |
(void)execvp(compr[method].argv[0],
|
|
|
c53a52 |
RCAST(char *const *, RCAST(intptr_t, compr[method].argv)));
|
|
|
c53a52 |
diff --git a/src/file.h b/src/file.h
|
|
|
c53a52 |
index f00e8010b..6c3900479 100644
|
|
|
c53a52 |
--- a/src/file.h
|
|
|
c53a52 |
+++ b/src/file.h
|
|
|
c53a52 |
@@ -27,7 +27,7 @@
|
|
|
c53a52 |
*/
|
|
|
c53a52 |
/*
|
|
|
c53a52 |
* file.h - definitions for file(1) program
|
|
|
c53a52 |
- * @(#)$File: file.h,v 1.220 2020/06/08 17:38:27 christos Exp $
|
|
|
c53a52 |
+ * @(#)$File: file.h,v 1.223 2020/12/08 21:26:00 christos Exp $
|
|
|
c53a52 |
*/
|
|
|
c53a52 |
|
|
|
c53a52 |
#ifndef __file_h__
|
|
|
c53a52 |
@@ -143,6 +143,14 @@
|
|
|
c53a52 |
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
|
|
c53a52 |
#endif
|
|
|
c53a52 |
|
|
|
c53a52 |
+#ifndef O_CLOEXEC
|
|
|
c53a52 |
+# define O_CLOEXEC 0
|
|
|
c53a52 |
+#endif
|
|
|
c53a52 |
+
|
|
|
c53a52 |
+#ifndef FD_CLOEXEC
|
|
|
c53a52 |
+# define FD_CLOEXEC 1
|
|
|
c53a52 |
+#endif
|
|
|
c53a52 |
+
|
|
|
c53a52 |
#define FILE_BADSIZE CAST(size_t, ~0ul)
|
|
|
c53a52 |
#define MAXDESC 64 /* max len of text description/MIME type */
|
|
|
c53a52 |
#define MAXMIME 80 /* max len of text MIME type */
|
|
|
c53a52 |
@@ -540,6 +548,8 @@ protected char * file_printable(char *, size_t, const char *, size_t);
|
|
|
c53a52 |
protected int file_os2_apptype(struct magic_set *, const char *, const void *,
|
|
|
c53a52 |
size_t);
|
|
|
c53a52 |
#endif /* __EMX__ */
|
|
|
c53a52 |
+protected int file_pipe_closexec(int *);
|
|
|
c53a52 |
+protected int file_clear_closexec(int);
|
|
|
c53a52 |
|
|
|
c53a52 |
protected void buffer_init(struct buffer *, int, const struct stat *,
|
|
|
c53a52 |
const void *, size_t);
|
|
|
c53a52 |
diff --git a/src/funcs.c b/src/funcs.c
|
|
|
c53a52 |
index ecbfa28c5..bcf9ddaae 100644
|
|
|
c53a52 |
--- a/src/funcs.c
|
|
|
c53a52 |
+++ b/src/funcs.c
|
|
|
c53a52 |
@@ -27,7 +27,7 @@
|
|
|
c53a52 |
#include "file.h"
|
|
|
c53a52 |
|
|
|
c53a52 |
#ifndef lint
|
|
|
c53a52 |
-FILE_RCSID("@(#)$File: funcs.c,v 1.115 2020/02/20 15:50:20 christos Exp $")
|
|
|
c53a52 |
+FILE_RCSID("@(#)$File: funcs.c,v 1.118 2020/12/08 21:26:00 christos Exp $")
|
|
|
c53a52 |
#endif /* lint */
|
|
|
c53a52 |
|
|
|
c53a52 |
#include "magic.h"
|
|
|
c53a52 |
@@ -36,6 +36,9 @@ FILE_RCSID("@(#)$File: funcs.c,v 1.117 2020/06/25 16:52:48 christos Exp $")
|
|
|
c53a52 |
#include <stdlib.h>
|
|
|
c53a52 |
#include <string.h>
|
|
|
c53a52 |
#include <ctype.h>
|
|
|
c53a52 |
+#ifdef HAVE_UNISTD_H
|
|
|
c53a52 |
+#include <unistd.h> /* for pipe2() */
|
|
|
c53a52 |
+#endif
|
|
|
c53a52 |
#if defined(HAVE_WCHAR_H)
|
|
|
c53a52 |
#include <wchar.h>
|
|
|
c53a52 |
#endif
|
|
|
c53a52 |
@@ -784,3 +787,22 @@ file_print_guid(char *str, size_t len, const uint64_t *guid)
|
|
|
c53a52 |
g->data4[2], g->data4[3], g->data4[4], g->data4[5],
|
|
|
c53a52 |
g->data4[6], g->data4[7]);
|
|
|
c53a52 |
}
|
|
|
c53a52 |
+
|
|
|
c53a52 |
+protected int
|
|
|
c53a52 |
+file_pipe_closexec(int *fds)
|
|
|
c53a52 |
+{
|
|
|
c53a52 |
+#ifdef HAVE_PIPE2
|
|
|
c53a52 |
+ return pipe2(fds, O_CLOEXEC);
|
|
|
c53a52 |
+#else
|
|
|
c53a52 |
+ if (pipe(fds) == -1)
|
|
|
c53a52 |
+ return -1;
|
|
|
c53a52 |
+ (void)fcntl(fds[0], F_SETFD, FD_CLOEXEC);
|
|
|
c53a52 |
+ (void)fcntl(fds[1], F_SETFD, FD_CLOEXEC);
|
|
|
c53a52 |
+ return 0;
|
|
|
c53a52 |
+#endif
|
|
|
c53a52 |
+}
|
|
|
c53a52 |
+
|
|
|
c53a52 |
+protected int
|
|
|
c53a52 |
+file_clear_closexec(int fd) {
|
|
|
c53a52 |
+ return fcntl(fd, F_SETFD, 0);
|
|
|
c53a52 |
+}
|
|
|
c53a52 |
diff --git a/src/magic.c b/src/magic.c
|
|
|
c53a52 |
index 17a7077d8..89f4e16c0 100644
|
|
|
c53a52 |
--- a/src/magic.c
|
|
|
c53a52 |
+++ b/src/magic.c
|
|
|
c53a52 |
@@ -33,7 +33,7 @@
|
|
|
c53a52 |
#include "file.h"
|
|
|
c53a52 |
|
|
|
c53a52 |
#ifndef lint
|
|
|
c53a52 |
-FILE_RCSID("@(#)$File: magic.c,v 1.112 2020/06/08 19:44:10 christos Exp $")
|
|
|
c53a52 |
+FILE_RCSID("@(#)$File: magic.c,v 1.113 2020/12/08 21:26:00 christos Exp $")
|
|
|
c53a52 |
#endif /* lint */
|
|
|
c53a52 |
|
|
|
c53a52 |
#include "magic.h"
|
|
|
c53a52 |
@@ -436,7 +436,7 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
|
|
|
c53a52 |
_setmode(STDIN_FILENO, O_BINARY);
|
|
|
c53a52 |
#endif
|
|
|
c53a52 |
if (inname != NULL) {
|
|
|
c53a52 |
- int flags = O_RDONLY|O_BINARY|O_NONBLOCK;
|
|
|
c53a52 |
+ int flags = O_RDONLY|O_BINARY|O_NONBLOCK|O_CLOEXEC;
|
|
|
c53a52 |
errno = 0;
|
|
|
c53a52 |
if ((fd = open(inname, flags)) < 0) {
|
|
|
c53a52 |
okstat = stat(inname, &sb) == 0;
|
|
|
c53a52 |
@@ -460,6 +460,9 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
|
|
|
c53a52 |
rv = 0;
|
|
|
c53a52 |
goto done;
|
|
|
c53a52 |
}
|
|
|
c53a52 |
+#if O_CLOEXEC == 0
|
|
|
c53a52 |
+ (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
|
|
|
c53a52 |
+#endif
|
|
|
c53a52 |
}
|
|
|
c53a52 |
|
|
|
c53a52 |
if (fd != -1) {
|