[PATCH] D93881: [llvm-objcopy] preserve file ownership when overwritten

Jian Cai via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 5 21:27:10 PST 2021


jcai19 created this revision.
Herald added subscribers: dexonsmith, abrachet, hiraditya, yaxunl.
Herald added a reviewer: alexshap.
Herald added a reviewer: rupprecht.
Herald added a reviewer: jhenderson.
jcai19 updated this revision to Diff 314724.
jcai19 added a comment.
jcai19 edited the summary of this revision.
jcai19 updated this revision to Diff 314795.
jcai19 published this revision for review.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

Update test cases.


jcai19 added a comment.

Fix test cases to make them pass on macOS.


GNU objcopy and strip preserve the ownership of a file when it's
overwritten, e.g. while "sudo objcopy foo -o bar" creates a new file bar
with root access,  "sudo objcopy foo" will keep the owner and group of
foo unchanged. Currently llvm-objcopy and llvm-strip behave differently,
always changing the ownership to root. The discrepancy prevents Chrome
OS from migrating to llvm-objcopy and llvm-strip as Portage (the build
system) builds binaries following recommended steps documented at the
man page of GNU strip as follows,

      

1.<Link the executable as normal.>
1.<Copy "foo" to "foo.full">
1.<Run "strip --strip-debug foo">
1.<Run "objcopy --add-gnu-debuglink=foo.full foo">

      

With llvm-strip and llvm-objcopy, the last two steps change ownership of
binaries to root and cause them to become inaccessible to the intended user.

      

Link: crbug.com/1108880


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D93881

Files:
  llvm/include/llvm/Support/FileSystem.h
  llvm/lib/Support/Unix/Path.inc
  llvm/test/tools/llvm-objcopy/preserve-file-ownership.test
  llvm/tools/llvm-objcopy/llvm-objcopy.cpp


Index: llvm/tools/llvm-objcopy/llvm-objcopy.cpp
===================================================================
--- llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -328,6 +328,20 @@
       return E;
   }
 
+#if !defined(_WIN32) || defined(__CYGWIN32__)
+  // Preserve the ownership if the input file is overwritten
+  if (Config.InputFilename != "-" &&
+      Config.InputFilename == Config.OutputFilename) {
+    sys::fs::file_status OStat;
+    if (std::error_code EC = sys::fs::status(Config.OutputFilename, OStat))
+      return createFileError(Config.OutputFilename, EC);
+    if (Stat.getUser() != OStat.getUser() ||
+        Stat.getGroup() != OStat.getGroup())
+      sys::fs::changeFileOwnership(Config.OutputFilename, Stat.getUser(),
+                                   Stat.getGroup());
+  }
+#endif
+
   return Error::success();
 }
 
Index: llvm/test/tools/llvm-objcopy/preserve-file-ownership.test
===================================================================
--- /dev/null
+++ llvm/test/tools/llvm-objcopy/preserve-file-ownership.test
@@ -0,0 +1,19 @@
+# RUN: yaml2obj %s -o %t
+# RUN: sudo llvm-objcopy %t
+# RUN: ls -l %t | FileCheck -DUSER=$(ls -ld %s | awk '{print $3}') -DGROUP=$(ls -ld %s | awk '{print $4}') %s
+# RUN: yaml2obj %s -o %t
+# RUN: sudo llvm-strip %t
+# RUN: ls -l %t | FileCheck -DUSER=$(ls -ld %s | awk '{print $3}') -DGROUP=$(ls -ld %s | awk '{print $4}') %s
+
+# CHECK: [[USER]] [[GROUP]]
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
Index: llvm/lib/Support/Unix/Path.inc
===================================================================
--- llvm/lib/Support/Unix/Path.inc
+++ llvm/lib/Support/Unix/Path.inc
@@ -1213,6 +1213,17 @@
   return std::error_code();
 }
 
+std::error_code changeFileOwnership(const Twine &Name, uint32_t Owner, uint32_t Group) {
+  int FD;
+  if (std::error_code EC = sys::fs::openFileForWrite(Name, FD, sys::fs::CD_OpenExisting))
+    return EC;
+  auto Chown = [&]() { return fchown(FD, Owner, Group); };
+  if ((sys::RetryAfterSignal(-1, Chown)) < 0)
+    return std::error_code(errno, std::generic_category());
+  if (std::error_code EC = sys::fs::closeFile(FD))
+    return EC;
+}
+
 } // end namespace fs
 
 namespace path {
Index: llvm/include/llvm/Support/FileSystem.h
===================================================================
--- llvm/include/llvm/Support/FileSystem.h
+++ llvm/include/llvm/Support/FileSystem.h
@@ -1159,6 +1159,17 @@
 /// means that the filesystem may have failed to perform some buffered writes.
 std::error_code closeFile(file_t &F);
 
+#ifdef LLVM_ON_UNIX
+/// @brief Change ownership of a file
+///
+/// @param Owner The owner of the file to change to
+/// @param Group The group of the file to change to
+/// @returns errc::success if successfully updated file ownership, otherwise an
+///          error code is returned.
+std::error_code changeFileOwnership(const Twine &Name, uint32_t Owner,
+                                    uint32_t Group);
+#endif
+
 /// RAII class that facilitates file locking.
 class FileLocker {
   int FD; ///< Locked file handle.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D93881.314795.patch
Type: text/x-patch
Size: 3342 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210106/ca0f5c21/attachment.bin>


More information about the llvm-commits mailing list