diff options
| -rw-r--r-- | meta/recipes-devtools/file/file_5.39.bb | 3 | ||||
| -rw-r--r-- | meta/recipes-devtools/file/files/0001-Fix-close_on_exec-multithreaded-decompression-issue.patch | 220 |
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" | |||
| 12 | DEPENDS_class-native = "bzip2-replacement-native" | 12 | DEPENDS_class-native = "bzip2-replacement-native" |
| 13 | 13 | ||
| 14 | SRC_URI = "git://github.com/file/file.git \ | 14 | SRC_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 | ||
| 17 | SRCREV = "87731415de945660b00f02207d8e9d986ef9b82e" | 18 | SRCREV = "87731415de945660b00f02207d8e9d986ef9b82e" |
| 18 | S = "${WORKDIR}/git" | 19 | S = "${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 @@ | |||
| 1 | From 0d82f2f3ba4a856504f23a9db1dd5f37bd076337 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Changqing Li <changqing.li@windriver.com> | ||
| 3 | Date: Mon, 23 Aug 2021 14:16:53 +0800 | ||
| 4 | Subject: [PATCH] Fix close_on_exec multithreaded decompression issue. | ||
| 5 | |||
| 6 | Upstream-Status: Backport [https://github.com/file/file/commit/81f15c2b0d6e9eaf524ff7bab37426c21af75fb7] | ||
| 7 | Signed-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 | |||
| 17 | diff --git a/ChangeLog b/ChangeLog | ||
| 18 | index 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 | ||
| 30 | diff --git a/configure.ac b/configure.ac | ||
| 31 | index 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) | ||
| 43 | diff --git a/src/compress.c b/src/compress.c | ||
| 44 | index 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))); | ||
| 103 | diff --git a/src/file.h b/src/file.h | ||
| 104 | index 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); | ||
| 140 | diff --git a/src/funcs.c b/src/funcs.c | ||
| 141 | index 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 | +} | ||
| 186 | diff --git a/src/magic.c b/src/magic.c | ||
| 187 | index 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 | -- | ||
| 219 | 2.17.1 | ||
| 220 | |||
