Commit 0d74ac470 (copy: make backup files more reliably, 2017-07-30)
made 'cp' and 'install' use renameat2 to make backups, but forgot 'ln'
despite mentioning it in the NEWS entry. This patch makes that change
for 'ln'. Not sure whether it's preferred to update old NEWS entries
for accuracy (and then run 'make update-NEWS-hash'), so I left it
as-is for now.

There were other behavior changes WRT backups in that commit. I'll
have a look at that separately since the OSS scanner issue was just
about the race.

-- 8< --

* src/ln.c (do_link): Use backup_file_rename which uses renameat2 on
platforms that support it.
* NEWS: Mention the bug fix.

Discovered by Anthropic's OSS Scanner, as bug ANT-2026-D7OXM969.
---
 NEWS     |  6 ++++++
 src/ln.c | 16 +++++-----------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/NEWS b/NEWS
index 009774a5d..74c463c4c 100644
--- a/NEWS
+++ b/NEWS
@@ -147,6 +147,12 @@ GNU coreutils NEWS                                    -*- 
outline -*-
   referenced.
   [This bug was present in "the beginning".]
 
+  'ln' now avoids races that could lose backup data in unlikely
+  circumstances.  Since the fix relies on the renameat2 system call of
+  Linux kernel 3.15 and later, the races are still present on other
+  platforms.
+  [This bug was present in "the beginning".]
+
   'ls' no longer omits ACL indicators or capability coloring for subsequent
   files on the same file system after an unsupported security context
   lookup on a file without an ACL.
diff --git a/src/ln.c b/src/ln.c
index 335c77150..2f0c2e112 100644
--- a/src/ln.c
+++ b/src/ln.c
@@ -285,19 +285,13 @@ do_link (char const *source, int destdir_fd, char const 
*dest_base,
 
                   if (backup_type != no_backups)
                     {
-                      backup_base = find_backup_file_name (destdir_fd,
-                                                           dest_base,
-                                                           backup_type);
-                      if (renameat (destdir_fd, dest_base,
-                                    destdir_fd, backup_base)
-                          != 0)
+                      backup_base = backup_file_rename (destdir_fd, dest_base,
+                                                        backup_type);
+                      if (! backup_base)
                         {
-                          int rename_errno = errno;
-                          free (backup_base);
-                          backup_base = NULL;
-                          if (rename_errno != ENOENT)
+                          if (errno != ENOENT)
                             {
-                              error (0, rename_errno, _("cannot backup %s"),
+                              error (0, errno, _("cannot backup %s"),
                                      quoteaf (dest));
                               goto fail;
                             }
-- 
2.56.1


Reply via email to