diff options
author | Alexandru Croitor <alexandru.croitor@theqtcompany.com> | 2016-01-26 17:16:02 +0100 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@theqtcompany.com> | 2016-01-28 13:42:30 +0000 |
commit | 7d2b096815c139aab19886cc97ccee5c1d4eaa73 (patch) | |
tree | 15bbc0c528de20eca363b134bb8bb8a70b93a2a1 | |
parent | d2b9b4850a5e20b126171e4418fdf1782e244c6f (diff) |
Fix macdeployqt to properly sign inner bundles.
QtWebEngine uses a framework called QtWebEngineCore which contains
an inner bundle called QtWebEngineProcess.app. Because it was not
signed in the proper order, the whole signing process failed.
Fix consists in checking if there are any inner app bundles
inside frameworks, and sign them before signing the rest of the
main bundle.
Change-Id: I48abe26d1e61cd1ce17cb185bcd8d1d72f6c9607
Task-number: QTBUG-50636
Reviewed-by: Morten Johan Sørvig <morten.sorvig@theqtcompany.com>
-rw-r--r-- | src/macdeployqt/shared/shared.cpp | 80 | ||||
-rw-r--r-- | src/macdeployqt/shared/shared.h | 4 |
2 files changed, 77 insertions, 7 deletions
diff --git a/src/macdeployqt/shared/shared.cpp b/src/macdeployqt/shared/shared.cpp index d20b2198e..9ea4c2261 100644 --- a/src/macdeployqt/shared/shared.cpp +++ b/src/macdeployqt/shared/shared.cpp @@ -350,6 +350,19 @@ QStringList findAppFrameworkNames(const QString &appBundlePath) return frameworks; } +QStringList findAppFrameworkPaths(const QString &appBundlePath) +{ + QStringList frameworks; + QString searchPath = appBundlePath + "/Contents/Frameworks/"; + QDirIterator iter(searchPath, QStringList() << QString::fromLatin1("*.framework"), QDir::Dirs); + while (iter.hasNext()) { + iter.next(); + frameworks << iter.fileInfo().filePath(); + } + + return frameworks; +} + QStringList findAppLibraries(const QString &appBundlePath) { QStringList result; @@ -1247,7 +1260,7 @@ void codesignFile(const QString &identity, const QString &filePath) } } -void codesign(const QString &identity, const QString &appBundlePath) +QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePath) { // Code sign all binaries in the app bundle. This needs to // be done inside-out, e.g sign framework dependencies @@ -1273,10 +1286,37 @@ void codesign(const QString &identity, const QString &appBundlePath) foreach (const QString &binary, foundPluginBinaries) pendingBinaries.push(binary); - QStringList foundLibraries = findAppBundleFiles(appBundlePath + "/Contents/Frameworks/"); - foreach (const QString &binary, foundLibraries) - pendingBinaries.push(binary); + // Add frameworks for processing. + QStringList frameworkPaths = findAppFrameworkPaths(appBundlePath); + foreach (const QString &frameworkPath, frameworkPaths) { + + // Add all files for a framework as a catch all. + QStringList bundleFiles = findAppBundleFiles(frameworkPath); + foreach (const QString &binary, bundleFiles) + pendingBinaries.push(binary); + // Prioritise first to sign any additional inner bundles found in the Helpers folder (e.g + // used by QtWebEngine). + QDirIterator helpersIterator(frameworkPath, QStringList() << QString::fromLatin1("Helpers"), QDir::Dirs | QDir::NoSymLinks, QDirIterator::Subdirectories); + while (helpersIterator.hasNext()) { + helpersIterator.next(); + QString helpersPath = helpersIterator.filePath(); + QStringList innerBundleNames = QDir(helpersPath).entryList(QStringList() << "*.app", QDir::Dirs); + foreach (const QString &innerBundleName, innerBundleNames) + signedBinaries += codesignBundle(identity, helpersPath + "/" + innerBundleName); + } + + // Also make sure to sign any libraries that will not be found by otool because they + // are not linked and won't be seen as a dependency. + QDirIterator librariesIterator(frameworkPath, QStringList() << QString::fromLatin1("Libraries"), QDir::Dirs | QDir::NoSymLinks, QDirIterator::Subdirectories); + while (librariesIterator.hasNext()) { + librariesIterator.next(); + QString librariesPath = librariesIterator.filePath(); + bundleFiles = findAppBundleFiles(librariesPath); + foreach (const QString &binary, bundleFiles) + pendingBinaries.push(binary); + } + } // Sign all binares; use otool to find and sign dependencies first. while (!pendingBinaries.isEmpty()) { @@ -1286,17 +1326,39 @@ void codesign(const QString &identity, const QString &appBundlePath) // Check if there are unsigned dependencies, sign these first QStringList dependencies = getBinaryDependencies(rootBinariesPath, binary).toSet().subtract(signedBinaries).toList(); + if (!dependencies.isEmpty()) { pendingBinaries.push(binary); - foreach (const QString &dependency, dependencies) + int dependenciesSkipped = 0; + foreach (const QString &dependency, dependencies) { + // Skip dependencies that are outside the current app bundle, because this might + // cause a codesign error if the current bundle is part of the dependency (e.g. + // a bundle is part of a framework helper, and depends on that framework). + // The dependencies will be taken care of after the current bundle is signed. + if (!dependency.startsWith(appBundlePath)) { + ++dependenciesSkipped; + LogNormal() << "Skipping outside dependency: " << dependency; + continue; + } pendingBinaries.push(dependency); - continue; + } + + // If all dependencies were skipped, make sure the binary is actually signed, instead + // of going into an infinite loop. + if (dependenciesSkipped == dependencies.size()) { + pendingBinaries.pop(); + } else { + continue; + } } + // All dependencies are signed, now sign this binary codesignFile(identity, binary); signedBinaries.insert(binary); } + LogNormal() << "Finished codesigning " << appBundlePath << "with identity" << identity; + // Verify code signature QProcess codesign; codesign.start("codesign", QStringList() << "--deep" << "-v" << appBundlePath); @@ -1308,6 +1370,12 @@ void codesign(const QString &identity, const QString &appBundlePath) } else if (!err.isEmpty()) { LogDebug() << err; } + + return signedBinaries; +} + +void codesign(const QString &identity, const QString &appBundlePath) { + codesignBundle(identity, appBundlePath); } void createDiskImage(const QString &appBundlePath) diff --git a/src/macdeployqt/shared/shared.h b/src/macdeployqt/shared/shared.h index ea678c226..a6d58607c 100644 --- a/src/macdeployqt/shared/shared.h +++ b/src/macdeployqt/shared/shared.h @@ -36,6 +36,7 @@ #include <QString> #include <QStringList> #include <QDebug> +#include <QSet> extern int logLevel; #define LogError() if (logLevel < 0) {} else qDebug() << "ERROR:" @@ -85,7 +86,6 @@ public: bool useLoaderPath; }; - inline QDebug operator<<(QDebug debug, const ApplicationBundleInfo &info); void changeQtFrameworks(const QString appPath, const QString &qtPath, bool useDebugLibs); @@ -107,7 +107,9 @@ void runStrip(const QString &binaryPath); void stripAppBinary(const QString &bundlePath); QString findAppBinary(const QString &appBundlePath); QStringList findAppFrameworkNames(const QString &appBundlePath); +QStringList findAppFrameworkPaths(const QString &appBundlePath); void codesignFile(const QString &identity, const QString &filePath); +QSet<QString> codesignBundle(const QString &identity, const QString &appBundlePath); void codesign(const QString &identity, const QString &appBundlePath); void createDiskImage(const QString &appBundlePath); |