diff options
author | Siddhesh Poyarekar <siddhesh@gotplt.org> | 2020-12-07 20:48:33 +0530 |
---|---|---|
committer | Siddhesh Poyarekar <siddhesh@gotplt.org> | 2020-12-07 20:48:33 +0530 |
commit | 014cc7f849e8209623fc99264814bce7b3b6faf2 (patch) | |
tree | 890c586d1a37643dfa2aa394935748a5e6542f51 /binutils/ar.c | |
parent | 1a1c3b4cc17687091cff5a368bd6f13742bcfdf8 (diff) | |
download | gdb-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/ar.c')
-rw-r--r-- | binutils/ar.c | 12 |
1 files changed, 11 insertions, 1 deletions
diff --git a/binutils/ar.c b/binutils/ar.c index 2253242..6598dd9 100644 --- a/binutils/ar.c +++ b/binutils/ar.c @@ -1254,6 +1254,8 @@ write_archive (bfd *iarch) char *old_name, *new_name; bfd *contents_head = iarch->archive_next; int ofd = -1; + struct stat target_stat; + bfd_boolean skip_stat = FALSE; old_name = (char *) xmalloc (strlen (bfd_get_filename (iarch)) + 1); strcpy (old_name, bfd_get_filename (iarch)); @@ -1299,6 +1301,14 @@ write_archive (bfd *iarch) if (!bfd_set_archive_head (obfd, contents_head)) bfd_fatal (old_name); +#if !defined (_WIN32) || defined (__CYGWIN32__) + ofd = dup (ofd); + if (iarch == NULL || iarch->iostream == NULL) + skip_stat = TRUE; + else if (ofd == -1 || fstat (fileno (iarch->iostream), &target_stat) != 0) + bfd_fatal (old_name); +#endif + if (!bfd_close (obfd)) bfd_fatal (old_name); @@ -1308,7 +1318,7 @@ write_archive (bfd *iarch) /* We don't care if this fails; we might be creating the archive. */ bfd_close (iarch); - if (smart_rename (new_name, old_name, 0) != 0) + if (smart_rename (new_name, old_name, ofd, skip_stat ? NULL : &target_stat, 0) != 0) xexit (1); free (old_name); free (new_name); |