aboutsummaryrefslogtreecommitdiff
path: root/binutils/objcopy.c
diff options
context:
space:
mode:
authorSiddhesh Poyarekar <siddhesh@gotplt.org>2020-12-07 20:48:33 +0530
committerSiddhesh Poyarekar <siddhesh@gotplt.org>2020-12-07 20:48:33 +0530
commit014cc7f849e8209623fc99264814bce7b3b6faf2 (patch)
tree890c586d1a37643dfa2aa394935748a5e6542f51 /binutils/objcopy.c
parent1a1c3b4cc17687091cff5a368bd6f13742bcfdf8 (diff)
downloadgdb-014cc7f849e8209623fc99264814bce7b3b6faf2.zip
gdb-014cc7f849e8209623fc99264814bce7b3b6faf2.tar.gz
gdb-014cc7f849e8209623fc99264814bce7b3b6faf2.tar.bz2
binutils: Make smart_rename safe too
smart_rename is capable of handling symlinks by copying and it also tries to preserve ownership and permissions of files when they're overwritten during the rename. This is useful in objcopy where the file properties need to be preserved. However because smart_rename does this using file names, it leaves a race window between renames and permission fixes. This change removes this race window by using file descriptors from the original BFDs that were used to manipulate these files wherever possible. The file that is to be renamed is also passed as a file descriptor so that we use fchown/fchmod on the file descriptor, thus making sure that we only modify the file we have opened to write. Further, in case the file is to be overwritten (as is the case in ar or objcopy), the permissions that need to be restored are taken from the file descriptor that was opened for input so that integrity of the file status is maintained all the way through to the rename. binutils/ * rename.c * ar.c (write_archive) [!defined (_WIN32) || defined (__CYGWIN32__)]: Initialize TARGET_STAT and OFD to pass to SMART_RENAME. * arsup.c (ar_save) [defined (_WIN32) || defined (__CYGWIN32__)]: Likewise. * bucomm.h (smart_rename): Add new arguments to declaration. * objcopy.c (strip_main)[defined (_WIN32) || defined (__CYGWIN32__)]: Initialize COPYFD and pass to SMART_RENAME. (copy_main) [defined (_WIN32) || defined (__CYGWIN32__)]: Likewise. * rename.c (try_preserve_permissions): New function. (smart_rename): Use it and add new arguments.
Diffstat (limited to 'binutils/objcopy.c')
-rw-r--r--binutils/objcopy.c42
1 files changed, 34 insertions, 8 deletions
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index b6cf6ea..04ba95e 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -4815,6 +4815,7 @@ strip_main (int argc, char *argv[])
struct stat statbuf;
char *tmpname;
int tmpfd = -1;
+ int copyfd = -1;
if (get_file_size (argv[i]) < 1)
{
@@ -4828,7 +4829,12 @@ strip_main (int argc, char *argv[])
else
tmpname = output_file;
- if (tmpname == NULL)
+ if (tmpname == NULL
+#if !defined (_WIN32) || defined (__CYGWIN32__)
+ /* Retain a copy of TMPFD since we will need it for SMART_RENAME. */
+ || (tmpfd >= 0 && (copyfd = dup (tmpfd)) == -1)
+#endif
+ )
{
bfd_nonfatal_message (argv[i], NULL, NULL,
_("could not create temporary file to hold stripped copy"));
@@ -4846,12 +4852,18 @@ strip_main (int argc, char *argv[])
if (output_file != tmpname)
status = (smart_rename (tmpname,
output_file ? output_file : argv[i],
- preserve_dates) != 0);
+ copyfd, &statbuf, preserve_dates) != 0);
if (status == 0)
status = hold_status;
}
else
- unlink_if_ordinary (tmpname);
+ {
+#if !defined (_WIN32) || defined (__CYGWIN32__)
+ if (copyfd >= 0)
+ close (copyfd);
+#endif
+ unlink_if_ordinary (tmpname);
+ }
if (output_file != tmpname)
free (tmpname);
}
@@ -5059,6 +5071,7 @@ copy_main (int argc, char *argv[])
bfd_boolean use_globalize = FALSE;
bfd_boolean use_keep_global = FALSE;
int c, tmpfd = -1;
+ int copyfd = -1;
struct stat statbuf;
const bfd_arch_info_type *input_arch = NULL;
@@ -5903,9 +5916,16 @@ copy_main (int argc, char *argv[])
else
tmpname = output_filename;
- if (tmpname == NULL)
- fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"),
- input_filename, strerror (errno));
+ if (tmpname == NULL
+#if !defined (_WIN32) || defined (__CYGWIN32__)
+ /* Retain a copy of TMPFD since we will need it for SMART_RENAME. */
+ || (tmpfd >= 0 && (copyfd = dup (tmpfd)) == -1)
+#endif
+ )
+ {
+ fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"),
+ input_filename, strerror (errno));
+ }
copy_file (input_filename, tmpname, tmpfd, &statbuf, input_target,
output_target, input_arch);
@@ -5914,11 +5934,17 @@ copy_main (int argc, char *argv[])
if (preserve_dates)
set_times (tmpname, &statbuf);
if (tmpname != output_filename)
- status = (smart_rename (tmpname, input_filename,
+ status = (smart_rename (tmpname, input_filename, copyfd, &statbuf,
preserve_dates) != 0);
}
else
- unlink_if_ordinary (tmpname);
+ {
+#if !defined (_WIN32) || defined (__CYGWIN32__)
+ if (copyfd >= 0)
+ close (copyfd);
+#endif
+ unlink_if_ordinary (tmpname);
+ }
if (tmpname != output_filename)
free (tmpname);