Skip to content

Commit 9f3fcf8

Browse files
committed
fix(darwin): check every architecture slice for a linker signature
replace_linker_signatures asked `codesign -d` about a single slice, the one codesign reports by default for the build machine. The linker signs arm64 slices and leaves x86_64 slices unsigned unless linked with -adhoc_codesign, so python-build's universal stdlib modules carry a linker-signed arm64 slice next to an unsigned x86_64 one. On an Intel Mac the helper saw only the unsigned slice and skipped every such file, and a linker-signed x86_64 slice next to an ad-hoc arm64 one was missed on any machine. Each slice listed by `lipo -archs` is checked with `codesign -d --architecture`, and a file with any linker-signed slice is re-signed as a whole. `codesign --verify` cannot serve as a shortcut because it accepts linker signatures. The CI check inspects every slice the same way and names the offending one.
1 parent dafa10d commit 9f3fcf8

2 files changed

Lines changed: 35 additions & 22 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,12 +153,15 @@ jobs:
153153
linker_signed=0
154154
while IFS= read -r bin; do
155155
total=$((total + 1))
156-
case $(codesign -d --verbose=1 "$bin" 2>&1) in
157-
*"CodeDirectory "*linker-signed*)
158-
echo "::error::Linker-signed: ${bin#"$app"/}"
159-
linker_signed=$((linker_signed + 1))
160-
;;
161-
esac
156+
for arch in $(lipo -archs "$bin" 2>/dev/null); do
157+
case $(codesign -d --verbose=1 --architecture "$arch" "$bin" 2>&1) in
158+
*"CodeDirectory "*linker-signed*)
159+
echo "::error::Linker-signed ($arch slice): ${bin#"$app"/}"
160+
linker_signed=$((linker_signed + 1))
161+
break
162+
;;
163+
esac
164+
done
162165
done < <(find "$app/Contents/Resources" -type f \( -name '*.so' -o -name '*.so.*' -o -name '*.dylib' \))
163166
echo "Checked $total bundled native libraries, $linker_signed linker-signed."
164167
[ "$total" -gt 0 ] && [ "$linker_signed" -eq 0 ]

‎src/serious_python_darwin/darwin/linker_signatures.sh‎

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
# replace_linker_signatures <dir>...
44
#
55
# Re-signs ad-hoc every `.so`, `.so.*` and `.dylib` under the given directories
6-
# that carries the signature the linker attached when it built the file.
6+
# that has an architecture slice carrying the signature the linker attached
7+
# when it built the file.
78
#
89
# A linker signature names the code after the output file, extension included
910
# (`_ssl.cpython-314-darwin.so`), and codesign never carries metadata over from
@@ -16,17 +17,22 @@
1617
# designated Requirement"). A regular ad-hoc signature's identifier is carried
1718
# over by re-signing, so the requirement and the signature agree.
1819
#
19-
# Files are inspected one at a time, because `codesign -d` given several paths
20-
# stops at the first one that is not signed. Anything that is not
21-
# linker-signed -- already re-signed, unsigned, or not Mach-O at all -- is left
22-
# untouched, so a repeated run only re-checks. Ad-hoc signing is deterministic,
23-
# so re-signing a fresh copy of the same file reproduces the same bytes. Paths
24-
# containing newlines are not supported.
20+
# Every slice of a universal file is inspected, one file at a time: `codesign
21+
# -d` reports a single slice unless `--architecture` selects one, which slice
22+
# that is depends on the build machine, and given several paths it stops at the
23+
# first one that is not signed. The linker signs arm64 slices and usually
24+
# leaves x86_64 slices unsigned, so the linker signature is often on a slice
25+
# other than the reported one. `codesign --verify` accepts linker signatures,
26+
# so it cannot tell them apart. A file with any linker-signed slice is
27+
# re-signed, all slices at once. Anything else -- already re-signed, unsigned,
28+
# or not Mach-O at all -- is left untouched, so a repeated run only re-checks.
29+
# Ad-hoc signing is deterministic, so re-signing a fresh copy of the same file
30+
# reproduces the same bytes. Paths containing newlines are not supported.
2531
#
2632
# Returns non-zero, after printing the error, when a directory cannot be listed
2733
# or a file cannot be re-signed.
2834
replace_linker_signatures() {
29-
local dir files bin err
35+
local dir files bin archs arch err
3036
for dir in "$@"; do
3137
[ -d "$dir" ] || continue
3238
if ! files=$(find "$dir" -type f \( -name '*.so' -o -name '*.so.*' -o -name '*.dylib' \)); then
@@ -35,14 +41,18 @@ replace_linker_signatures() {
3541
fi
3642
while IFS= read -r bin; do
3743
[ -n "$bin" ] || continue
38-
case $(codesign -d --verbose=1 "$bin" 2>&1) in
39-
*"CodeDirectory "*linker-signed*) ;;
40-
*) continue ;;
41-
esac
42-
if ! err=$(codesign --force --sign - "$bin" 2>&1); then
43-
echo "replace_linker_signatures: codesign failed for $bin: $err" >&2
44-
return 1
45-
fi
44+
archs=$(lipo -archs "$bin" 2>/dev/null) || continue
45+
for arch in $archs; do
46+
case $(codesign -d --verbose=1 --architecture "$arch" "$bin" 2>&1) in
47+
*"CodeDirectory "*linker-signed*) ;;
48+
*) continue ;;
49+
esac
50+
if ! err=$(codesign --force --sign - "$bin" 2>&1); then
51+
echo "replace_linker_signatures: codesign failed for $bin: $err" >&2
52+
return 1
53+
fi
54+
break
55+
done
4656
done <<EOF
4757
$files
4858
EOF

0 commit comments

Comments
 (0)