From b2c03347b07e24a5298361451277264fda8fdb4c Mon Sep 17 00:00:00 2001
From: Kyle Edwards <kyle.edwards@kitware.com>
Date: Mon, 12 Jul 2021 15:38:43 -0400
Subject: [PATCH] file(GET_RUNTIME_DEPENDENCIES): Check architecture of
 dependencies

Fixes: #22106
---
 Source/cmBinUtilsLinuxELFLinker.cxx           | 43 ++++++++++++++++++-
 Source/cmBinUtilsLinuxELFLinker.h             |  4 ++
 Source/cmELF.cxx                              | 16 +++++++
 Source/cmELF.h                                |  4 ++
 .../linux-notfile-all-stderr.txt              |  5 +--
 5 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/Source/cmBinUtilsLinuxELFLinker.cxx b/Source/cmBinUtilsLinuxELFLinker.cxx
index 9ce403dcc0..99707a3f70 100644
--- a/Source/cmBinUtilsLinuxELFLinker.cxx
+++ b/Source/cmBinUtilsLinuxELFLinker.cxx
@@ -18,6 +18,10 @@
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
 
+#ifdef CMake_USE_ELF_PARSER
+#  include "cmELF.h"
+#endif
+
 static std::string ReplaceOrigin(const std::string& rpath,
                                  const std::string& origin)
 {
@@ -86,6 +90,24 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
   std::string const& file, cmStateEnums::TargetType /* unused */)
 {
   std::vector<std::string> parentRpaths;
+
+#ifdef CMake_USE_ELF_PARSER
+  cmELF elf(file.c_str());
+  if (!elf) {
+    return false;
+  }
+  if (elf.GetMachine() != 0) {
+    if (this->Machine != 0) {
+      if (elf.GetMachine() != this->Machine) {
+        this->SetError("All files must have the same architecture.");
+        return false;
+      }
+    } else {
+      this->Machine = elf.GetMachine();
+    }
+  }
+#endif
+
   return this->ScanDependencies(file, parentRpaths);
 }
 
@@ -150,13 +172,29 @@ bool cmBinUtilsLinuxELFLinker::ScanDependencies(
   return true;
 }
 
+namespace {
+bool FileHasArchitecture(const char* filename, std::uint16_t machine)
+{
+#ifdef CMake_USE_ELF_PARSER
+  cmELF elf(filename);
+  if (!elf) {
+    return false;
+  }
+  return machine == 0 || machine == elf.GetMachine();
+#else
+  return true;
+#endif
+}
+}
+
 bool cmBinUtilsLinuxELFLinker::ResolveDependency(
   std::string const& name, std::vector<std::string> const& searchPaths,
   std::string& path, bool& resolved)
 {
   for (auto const& searchPath : searchPaths) {
     path = cmStrCat(searchPath, '/', name);
-    if (cmSystemTools::PathExists(path)) {
+    if (cmSystemTools::PathExists(path) &&
+        FileHasArchitecture(path.c_str(), this->Machine)) {
       resolved = true;
       return true;
     }
@@ -164,7 +202,8 @@ bool cmBinUtilsLinuxELFLinker::ResolveDependency(
 
   for (auto const& searchPath : this->Archive->GetSearchDirectories()) {
     path = cmStrCat(searchPath, '/', name);
-    if (cmSystemTools::PathExists(path)) {
+    if (cmSystemTools::PathExists(path) &&
+        FileHasArchitecture(path.c_str(), this->Machine)) {
       std::ostringstream warning;
       warning << "Dependency " << name << " found in search directory:\n  "
               << searchPath
diff --git a/Source/cmBinUtilsLinuxELFLinker.h b/Source/cmBinUtilsLinuxELFLinker.h
index 4e7e36d4c8..395ed567b4 100644
--- a/Source/cmBinUtilsLinuxELFLinker.h
+++ b/Source/cmBinUtilsLinuxELFLinker.h
@@ -3,6 +3,9 @@
 
 #pragma once
 
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <cstdint>
 #include <memory>
 #include <string>
 #include <vector>
@@ -29,6 +32,7 @@ private:
   std::unique_ptr<cmLDConfigTool> LDConfigTool;
   bool HaveLDConfigPaths = false;
   std::vector<std::string> LDConfigPaths;
+  std::uint16_t Machine = 0;
 
   bool ScanDependencies(std::string const& file,
                         std::vector<std::string> const& parentRpaths);
diff --git a/Source/cmELF.cxx b/Source/cmELF.cxx
index deffdb6467..9a474e32c5 100644
--- a/Source/cmELF.cxx
+++ b/Source/cmELF.cxx
@@ -168,6 +168,9 @@ public:
   // Return the recorded ELF type.
   cmELF::FileType GetFileType() const { return this->ELFType; }
 
+  // Return the recorded machine.
+  std::uint16_t GetMachine() const { return this->Machine; }
+
 protected:
   // Data common to all ELF class implementations.
 
@@ -183,6 +186,9 @@ protected:
   // The ELF file type.
   cmELF::FileType ELFType;
 
+  // The ELF architecture.
+  std::uint16_t Machine;
+
   // Whether we need to byte-swap structures read from the stream.
   bool NeedSwap;
 
@@ -478,6 +484,8 @@ cmELFInternalImpl<Types>::cmELFInternalImpl(cmELF* external,
     }
   }
 
+  this->Machine = this->ELFHeader.e_machine;
+
   // Load the section headers.
   this->SectionHeaders.resize(this->ELFHeader.e_shnum);
   for (ELF_Half i = 0; i < this->ELFHeader.e_shnum; ++i) {
@@ -757,6 +765,14 @@ cmELF::FileType cmELF::GetFileType() const
   return FileTypeInvalid;
 }
 
+std::uint16_t cmELF::GetMachine() const
+{
+  if (this->Valid()) {
+    return this->Internal->GetMachine();
+  }
+  return 0;
+}
+
 unsigned int cmELF::GetNumberOfSections() const
 {
   if (this->Valid()) {
diff --git a/Source/cmELF.h b/Source/cmELF.h
index c479e2b951..f88ebe9920 100644
--- a/Source/cmELF.h
+++ b/Source/cmELF.h
@@ -4,6 +4,7 @@
 
 #include "cmConfigure.h" // IWYU pragma: keep
 
+#include <cstdint>
 #include <iosfwd>
 #include <memory>
 #include <string>
@@ -72,6 +73,9 @@ public:
   /** Get the type of the file opened.  */
   FileType GetFileType() const;
 
+  /** Get the machine of the file opened.  */
+  std::uint16_t GetMachine() const;
+
   /** Get the number of ELF sections present.  */
   unsigned int GetNumberOfSections() const;
 
diff --git a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-notfile-all-stderr.txt b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-notfile-all-stderr.txt
index d9758c579e..5b863220ab 100644
--- a/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-notfile-all-stderr.txt
+++ b/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-notfile-all-stderr.txt
@@ -1,5 +1,2 @@
 ^CMake Error at cmake_install\.cmake:[0-9]+ \(file\):
-  file Failed to run objdump on:
-
-    [^
-]*/Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/linux-notfile-build/root-all/bin/\.\./lib/libtest\.so$
+  file Could not resolve file libtest\.so$
-- 
GitLab