blob: d6117b65a42159e783c2e45ef40259f82097ac01 [file] [log] [blame]
Andrew Geisslerc926e172021-05-07 16:11:35 -05001From d3edaa91d4cf7202ec14342410194841e2f67f12 Mon Sep 17 00:00:00 2001
2From: Alan Modra <amodra@gmail.com>
3Date: Fri, 26 Feb 2021 11:30:32 +1030
4Subject: [PATCH] Reinstate various pieces backed out from smart_rename changes
5
6In the interests of a stable release various last minute smart_rename
7patches were backed out of the 2.36 branch. The main reason to
8reinstate some of those backed out changes here is to make necessary
9followup fixes to commit 8e03235147a9 simple cherry-picks from
10mainline. A secondary reason is that ar -M support isn't fixed for
11pr26945 without this patch.
12
13 PR 26945
14 * ar.c: Don't include libbfd.h.
15 (write_archive): Replace xmalloc+strcpy with xstrdup.
16 * arsup.c (temp_name, real_ofd): New static variables.
17 (ar_open): Use make_tempname and bfd_fdopenw.
18 (ar_save): Adjust to suit ar_open changes.
19 * objcopy.c: Don't include libbfd.h.
20 * rename.c: Rename and reorder variables.
21
22(cherry picked from commit 95b91a043aeaeb546d2fea556d84a2de1e917770)
23
24Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=d3edaa91d4cf7202ec14342410194841e2f67f12]
25CVE: CVE-2021-20197
26Signed-off-by: Vinay Kumar <vinay.m.engg@gmail.com>
27---
28 binutils/ar.c | 6 +-
29 binutils/arsup.c | 37 ++++++++----
30 binutils/bucomm.h | 3 +-
31 binutils/objcopy.c | 9 +--
32 binutils/rename.c | 148 +++++++++++----------------------------------
33 5 files changed, 67 insertions(+), 136 deletions(-)
34
35diff --git a/binutils/ar.c b/binutils/ar.c
36index 45a34e3a6cf..44df48c5c67 100644
37--- a/binutils/ar.c
38+++ b/binutils/ar.c
39@@ -25,7 +25,6 @@
40
41 #include "sysdep.h"
42 #include "bfd.h"
43-#include "libbfd.h"
44 #include "libiberty.h"
45 #include "progress.h"
46 #include "getopt.h"
47@@ -1255,8 +1254,7 @@ write_archive (bfd *iarch)
48 bfd *contents_head = iarch->archive_next;
49 int ofd = -1;
50
51- old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1);
52- strcpy (old_name, bfd_get_filename (iarch));
53+ old_name = xstrdup (bfd_get_filename (iarch));
54 new_name = make_tempname (old_name, &ofd);
55
56 if (new_name == NULL)
57@@ -1308,7 +1306,7 @@ write_archive (bfd *iarch)
58 /* We don't care if this fails; we might be creating the archive. */
59 bfd_close (iarch);
60
61- if (smart_rename (new_name, old_name, 0) != 0)
62+ if (smart_rename (new_name, old_name, NULL) != 0)
63 xexit (1);
64 free (old_name);
65 free (new_name);
66diff --git a/binutils/arsup.c b/binutils/arsup.c
67index 5403a0c5d74..f7ce8f0bc82 100644
68--- a/binutils/arsup.c
69+++ b/binutils/arsup.c
70@@ -42,6 +42,8 @@ extern int deterministic;
71
72 static bfd *obfd;
73 static char *real_name;
74+static char *temp_name;
75+static int real_ofd;
76 static FILE *outfile;
77
78 static void
79@@ -149,27 +151,24 @@ maybequit (void)
80 void
81 ar_open (char *name, int t)
82 {
83- char *tname;
84- const char *bname = lbasename (name);
85- real_name = name;
86+ real_name = xstrdup (name);
87+ temp_name = make_tempname (real_name, &real_ofd);
88
89- /* Prepend tmp- to the beginning, to avoid file-name clashes after
90- truncation on filesystems with limited namespaces (DOS). */
91- if (asprintf (&tname, "%.*stmp-%s", (int) (bname - name), name, bname) == -1)
92+ if (temp_name == NULL)
93 {
94- fprintf (stderr, _("%s: Can't allocate memory for temp name (%s)\n"),
95+ fprintf (stderr, _("%s: Can't open temporary file (%s)\n"),
96 program_name, strerror(errno));
97 maybequit ();
98 return;
99 }
100
101- obfd = bfd_openw (tname, NULL);
102+ obfd = bfd_fdopenw (temp_name, NULL, real_ofd);
103
104 if (!obfd)
105 {
106 fprintf (stderr,
107 _("%s: Can't open output archive %s\n"),
108- program_name, tname);
109+ program_name, temp_name);
110
111 maybequit ();
112 }
113@@ -344,16 +343,30 @@ ar_save (void)
114 }
115 else
116 {
117- char *ofilename = xstrdup (bfd_get_filename (obfd));
118+ struct stat target_stat;
119
120 if (deterministic > 0)
121 obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
122
123 bfd_close (obfd);
124
125- smart_rename (ofilename, real_name, 0);
126+ if (stat (real_name, &target_stat) != 0)
127+ {
128+ /* The temp file created in ar_open has mode 0600 as per mkstemp.
129+ Create the real empty output file here so smart_rename will
130+ update the mode according to the process umask. */
131+ obfd = bfd_openw (real_name, NULL);
132+ if (obfd != NULL)
133+ {
134+ bfd_set_format (obfd, bfd_archive);
135+ bfd_close (obfd);
136+ }
137+ }
138+
139+ smart_rename (temp_name, real_name, NULL);
140 obfd = 0;
141- free (ofilename);
142+ free (temp_name);
143+ free (real_name);
144 }
145 }
146
147diff --git a/binutils/bucomm.h b/binutils/bucomm.h
148index 91f6a5b228f..aa7e33d8cd1 100644
149--- a/binutils/bucomm.h
150+++ b/binutils/bucomm.h
151@@ -71,7 +71,8 @@ extern void print_version (const char *);
152 /* In rename.c. */
153 extern void set_times (const char *, const struct stat *);
154
155-extern int smart_rename (const char *, const char *, int);
156+extern int smart_rename (const char *, const char *, struct stat *);
157+
158
159 /* In libiberty. */
160 void *xmalloc (size_t);
161diff --git a/binutils/objcopy.c b/binutils/objcopy.c
162index eab3b6db585..73aa8bc2514 100644
163--- a/binutils/objcopy.c
164+++ b/binutils/objcopy.c
165@@ -20,7 +20,6 @@
166
167 #include "sysdep.h"
168 #include "bfd.h"
169-#include "libbfd.h"
170 #include "progress.h"
171 #include "getopt.h"
172 #include "libiberty.h"
173@@ -4861,12 +4860,10 @@ strip_main (int argc, char *argv[])
174 output_target, NULL);
175 if (status == 0)
176 {
177- if (preserve_dates)
178- set_times (tmpname, &statbuf);
179 if (output_file != tmpname)
180 status = (smart_rename (tmpname,
181 output_file ? output_file : argv[i],
182- preserve_dates) != 0);
183+ preserve_dates ? &statbuf : NULL) != 0);
184 if (status == 0)
185 status = hold_status;
186 }
187@@ -5931,11 +5928,9 @@ copy_main (int argc, char *argv[])
188 output_target, input_arch);
189 if (status == 0)
190 {
191- if (preserve_dates)
192- set_times (tmpname, &statbuf);
193 if (tmpname != output_filename)
194 status = (smart_rename (tmpname, input_filename,
195- preserve_dates) != 0);
196+ preserve_dates ? &statbuf : NULL) != 0);
197 }
198 else
199 unlink_if_ordinary (tmpname);
200diff --git a/binutils/rename.c b/binutils/rename.c
201index 65ad5bf52c4..72a9323d72c 100644
202--- a/binutils/rename.c
203+++ b/binutils/rename.c
204@@ -24,14 +24,9 @@
205
206 #ifdef HAVE_GOOD_UTIME_H
207 #include <utime.h>
208-#else /* ! HAVE_GOOD_UTIME_H */
209-#ifdef HAVE_UTIMES
210+#elif defined HAVE_UTIMES
211 #include <sys/time.h>
212-#endif /* HAVE_UTIMES */
213-#endif /* ! HAVE_GOOD_UTIME_H */
214-
215-#if ! defined (_WIN32) || defined (__CYGWIN32__)
216-static int simple_copy (const char *, const char *);
217+#endif
218
219 /* The number of bytes to copy at once. */
220 #define COPY_BUF 8192
221@@ -82,7 +77,6 @@ simple_copy (const char *from, const char *to)
222 }
223 return 0;
224 }
225-#endif /* __CYGWIN32__ or not _WIN32 */
226
227 /* Set the times of the file DESTINATION to be the same as those in
228 STATBUF. */
229@@ -91,122 +85,52 @@ void
230 set_times (const char *destination, const struct stat *statbuf)
231 {
232 int result;
233-
234- {
235 #ifdef HAVE_GOOD_UTIME_H
236- struct utimbuf tb;
237-
238- tb.actime = statbuf->st_atime;
239- tb.modtime = statbuf->st_mtime;
240- result = utime (destination, &tb);
241-#else /* ! HAVE_GOOD_UTIME_H */
242-#ifndef HAVE_UTIMES
243- long tb[2];
244-
245- tb[0] = statbuf->st_atime;
246- tb[1] = statbuf->st_mtime;
247- result = utime (destination, tb);
248-#else /* HAVE_UTIMES */
249- struct timeval tv[2];
250-
251- tv[0].tv_sec = statbuf->st_atime;
252- tv[0].tv_usec = 0;
253- tv[1].tv_sec = statbuf->st_mtime;
254- tv[1].tv_usec = 0;
255- result = utimes (destination, tv);
256-#endif /* HAVE_UTIMES */
257-#endif /* ! HAVE_GOOD_UTIME_H */
258- }
259+ struct utimbuf tb;
260+
261+ tb.actime = statbuf->st_atime;
262+ tb.modtime = statbuf->st_mtime;
263+ result = utime (destination, &tb);
264+#elif defined HAVE_UTIMES
265+ struct timeval tv[2];
266+
267+ tv[0].tv_sec = statbuf->st_atime;
268+ tv[0].tv_usec = 0;
269+ tv[1].tv_sec = statbuf->st_mtime;
270+ tv[1].tv_usec = 0;
271+ result = utimes (destination, tv);
272+#else
273+ long tb[2];
274+
275+ tb[0] = statbuf->st_atime;
276+ tb[1] = statbuf->st_mtime;
277+ result = utime (destination, tb);
278+#endif
279
280 if (result != 0)
281 non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno));
282 }
283
284-#ifndef S_ISLNK
285-#ifdef S_IFLNK
286-#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
287-#else
288-#define S_ISLNK(m) 0
289-#define lstat stat
290-#endif
291-#endif
292-
293-/* Rename FROM to TO, copying if TO is a link.
294- Return 0 if ok, -1 if error. */
295+/* Copy FROM to TO. TARGET_STAT has the file status that, if non-NULL,
296+ is used to fix up timestamps. Return 0 if ok, -1 if error.
297+ At one time this function renamed files, but file permissions are
298+ tricky to update given the number of different schemes used by
299+ various systems. So now we just copy. */
300
301 int
302-smart_rename (const char *from, const char *to, int preserve_dates ATTRIBUTE_UNUSED)
303+smart_rename (const char *from, const char *to,
304+ struct stat *target_stat)
305 {
306- bfd_boolean exists;
307- struct stat s;
308- int ret = 0;
309-
310- exists = lstat (to, &s) == 0;
311-
312-#if defined (_WIN32) && !defined (__CYGWIN32__)
313- /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but
314- fail instead. Also, chown is not present. */
315+ int ret;
316
317- if (exists)
318- remove (to);
319-
320- ret = rename (from, to);
321+ ret = simple_copy (from, to);
322 if (ret != 0)
323- {
324- /* We have to clean up here. */
325- non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
326- unlink (from);
327- }
328-#else
329- /* Use rename only if TO is not a symbolic link and has
330- only one hard link, and we have permission to write to it. */
331- if (! exists
332- || (!S_ISLNK (s.st_mode)
333- && S_ISREG (s.st_mode)
334- && (s.st_mode & S_IWUSR)
335- && s.st_nlink == 1)
336- )
337- {
338- ret = rename (from, to);
339- if (ret == 0)
340- {
341- if (exists)
342- {
343- /* Try to preserve the permission bits and ownership of
344- TO. First get the mode right except for the setuid
345- bit. Then change the ownership. Then fix the setuid
346- bit. We do the chmod before the chown because if the
347- chown succeeds, and we are a normal user, we won't be
348- able to do the chmod afterward. We don't bother to
349- fix the setuid bit first because that might introduce
350- a fleeting security problem, and because the chown
351- will clear the setuid bit anyhow. We only fix the
352- setuid bit if the chown succeeds, because we don't
353- want to introduce an unexpected setuid file owned by
354- the user running objcopy. */
355- chmod (to, s.st_mode & 0777);
356- if (chown (to, s.st_uid, s.st_gid) >= 0)
357- chmod (to, s.st_mode & 07777);
358- }
359- }
360- else
361- {
362- /* We have to clean up here. */
363- non_fatal (_("unable to rename '%s'; reason: %s"), to, strerror (errno));
364- unlink (from);
365- }
366- }
367- else
368- {
369- ret = simple_copy (from, to);
370- if (ret != 0)
371- non_fatal (_("unable to copy file '%s'; reason: %s"), to, strerror (errno));
372+ non_fatal (_("unable to copy file '%s'; reason: %s"),
373+ to, strerror (errno));
374
375- if (preserve_dates)
376- set_times (to, &s);
377- unlink (from);
378- }
379-#endif /* _WIN32 && !__CYGWIN32__ */
380+ if (target_stat != NULL)
381+ set_times (to, target_stat);
382+ unlink (from);
383
384 return ret;
385 }
386--
3872.17.1
388