Compare commits

..
7 changed files with 26 additions and 177 deletions

View file

@ -50,8 +50,8 @@ jobs:
# the FP6 patches to the next upstream version bump. Requires the
# PACKAGE_TOKEN repo secret (catbot account, package:write scope);
# skips quietly until it exists. 409 = same version already published.
# imsd and fingerprintd are skipped: build.sh 3b took them FROM the
# registry (re-signed for the chroot), so they are not ours to publish.
# imsd is skipped: build.sh 3b took it FROM the registry (re-signed
# for the chroot), so it is not ours to publish.
- name: Publish packages to the apk registry
env:
PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }}
@ -65,7 +65,7 @@ jobs:
for f in /home/build/.local/var/pmbootstrap/packages/*/aarch64/*.apk; do
[ -e "$f" ] || continue
case "$(basename "$f")" in
imsd-*|fingerprintd-*) echo "registry-sourced, not republished: $(basename "$f")"; continue ;;
imsd-*) echo "registry-sourced, not republished: $(basename "$f")"; continue ;;
esac
found=1
code=$(curl -s -o /dev/null -w '%{http_code}' \

View file

@ -14,9 +14,7 @@ Maintained by [Jorijn van der Graaf](https://catcrafts.net/about)
Everything on the `combined-stable` branch: display, touch, wifi, cellular
data, NFC (reader), speaker audio, microphone, IMU, magnetometer, barometer,
ambient light/proximity, fingerprint unlock through
[fingerprintd](https://forgejo.catcrafts.net/Catcrafts/fingerprintd), plus
VoLTE calls (both directions) through imsd.
ambient light/proximity plus VoLTE calls (both directions) through imsd.
## Flashing
@ -51,26 +49,4 @@ Find it in a stock-firmware capture or your carrier's IMS documentation, then
`systemctl restart imsd` (the service is enabled at boot and waits for this
file to exist). See the
[imsd README](https://forgejo.catcrafts.net/Catcrafts/imsd) for the full
variable reference and carrier assumptions.
## Fingerprint
Enrol under **Settings → Users** (Plasma's own fingerprint page; the `fprintd`
command-line tools are not installed, fingerprintd replaces that package).
**Hold** the finger on the sensor for each of the ~20 presses rather than
tapping it; a held press is what the matcher was measured on.
Two things to know:
- The lock screen listens for a finger for **60 seconds after it appears**.
A press after that reaches nothing and looks like a dead sensor. Lock and
unlock again to re-arm it.
- The matcher is the phone's own proprietary trustlet, reassembled from the
stock modem partition on first boot and never shipped by us. Templates are
stored on the Android `persist` partition, sealed to the same hardware
anti-rollback counter stock Android uses. Whether fingerprints enrolled under
stock Android survive a return to it after using this has **not** been
tested.
A finger can also run something in your session on a match
(`~/.config/fingerprintd/fingers.conf`, see the fingerprintd README).
variable reference and carrier assumptions.

View file

@ -14,7 +14,7 @@
maintainer="Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>"
pkgname=fp6-vendor-blobs
pkgver=1
pkgrel=2
pkgrel=1
pkgdesc="On-device extraction of vendor blobs from the stock Android partitions"
url="https://forgejo.catcrafts.net/Catcrafts/fp6-img"
arch="noarch"

View file

@ -10,7 +10,6 @@
# processed in sorted order; '#' comments and blank lines ignored:
#
# file <partition[,partition...]> <path-in-partition> <dest> <sha256>
# mbn <partition[,partition...]> <dir-in-partition> <name> <dest> <sha256>
# rebind <bus> <device>
#
# file: mount the first available listed partition READ-ONLY (ext4 also
@ -21,16 +20,6 @@
# unverified blob is never installed and a missing one never silently
# skipped. Dests that already exist are left alone (no hashing: a
# deliberately replaced file stays).
# mbn: the same, for a Qualcomm trustlet, which is not shipped as one file.
# QTEE images live in the modem partition's image/ as an ELF header+hashes
# file (<name>.mdt) plus one payload per program header (<name>.b00, .b01,
# ...), and the loader wants them written back at each segment's p_offset.
# Reassembly is therefore not a concatenation: segments are page aligned
# but not contiguous, gaps stay zero, and two segments may share an offset
# (focal64 has two such pairs), so they are written in index order and the
# later one wins. Same guarantees as file: the sha256 is of the reassembled
# image, a mismatch tries the next partition, and an unverified image is
# never installed.
# rebind: if this fragment's run extracted at least one file, unbind and
# re-probe <device> on <bus> so the consuming driver picks the file up
# in the same boot. Unconditional on purpose: a still-bound consumer may
@ -114,90 +103,6 @@ mount_part() {
MNT_PART=$1
}
# Little-endian scalars out of an ELF header. aarch64 is little endian and so
# is the image, so od's host order is the right one.
u64() { od -An -tu8 -j "$2" -N 8 "$1" | tr -d ' '; }
u16() { od -An -tu2 -j "$2" -N 2 "$1" | tr -d ' '; }
# Reassemble <dir>/<name>.mdt + .b0N into a flat image at <out>. Mirrors
# utilities/ta-analysis/reassemble.py in the fp6 bring-up repo, which is where
# the format was worked out and where the known-good hash comes from.
# POSIX sh has no locals, so these names are deliberately distinct from
# extract_mbn's: reassemble() taking rdir= would rewrite its CALLER's copy to
# the mount path, and the next partition in the retry loop would then be
# searched at $MNT/$MNT/...
reassemble() { # <dir> <name> <out>
mdir=$1 mname=$2 mout=$3
mdt="$mdir/$mname.mdt"
[ -f "$mdt" ] || return 1
phoff=$(u64 "$mdt" 32) phentsize=$(u16 "$mdt" 54) phnum=$(u16 "$mdt" 56)
[ -n "$phoff" ] && [ -n "$phentsize" ] && [ -n "$phnum" ] || return 1
[ "$phnum" -gt 0 ] 2>/dev/null || return 1
# The image is as long as the furthest segment reaches; everything no
# segment covers stays zero.
total=0 i=0
while [ "$i" -lt "$phnum" ]; do
o=$((phoff + i * phentsize))
pfsz=$(u64 "$mdt" $((o + 32)))
if [ "$pfsz" -gt 0 ]; then
poff=$(u64 "$mdt" $((o + 8)))
[ $((poff + pfsz)) -gt "$total" ] && total=$((poff + pfsz))
fi
i=$((i + 1))
done
[ "$total" -gt 0 ] || return 1
: > "$mout" || return 1
truncate -s "$total" "$mout" || return 1
i=0
while [ "$i" -lt "$phnum" ]; do
o=$((phoff + i * phentsize))
pfsz=$(u64 "$mdt" $((o + 32)))
if [ "$pfsz" -gt 0 ]; then
poff=$(u64 "$mdt" $((o + 8)))
seg=$(printf '%s/%s.b%02d' "$mdir" "$mname" "$i")
[ -f "$seg" ] || { log "$mname: segment $i missing"; return 1; }
# dd seeks in whole blocks, which is only correct because
# every p_offset in these images is page aligned. Refuse
# rather than silently misplace a segment if that changes.
[ $((poff % 4096)) -eq 0 ] || {
log "$mname: segment $i offset $poff is not page aligned"
return 1
}
dd if="$seg" of="$mout" bs=4096 seek=$((poff / 4096)) \
conv=notrunc 2>/dev/null || return 1
fi
i=$((i + 1))
done
return 0
}
extract_mbn() { # <partition,...> <dir-in-partition> <name> <dest> <sha256>
parts=$1 rdir=$2 rname=$3 dest=$4 want=$5
for part in $(echo "$parts" | tr ',' ' '); do
mount_part "$part" || { log "$part: not mountable, trying next"; continue; }
[ -f "$MNT/$rdir/$rname.mdt" ] || { log "$part: no $rdir/$rname.mdt, trying next"; continue; }
tmp="$dest.fp6-extract.$$"
mkdir -p "${dest%/*}" || fail "cannot create ${dest%/*}"
if ! reassemble "$MNT/$rdir" "$rname" "$tmp"; then
rm -f "$tmp"
log "$part: reassembling $rname failed, trying next"
continue
fi
got=$(sha256sum "$tmp" | awk '{print $1}')
if [ "$got" != "$want" ]; then
rm -f "$tmp"
log "$part:$rdir/$rname sha256 $got != expected, trying next"
continue
fi
chmod 644 "$tmp" && mv "$tmp" "$dest" || { rm -f "$tmp"; fail "installing $dest failed"; }
log "reassembled $part:$rdir/$rname.{mdt,b0N} -> $dest"
return 0
done
fail "no listed partition ($parts) yields $rname with sha256 $want - $dest NOT installed"
}
extract() { # <partition,...> <path-in-partition> <dest> <sha256>
parts=$1 src=$2 dest=$3 want=$4
for part in $(echo "$parts" | tr ',' ' '); do
@ -250,11 +155,8 @@ fi
missing=
for f in "$MANIFEST_DIR"/*.manifest; do
[ -e "$f" ] || continue
while read -r kind a b c d e; do
case "$kind" in
file) [ -e "$c" ] || missing=1 ;;
mbn) [ -e "$d" ] || missing=1 ;;
esac
while read -r kind _ _ dest _; do
[ "$kind" = file ] && [ ! -e "$dest" ] && missing=1
done < "$f"
done
[ -z "$missing" ] && exit 0
@ -263,7 +165,7 @@ for f in "$MANIFEST_DIR"/*.manifest; do
[ -e "$f" ] || continue
extracted=
rebinds=
while read -r kind a b c d e; do
while read -r kind a b c d; do
case "$kind" in
''|'#'*) ;;
file)
@ -272,12 +174,6 @@ for f in "$MANIFEST_DIR"/*.manifest; do
extract "$a" "$b" "$c" "$d" </dev/null
extracted=1
;;
mbn)
[ -n "$e" ] || fail "$f: malformed mbn line"
[ -e "$d" ] && continue
extract_mbn "$a" "$b" "$c" "$d" "$e" </dev/null
extracted=1
;;
rebind)
[ -n "$b" ] || fail "$f: malformed rebind line"
rebinds="$rebinds $a/$b"

View file

@ -8,7 +8,7 @@ _flavor="postmarketos-qcom-milos"
pkgname=linux-$_flavor
pkgver=7.2.0
# always sorts above the upstream aport (r0..r99)
pkgrel=101
pkgrel=100
pkgdesc="Milos mainline kernel + Catcrafts FP6 bring-up carries (combined-stable)"
arch="aarch64"
_carch="arm64"

View file

@ -7224,7 +7224,7 @@ CONFIG_TEE_DMABUF_HEAPS=y
CONFIG_OPTEE=y
# CONFIG_OPTEE_INSECURE_LOAD_IMAGE is not set
CONFIG_OPTEE_STATIC_PROTMEM_POOL=y
CONFIG_QCOMTEE=m
# CONFIG_QCOMTEE is not set
# CONFIG_MUX_CORE is not set
CONFIG_PM_OPP=y
# CONFIG_SIOX is not set

View file

@ -1,7 +1,6 @@
#!/bin/sh -eu
# fp6-img pipeline: build a flashable postmarketOS image for the Fairphone 6
# with the Catcrafts kernel (milos-linux combined-stable), imsd (VoLTE) and
# fingerprintd (fingerprint unlock)
# with the Catcrafts kernel (milos-linux combined-stable) and imsd (VoLTE)
# installed from the Catcrafts apk registry.
#
# Runs in CI inside an Alpine container on the privileged "pmos" runner
@ -31,19 +30,6 @@ IMSD_SHA256="
f1c317d7ff9448c05df068d683d31da08e4bfc074704d96cf52cb8acbdee6304 imsd-0.3.1-r0.apk
a78ef31fc2943ac02e120c46df26353d515ac9840d959cf5193b2afe1c665fa6 imsd-systemd-0.3.1-r0.apk
"
# fingerprintd (fingerprint unlock) comes from the same registry the same way:
# its repo's package CI is the only producer, and the same pinning rule holds.
# Three apks: the daemon, its systemd units, and the session agent (inert
# until a user writes ~/.config/fingerprintd/fingers.conf). Needs the kernel
# aport's CONFIG_QCOMTEE=m (pkgrel 101) and fp6-vendor-blobs >= 1-r2, both
# built in this run. 0.2.3: 0.2.2 (enrol, unlock, agent, actions) + the
# versioned blobs dependency + a post-upgrade daemon restart.
FPD_VERSION=0.2.3-r0
FPD_SHA256="
3e28f0c1a9a844592ab6878b2dfc0d8f91674549e44bdc1652e7d7d029de1765 fingerprintd-0.2.3-r0.apk
0cc46eba5c6c77d5bb54cd9f0e2902f7644720f9c98153062ffa33e19ca36889 fingerprintd-systemd-0.2.3-r0.apk
6dfdbc6f971ba4b8f811f828e5868869c7d71fea6c7045e2bffd51bf2736c040 fingerprintd-agent-0.2.3-r0.apk
"
PMAPORTS_REPO=https://gitlab.postmarketos.org/postmarketOS/pmaports.git
cd "$(dirname "$0")"
@ -229,7 +215,7 @@ aports = $WORK/pmaports
device = fairphone-fp6
ui = plasma-mobile
systemd = always
extra_packages = soc-fairphone-fp6-audio,callaudioshim,imsd,fingerprintd,fingerprintd-systemd,fingerprintd-agent,fp6-device-tweaks,fp6-charging-mode,catcrafts-fp6-repo,postmarketos-base-ui-audio-backend-pipewire,pipewire-pulse,pipewire-echo-cancel
extra_packages = soc-fairphone-fp6-audio,callaudioshim,imsd,fp6-device-tweaks,fp6-charging-mode,catcrafts-fp6-repo,postmarketos-base-ui-audio-backend-pipewire,pipewire-pulse,pipewire-echo-cancel
EOF
# All four source tarballs are generated locally above, so every checksum
@ -258,9 +244,9 @@ retry "build modemmanager" pmbootstrap $NOCROSS build --arch aarch64 modemmanage
# patched -r2 exists for the publish step even if the install set resolves
# it before the overlay is considered.
retry "build libcamera" pmbootstrap $NOCROSS build --arch aarch64 libcamera
# --- 3b. imsd + fingerprintd: the published apks, not local builds -----------
# Each repo's package CI is the only producer of its apk; the image installs
# the exact registry package users later get via 'apk upgrade'.
# --- 3b. imsd: the published apk, not a local build --------------------------
# The imsd repo's package CI is the only producer of the imsd apk; the image
# installs the exact registry package users later get via 'apk upgrade'.
# pmbootstrap has no knob for a third-party repository, and after the main
# 'apk add' it re-adds every package found in its local packages dir BY FILE
# PATH — which makes apk verify the package's own signature, and registry
@ -270,21 +256,13 @@ retry "build libcamera" pmbootstrap $NOCROSS build --arch aarch64 libcamera
# stay byte-identical, so the identity checksum equals the registry's), drop
# into the local packages dir, re-index. The abuild key exists because the
# builds above initialized the buildroot.
REG_DL="$WORK/registry-apks"
rm -rf "$REG_DL"
mkdir -p "$REG_DL"
for _f in "imsd-$IMSD_VERSION.apk" "imsd-systemd-$IMSD_VERSION.apk" \
"fingerprintd-$FPD_VERSION.apk" "fingerprintd-systemd-$FPD_VERSION.apk" \
"fingerprintd-agent-$FPD_VERSION.apk"; do
# every fetched file must have a pin: 'grep .' below drops empty lines,
# so an empty pin list would otherwise pass the check with nothing checked
printf '%s\n' "$IMSD_SHA256" "$FPD_SHA256" | grep -q " $_f\$" || {
echo "no sha256 pin for $_f - add it to IMSD_SHA256/FPD_SHA256" >&2
exit 1
}
retry "fetch $_f" curl -fsSL -o "$REG_DL/$_f" "$IMSD_REGISTRY/aarch64/$_f"
IMSD_DL="$WORK/imsd-apk"
rm -rf "$IMSD_DL"
mkdir -p "$IMSD_DL"
for _f in "imsd-$IMSD_VERSION.apk" "imsd-systemd-$IMSD_VERSION.apk"; do
retry "fetch $_f" curl -fsSL -o "$IMSD_DL/$_f" "$IMSD_REGISTRY/aarch64/$_f"
done
(cd "$REG_DL" && printf '%s\n' "$IMSD_SHA256" "$FPD_SHA256" | grep . | sha256sum -c -)
(cd "$IMSD_DL" && printf '%s\n' "$IMSD_SHA256" | grep . | sha256sum -c -)
ABUILD_KEY=$(echo "$WORKDIR"/config_abuild/*.rsa)
if [ ! -f "$ABUILD_KEY" ]; then
echo "expected exactly one abuild key in $WORKDIR/config_abuild" >&2
@ -293,9 +271,9 @@ fi
# abuild-keygen ran inside the chroot as pmbootstrap's user (uid 12345), so
# the key is 0600 to that uid and unreadable here (run 49 died on exactly
# this); sign from a private copy taken via sudo, then drop it.
KEYCOPY="$REG_DL/abuild-key.rsa"
KEYCOPY="$IMSD_DL/abuild-key.rsa"
sudo install -m 0600 -o "$(id -un)" "$ABUILD_KEY" "$KEYCOPY"
for _f in "$REG_DL"/*.apk; do
for _f in "$IMSD_DL"/*.apk; do
python3 ./apk-resign.py "$_f" "$KEYCOPY" "$(basename "$ABUILD_KEY").pub"
done
rm -f "$KEYCOPY"
@ -308,11 +286,11 @@ if [ ! -d "$PKGDIR" ]; then
echo "$PKGDIR missing - the package builds above should have created it" >&2
exit 1
fi
for _f in "$REG_DL"/*.apk; do
for _f in "$IMSD_DL"/*.apk; do
sudo install -m 0644 -o "$(stat -c %u "$PKGDIR")" -g "$(stat -c %g "$PKGDIR")" \
"$_f" "$PKGDIR/$(basename "$_f")"
done
rm -f "$REG_DL"/*.apk
rm -f "$IMSD_DL"/*.apk
pmbootstrap index
# --- 4. build the image -------------------------------------------------------
@ -345,7 +323,6 @@ cp README.md install.sh "$STAGE/fp6-img/"
echo "built: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
echo "default login: user / 147147 (same as official postmarketOS images)"
echo "imsd: $IMSD_REGISTRY imsd-$IMSD_VERSION (registry package, sha256-pinned)"
echo "fingerprintd: $IMSD_REGISTRY fingerprintd-$FPD_VERSION (registry package, sha256-pinned)"
} > "$STAGE/fp6-img/build-info.txt"
# sums of the extracted contents
(cd "$STAGE/fp6-img" && sha256sum -- * > sha256sums.txt)