mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-04 04:52:39 +08:00
[fix] include OpenSSL resource symbols in iOS archives
This commit is contained in:
@@ -222,6 +222,7 @@
|
||||
300000000000000000000001 /* Frameworks */,
|
||||
600000000000000000000002 /* Resources */,
|
||||
300000000000000000000002 /* Embed Frameworks */,
|
||||
700000000000000000000002 /* Generate OpenSSL symbols */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -318,6 +319,24 @@
|
||||
shellPath = /bin/zsh;
|
||||
shellScript = "set -e\npython3 \"${PROJECT_DIR}/scripts/prepare_source_metadata.py\" --output \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SourceMetadata.json\"\n\"${PROJECT_DIR}/scripts/build_minirtc_ios.sh\"\npython3 \"${PROJECT_DIR}/scripts/verify_native_build.py\" --inputs \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --xmake-version \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/xmake-version.txt\"\npython3 \"${PROJECT_DIR}/scripts/package_openssl_ios.py\" --inputs \"${PROJECT_DIR}/Vendor/${PLATFORM_NAME}/${CONFIGURATION}/libCrossDeskMiniRTC.a.inputs.sha256\" --output \"${BUILT_PRODUCTS_DIR}/OpenSSL.framework\" --platform \"${PLATFORM_NAME}\"\n";
|
||||
};
|
||||
700000000000000000000002 /* Generate OpenSSL symbols */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"$(TARGET_BUILD_DIR)/$(FRAMEWORKS_FOLDER_PATH)/OpenSSL.framework/OpenSSL",
|
||||
"$(PROJECT_DIR)/scripts/generate_openssl_symbols.py",
|
||||
);
|
||||
name = "Generate OpenSSL symbols";
|
||||
outputPaths = (
|
||||
"$(DWARF_DSYM_FOLDER_PATH)/OpenSSL.framework.dSYM/Contents/Resources/DWARF/OpenSSL",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/zsh;
|
||||
shellScript = "set -e\nif [[ \"${DEBUG_INFORMATION_FORMAT}\" == \"dwarf-with-dsym\" ]]; then\n python3 -B \"${PROJECT_DIR}/scripts/generate_openssl_symbols.py\" --binary \"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework/OpenSSL\" --output \"${DWARF_DSYM_FOLDER_PATH}/OpenSSL.framework.dSYM\"\nfi\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -496,7 +515,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 3;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
@@ -548,7 +567,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 3;
|
||||
CURRENT_PROJECT_VERSION = 4;
|
||||
ENABLE_BITCODE = NO;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
|
||||
@@ -586,6 +586,16 @@ Xcode removes the static archive from the embedded framework (it may insert a
|
||||
small resource-framework stub) and preserves `PrivacyInfo.xcprivacy`, source
|
||||
metadata and license texts. The application does not load a dynamic OpenSSL copy.
|
||||
|
||||
For builds using `DWARF with dSYM File`, the **Generate OpenSSL symbols** phase
|
||||
runs after embedding. It verifies that Xcode's placeholder has no executable
|
||||
code, generates `OpenSSL.framework.dSYM` from that exact binary, and checks its
|
||||
UUIDs. This companion describes the empty resource stub, not the statically
|
||||
linked OpenSSL implementation. Xcode includes it alongside the app's dSYM in
|
||||
the archive so Organizer can upload symbols for every embedded Mach-O binary.
|
||||
`verify_app_bundle.py` checks both UUID matches when given an archived app;
|
||||
for an ordinary Release build, pass `--dsym-dir /path/to/Release-iphoneos`.
|
||||
The CI ZIP includes both dSYM bundles.
|
||||
|
||||
The iOS-specific OpenSSL recipe disables POSIX metadata calls, automatic
|
||||
`openssl.cnf` loading, and the unused file-URI store provider. It selects the
|
||||
upstream `getrandom` entropy backend, which uses Darwin's `getentropy` on the
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate matching symbols for Xcode's embedded, codeless OpenSSL framework."""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def uuids(path):
|
||||
output = subprocess.check_output(["xcrun", "dwarfdump", "--uuid", str(path)], text=True)
|
||||
result = dict((arch, uuid.upper()) for uuid, arch in
|
||||
re.findall(r"UUID: ([0-9A-Fa-f-]{36}) \(([^)]+)\)", output))
|
||||
if not result:
|
||||
raise ValueError(f"No Mach-O UUIDs found: {path}")
|
||||
return result
|
||||
|
||||
|
||||
def verify_symbols(binary, dsym):
|
||||
dwarf = dsym / "Contents/Resources/DWARF" / binary.name
|
||||
if not dwarf.is_file():
|
||||
raise ValueError(f"Missing dSYM DWARF file: {dwarf}")
|
||||
if uuids(binary) != uuids(dwarf):
|
||||
raise ValueError(f"dSYM UUIDs do not match {binary}: {dwarf}")
|
||||
|
||||
|
||||
def generate(binary, output):
|
||||
# This is only for Xcode's resource placeholder. Real OpenSSL code remains
|
||||
# statically linked into the app and must not receive an empty dSYM here.
|
||||
commands = subprocess.check_output(["xcrun", "otool", "-l", str(binary)], text=True)
|
||||
text_sizes = re.findall(
|
||||
r"sectname __text\s+segname __TEXT\s+addr \S+\s+size (0x[0-9a-fA-F]+)", commands)
|
||||
if not text_sizes or any(int(size, 16) for size in text_sizes):
|
||||
raise ValueError(f"Expected a codeless OpenSSL resource stub: {binary}")
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
# No function-level debug info exists in this empty stub. dsymutil still
|
||||
# emits a valid UUID-matched DWARF companion; quiet suppresses that expected
|
||||
# warning only after verifying that there is no executable code to lose.
|
||||
subprocess.run(["xcrun", "dsymutil", "--quiet", str(binary), "-o", str(output)], check=True)
|
||||
verify_symbols(binary, output)
|
||||
subprocess.run(["xcrun", "dwarfdump", "--verify", str(output)], check=True)
|
||||
print(f"Generated UUID-matched OpenSSL resource symbols: {output}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--binary", required=True, type=Path)
|
||||
parser.add_argument("--output", required=True, type=Path)
|
||||
args = parser.parse_args()
|
||||
generate(args.binary, args.output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
except (OSError, ValueError, subprocess.CalledProcessError) as error:
|
||||
print(f"OpenSSL symbols: {error}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
@@ -10,8 +10,10 @@ import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from generate_openssl_symbols import verify_symbols
|
||||
|
||||
def verify(app, require_release=False):
|
||||
|
||||
def verify(app, require_release=False, dsym_dir=None):
|
||||
info = plistlib.loads((app / "Info.plist").read_bytes())
|
||||
binary = app / info["CFBundleExecutable"]
|
||||
subprocess.run(["xcrun", "lipo", str(binary), "-verify_arch", "arm64"], check=True)
|
||||
@@ -63,6 +65,14 @@ def verify(app, require_release=False):
|
||||
sdk_symbols = subprocess.check_output(["xcrun", "nm", "-gU", str(embedded_binary)], text=True)
|
||||
if re.search(r"\b_(?:SSL_new|OPENSSL_init_crypto)\b", sdk_symbols):
|
||||
raise ValueError("Unexpected dynamic OpenSSL implementation in resource framework")
|
||||
# Archive validation includes the exact files that Organizer uploads.
|
||||
if dsym_dir is None and app.parents[2].suffix == ".xcarchive":
|
||||
dsym_dir = app.parents[2] / "dSYMs"
|
||||
if dsym_dir is not None:
|
||||
verify_symbols(binary, dsym_dir / f"{app.name}.dSYM")
|
||||
if embedded_binary.exists():
|
||||
verify_symbols(embedded_binary, dsym_dir / "OpenSSL.framework.dSYM")
|
||||
print("Verified app and embedded OpenSSL dSYM UUIDs")
|
||||
linked = subprocess.check_output(["xcrun", "otool", "-L", str(binary)], text=True)
|
||||
if "OpenSSL.framework" in linked:
|
||||
raise ValueError("OpenSSL must be statically linked into the application")
|
||||
@@ -79,8 +89,9 @@ def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("app", type=Path)
|
||||
parser.add_argument("--require-release", action="store_true")
|
||||
parser.add_argument("--dsym-dir", type=Path)
|
||||
args = parser.parse_args()
|
||||
verify(args.app, args.require_release)
|
||||
verify(args.app.resolve(), args.require_release, args.dsym_dir)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user