summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-devtools/file/file_5.39.bb3
-rw-r--r--meta/recipes-devtools/file/files/0001-Fix-close_on_exec-multithreaded-decompression-issue.patch220
2 files changed, 222 insertions, 1 deletions
diff --git a/meta/recipes-devtools/file/file_5.39.bb b/meta/recipes-devtools/file/file_5.39.bb
index abaa8149a3..c0c7253688 100644
--- a/meta/recipes-devtools/file/file_5.39.bb
+++ b/meta/recipes-devtools/file/file_5.39.bb
@@ -12,7 +12,8 @@ DEPENDS = "file-replacement-native"
12DEPENDS_class-native = "bzip2-replacement-native" 12DEPENDS_class-native = "bzip2-replacement-native"
13 13
14SRC_URI = "git://github.com/file/file.git \ 14SRC_URI = "git://github.com/file/file.git \
15 file://0001-src-compress.c-correct-header-define-for-xz-lzma.patch" 15 file://0001-src-compress.c-correct-header-define-for-xz-lzma.patch \
16 file://0001-Fix-close_on_exec-multithreaded-decompression-issue.patch"
16 17
17SRCREV = "87731415de945660b00f02207d8e9d986ef9b82e" 18SRCREV = "87731415de945660b00f02207d8e9d986ef9b82e"
18S = "${WORKDIR}/git" 19S = "${WORKDIR}/git"
diff --git a/meta/recipes-devtools/file/files/0001-Fix-close_on_exec-multithreaded-decompression-issue.patch b/meta/recipes-devtools/file/files/0001-Fix-close_on_exec-multithreaded-decompression-issue.patch
new file mode 100644
index 0000000000..42105feed9
--- /dev/null
+++ b/meta/recipes-devtools/file/files/0001-Fix-close_on_exec-multithreaded-decompression-issue.patch
@@ -0,0 +1,220 @@
1From 0d82f2f3ba4a856504f23a9db1dd5f37bd076337 Mon Sep 17 00:00:00 2001
2From: Changqing Li <changqing.li@windriver.com>
3Date: Mon, 23 Aug 2021 14:16:53 +0800
4Subject: [PATCH] Fix close_on_exec multithreaded decompression issue.
5
6Upstream-Status: Backport [https://github.com/file/file/commit/81f15c2b0d6e9eaf524ff7bab37426c21af75fb7]
7Signed-off-by: Changqing Li <changqing.li@windriver.com>
8---
9 ChangeLog | 5 +++++
10 configure.ac | 2 +-
11 src/compress.c | 25 ++++++++++++++++++++++---
12 src/file.h | 12 +++++++++++-
13 src/funcs.c | 24 +++++++++++++++++++++++-
14 src/magic.c | 7 +++++--
15 6 files changed, 67 insertions(+), 8 deletions(-)
16
17diff --git a/ChangeLog b/ChangeLog
18index f877ad22..8c4a43d4 100644
19--- a/ChangeLog
20+++ b/ChangeLog
21@@ -1,3 +1,8 @@
22+2020-12-08 16:24 Christos Zoulas <christos@zoulas.com>
23+
24+ * fix multithreaded decompression file descriptor issue
25+ by using close-on-exec (Denys Vlasenko)
26+
27 2020-06-14 20:02 Christos Zoulas <christos@zoulas.com>
28
29 * release 5.39
30diff --git a/configure.ac b/configure.ac
31index 64c9f42e..521dc12d 100644
32--- a/configure.ac
33+++ b/configure.ac
34@@ -166,7 +166,7 @@ else
35 fi])
36
37 dnl Checks for functions
38-AC_CHECK_FUNCS(strndup mkstemp mkostemp utimes utime wcwidth strtof newlocale uselocale freelocale memmem)
39+AC_CHECK_FUNCS(strndup mkstemp mkostemp utimes utime wcwidth strtof newlocale uselocale freelocale memmem pipe2)
40
41 dnl Provide implementation of some required functions if necessary
42 AC_REPLACE_FUNCS(getopt_long asprintf vasprintf strlcpy strlcat getline ctime_r asctime_r localtime_r gmtime_r pread strcasestr fmtcheck dprintf)
43diff --git a/src/compress.c b/src/compress.c
44index 9670b72c..9f65e4fa 100644
45--- a/src/compress.c
46+++ b/src/compress.c
47@@ -35,7 +35,7 @@
48 #include "file.h"
49
50 #ifndef lint
51-FILE_RCSID("@(#)$File: compress.c,v 1.127 2020/05/31 00:11:06 christos Exp $")
52+FILE_RCSID("@(#)$File: compress.c,v 1.129 2020/12/08 21:26:00 christos Exp $")
53 #endif
54
55 #include "magic.h"
56@@ -844,8 +844,23 @@ uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
57 for (i = 0; i < __arraycount(fdp); i++)
58 fdp[i][0] = fdp[i][1] = -1;
59
60- if ((fd == -1 && pipe(fdp[STDIN_FILENO]) == -1) ||
61- pipe(fdp[STDOUT_FILENO]) == -1 || pipe(fdp[STDERR_FILENO]) == -1) {
62+ /*
63+ * There are multithreaded users who run magic_file()
64+ * from dozens of threads. If two parallel magic_file() calls
65+ * analyze two large compressed files, both will spawn
66+ * an uncompressing child here, which writes out uncompressed data.
67+ * We read some portion, then close the pipe, then waitpid() the child.
68+ * If uncompressed data is larger, child shound get EPIPE and exit.
69+ * However, with *parallel* calls OTHER child may unintentionally
70+ * inherit pipe fds, thus keeping pipe open and making writes in
71+ * our child block instead of failing with EPIPE!
72+ * (For the bug to occur, two threads must mutually inherit their pipes,
73+ * and both must have large outputs. Thus it happens not that often).
74+ * To avoid this, be sure to create pipes with O_CLOEXEC.
75+ */
76+ if ((fd == -1 && file_pipe_closexec(fdp[STDIN_FILENO]) == -1) ||
77+ file_pipe_closexec(fdp[STDOUT_FILENO]) == -1 ||
78+ file_pipe_closexec(fdp[STDERR_FILENO]) == -1) {
79 closep(fdp[STDIN_FILENO]);
80 closep(fdp[STDOUT_FILENO]);
81 return makeerror(newch, n, "Cannot create pipe, %s",
82@@ -876,16 +891,20 @@ uncompressbuf(int fd, size_t bytes_max, size_t method, const unsigned char *old,
83 if (fdp[STDIN_FILENO][1] > 2)
84 (void) close(fdp[STDIN_FILENO][1]);
85 }
86+ file_clear_closexec(STDIN_FILENO);
87+
88 ///FIXME: if one of the fdp[i][j] is 0 or 1, this can bomb spectacularly
89 if (copydesc(STDOUT_FILENO, fdp[STDOUT_FILENO][1]))
90 (void) close(fdp[STDOUT_FILENO][1]);
91 if (fdp[STDOUT_FILENO][0] > 2)
92 (void) close(fdp[STDOUT_FILENO][0]);
93+ file_clear_closexec(STDOUT_FILENO);
94
95 if (copydesc(STDERR_FILENO, fdp[STDERR_FILENO][1]))
96 (void) close(fdp[STDERR_FILENO][1]);
97 if (fdp[STDERR_FILENO][0] > 2)
98 (void) close(fdp[STDERR_FILENO][0]);
99+ file_clear_closexec(STDERR_FILENO);
100
101 (void)execvp(compr[method].argv[0],
102 RCAST(char *const *, RCAST(intptr_t, compr[method].argv)));
103diff --git a/src/file.h b/src/file.h
104index 28ebc0c1..48f4b698 100644
105--- a/src/file.h
106+++ b/src/file.h
107@@ -27,7 +27,7 @@
108 */
109 /*
110 * file.h - definitions for file(1) program
111- * @(#)$File: file.h,v 1.220 2020/06/08 17:38:27 christos Exp $
112+ * @(#)$File: file.h,v 1.223 2020/12/08 21:26:00 christos Exp $
113 */
114
115 #ifndef __file_h__
116@@ -143,6 +143,14 @@
117 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
118 #endif
119
120+#ifndef O_CLOEXEC
121+# define O_CLOEXEC 0
122+#endif
123+
124+#ifndef FD_CLOEXEC
125+# define FD_CLOEXEC 1
126+#endif
127+
128 #define FILE_BADSIZE CAST(size_t, ~0ul)
129 #define MAXDESC 64 /* max len of text description/MIME type */
130 #define MAXMIME 80 /* max len of text MIME type */
131@@ -538,6 +546,8 @@ protected char * file_printable(char *, size_t, const char *, size_t);
132 protected int file_os2_apptype(struct magic_set *, const char *, const void *,
133 size_t);
134 #endif /* __EMX__ */
135+protected int file_pipe_closexec(int *);
136+protected int file_clear_closexec(int);
137
138 protected void buffer_init(struct buffer *, int, const struct stat *,
139 const void *, size_t);
140diff --git a/src/funcs.c b/src/funcs.c
141index b66510c6..d6c485fe 100644
142--- a/src/funcs.c
143+++ b/src/funcs.c
144@@ -27,7 +27,7 @@
145 #include "file.h"
146
147 #ifndef lint
148-FILE_RCSID("@(#)$File: funcs.c,v 1.115 2020/02/20 15:50:20 christos Exp $")
149+FILE_RCSID("@(#)$File: funcs.c,v 1.118 2020/12/08 21:26:00 christos Exp $")
150 #endif /* lint */
151
152 #include "magic.h"
153@@ -36,6 +36,9 @@ FILE_RCSID("@(#)$File: funcs.c,v 1.115 2020/02/20 15:50:20 christos Exp $")
154 #include <stdlib.h>
155 #include <string.h>
156 #include <ctype.h>
157+#ifdef HAVE_UNISTD_H
158+#include <unistd.h> /* for pipe2() */
159+#endif
160 #if defined(HAVE_WCHAR_H)
161 #include <wchar.h>
162 #endif
163@@ -783,3 +786,22 @@ file_print_guid(char *str, size_t len, const uint64_t *guid)
164 g->data4[2], g->data4[3], g->data4[4], g->data4[5],
165 g->data4[6], g->data4[7]);
166 }
167+
168+protected int
169+file_pipe_closexec(int *fds)
170+{
171+#ifdef HAVE_PIPE2
172+ return pipe2(fds, O_CLOEXEC);
173+#else
174+ if (pipe(fds) == -1)
175+ return -1;
176+ (void)fcntl(fds[0], F_SETFD, FD_CLOEXEC);
177+ (void)fcntl(fds[1], F_SETFD, FD_CLOEXEC);
178+ return 0;
179+#endif
180+}
181+
182+protected int
183+file_clear_closexec(int fd) {
184+ return fcntl(fd, F_SETFD, 0);
185+}
186diff --git a/src/magic.c b/src/magic.c
187index 17a7077d..89f4e16c 100644
188--- a/src/magic.c
189+++ b/src/magic.c
190@@ -33,7 +33,7 @@
191 #include "file.h"
192
193 #ifndef lint
194-FILE_RCSID("@(#)$File: magic.c,v 1.112 2020/06/08 19:44:10 christos Exp $")
195+FILE_RCSID("@(#)$File: magic.c,v 1.113 2020/12/08 21:26:00 christos Exp $")
196 #endif /* lint */
197
198 #include "magic.h"
199@@ -436,7 +436,7 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
200 _setmode(STDIN_FILENO, O_BINARY);
201 #endif
202 if (inname != NULL) {
203- int flags = O_RDONLY|O_BINARY|O_NONBLOCK;
204+ int flags = O_RDONLY|O_BINARY|O_NONBLOCK|O_CLOEXEC;
205 errno = 0;
206 if ((fd = open(inname, flags)) < 0) {
207 okstat = stat(inname, &sb) == 0;
208@@ -460,6 +460,9 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
209 rv = 0;
210 goto done;
211 }
212+#if O_CLOEXEC == 0
213+ (void)fcntl(fd, F_SETFD, FD_CLOEXEC);
214+#endif
215 }
216
217 if (fd != -1) {
218--
2192.17.1
220