sycamore_row_5G: sync validated TWRP bring-up

This commit is contained in:
Nicholas Andrew 2026-09-01 18:02:27 -04:00
commit 3745f771d4
244 changed files with 240 additions and 4201 deletions

View file

@ -10,46 +10,3 @@ cc_prebuilt_library_shared {
none: true,
},
}
cc_binary {
name: "sycamore_fscryptd",
defaults: [
"vold_default_flags",
"vold_default_libs",
],
srcs: ["fscryptd/sycamore_fscryptd.cpp"],
include_dirs: ["vendor/twrp/libfscrypt/include"],
static_libs: ["libvold_fscrypt_helper"],
header_libs: ["libvold_headers"],
shared_libs: [
"android.hardware.confirmationui@1.0",
"android.hardware.gatekeeper@1.0",
"android.hardware.health.storage@1.0",
"android.hardware.health.storage-V1-ndk_platform",
"android.hardware.keymaster@4.1",
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.weaver@1.0",
"android.security.apc-ndk_platform",
"android.system.keystore2-V1-ndk_platform",
"android.security.authorization-ndk_platform",
"android.security.maintenance-ndk_platform",
"libbase",
"libbinder",
"libbinder_ndk",
"libgatekeeper",
"libgatekeeper_aidl",
"libhardware",
"libhidlbase",
"libkeymaster4_1support",
"libkeystoreinfo",
"libkeystore-attestation-application-id",
"libkeymint_support",
"liblog",
"libchrome",
],
cflags: [
"-Wall",
"-Werror",
"-Wextra",
],
}

View file

@ -54,15 +54,4 @@ $(eval $(call sycamore-recovery-library,sycamore_soft_attestation,libsoft_attest
$(eval $(call sycamore-recovery-library,sycamore_cppbor_external,libcppbor_external.so,vendor/lib64))
$(eval $(call sycamore-recovery-library,sycamore_cppcose_rkp,libcppcose_rkp.so,vendor/lib64))
# Diagnostic V8 only: observe the 64-byte STORAGE_KEY at Beanpod's final
# userspace boundary, then tail-call the byte-identical stock A16 function.
include $(CLEAR_VARS)
LOCAL_MODULE := libsycamore_keytrace
LOCAL_SRC_FILES := diagnostics/keytrace.cpp
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/vendor/lib64
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES := libcrypto libdl liblog
include $(BUILD_SHARED_LIBRARY)
endif

View file

@ -102,13 +102,24 @@ endif
# PLATFORM already provides the complete stock module tree. Remove the duplicate
# device recovery metadata after recovery-root population and before mkbootfs;
# otherwise its recovery-oriented modules.load shadows the stock normal list.
# Final recovery-root preparation:
# - remove duplicate recovery module metadata so the pristine PLATFORM ramdisk wins
# - present the exact production XT2575-4 vendor identity before Microtrust starts
BOARD_RECOVERY_IMAGE_PREPARE = test -n "$(TARGET_RECOVERY_ROOT_OUT)" && \
rm -rf -- "$(TARGET_RECOVERY_ROOT_OUT)/lib/modules"
TARGET_RECOVERY_PIXEL_FORMAT := "BGRA_8888"
RECOVERY_GRAPHICS_FORCE_USE_LINELENGTH := true
rm -rf -- "$(TARGET_RECOVERY_ROOT_OUT)/lib/modules" && \
sed -i \
-e 's/^ro.product.vendor.device=sycamore_row_5G$$/ro.product.vendor.device=XT2575-4/' \
-e 's/^ro.product.vendor.name=twrp_sycamore_row_5G$$/ro.product.vendor.name=XT2575-4/' \
"$(TARGET_RECOVERY_ROOT_OUT)/prop.default" && \
grep -Fqx 'ro.product.device=XT2575-4' "$(TARGET_RECOVERY_ROOT_OUT)/prop.default" && \
grep -Fqx 'ro.product.vendor.device=XT2575-4' "$(TARGET_RECOVERY_ROOT_OUT)/prop.default" && \
grep -Fqx 'ro.product.vendor.name=XT2575-4' "$(TARGET_RECOVERY_ROOT_OUT)/prop.default" && \
grep -Fqx 'ro.product.vendor.model=XT2575-4' "$(TARGET_RECOVERY_ROOT_OUT)/prop.default" && \
grep -Fqx 'ro.build.product=sycamore_row_5G' "$(TARGET_RECOVERY_ROOT_OUT)/prop.default"
TARGET_RECOVERY_PIXEL_FORMAT := RGBX_8888
BOARD_HAS_NO_SELECT_BUTTON := true
# V18: exact production teei_daemon domain and narrowly scoped Microtrust
# Exact production teei_daemon domain and narrowly scoped Microtrust
# device labels. The platform policy already defines tee/tee_exec and its
# init transition; this directory supplies only Sycamore-specific paths/types.
BOARD_VENDOR_SEPOLICY_DIRS += $(DEVICE_PATH)/sepolicy/vendor
@ -126,39 +137,18 @@ TW_INCLUDE_FASTBOOTD := true
# Preserve the device recovery.fstab mount options. The stock additional fstab
# otherwise reparses /metadata and drops its recovery-only context= option.
TW_SKIP_ADDITIONAL_FSTAB := true
# Build the crypto-only helper against the existing platform libvold, then use
# TeamWin's supported device hook to relink it into recovery /system/bin.
TW_RECOVERY_ADDITIONAL_RELINK_BINARY_FILES += $(TARGET_OUT_EXECUTABLES)/sycamore_fscryptd
# The generic TWRP 12.1 synthetic /super object exposes raw restore/image
# writes while logical mappings are live. Keep super discovery, but hide those
# unsafe UI operations on this virtual A/B device.
TW_EXCLUDE_SUPER_BACKUP_FLASH := true
TW_INTERNAL_STORAGE_PATH := "/data/media/0"
TW_INTERNAL_STORAGE_MOUNT_POINT := "data"
TW_USB_STORAGE := false
# Runtime diagnostic: the initial configfs ADB gadget works, but entering the
# GUI makes TWRP request mtp,adb. This tree has no configfs mtp,adb property
# action, so that transition unbinds the UDC and loses all host enumeration.
# Keep the proven adb-only gadget until MTK configfs MTP is implemented.
# Tree-only FBE diagnostic: avoid twrpApex::loadApexImage(), whose TWRP 12.1
# implementation seeks an already-closed payload fd. Recovery's own crypto
# binaries and libraries are packaged in the ramdisk, so first prove the stock
# KeyMint/TEE chain without depending on Android's runtime APEX mounts. The
# generic source correction is retained separately as patch 0002.
# TWRP 12.1's APEX loader is incompatible with this recovery's crypto path.
# Sycamore packages the required Android 16 crypto binaries and libraries
# directly in the recovery ramdisk, so recovery APEX mounting is unnecessary.
TW_EXCLUDE_APEX := true
# Stock FBE v2 + metadata encryption. Branch must provide Android 15/16 crypto.
# Temporary first-hardware-boot diagnostic: keep /data encrypted and unmounted,
# and bypass the synchronous Android 16 metadata/FBE decrypt path so the GUI
# can start. Re-enable these only after the KeyMint/Keystore2 dependency chain
# is made compatible with the stock Android 16 vendor environment.
SYCAMORE_DIAGNOSTIC_NO_DECRYPT := false
ifneq ($(SYCAMORE_DIAGNOSTIC_NO_DECRYPT),true)
# Stock FBE v2 with metadata encryption.
TW_INCLUDE_CRYPTO := true
TW_INCLUDE_CRYPTO_FBE := true
TW_INCLUDE_FBE_METADATA_DECRYPT := true
endif
BOARD_USES_METADATA_PARTITION := true
# Bring-up/debug essentials; no missing-dependency escape hatch.
@ -171,7 +161,6 @@ TW_EXCLUDE_DEFAULT_USB_INIT := true
TW_DEFAULT_LANGUAGE := en
TW_EXTRA_LANGUAGES := true
TW_USE_SERIALNO_PROPERTY_FOR_DEVICE_ID := true
# Preserve the exact factory vendor_boot AVB fingerprint independently of the
# recovery build fingerprint.
BOARD_AVB_VENDOR_BOOT_FINGERPRINT := Motorola/XT2575-4/XT2575-4:15/AP3A.240905.015.A2/9bdeac_017:user/release-keys
@ -185,8 +174,8 @@ BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS += \
# Removable storage filesystem support.
TW_INCLUDE_NTFS_3G := true
# R7v9.60: platform-side TWRP FBE property definition
# Platform-side TWRP FBE property definition.
SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS += device/motorola/sycamore_row_5G/sepolicy/public
# R7v9.60: platform-side TWRP FBE property context
# Platform-side TWRP FBE property context.
SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS += device/motorola/sycamore_row_5G/sepolicy/private

View file

@ -1,162 +0,0 @@
DEVICE_PATH := device/motorola/sycamore_row_5G
# Architecture (64-bit recovery; runtime CPU properties identify Cortex-A55/A76 cores).
TARGET_ARCH := arm64
TARGET_ARCH_VARIANT := armv8-a
TARGET_CPU_ABI := arm64-v8a
TARGET_CPU_ABI2 :=
TARGET_CPU_VARIANT := generic
TARGET_CPU_VARIANT_RUNTIME := cortex-a55
TARGET_USES_64_BIT_BINDER := true
# Platform and assertions.
TARGET_BOARD_PLATFORM := mt6835
TARGET_BOOTLOADER_BOARD_NAME := sycamore_row_5G
TARGET_NO_BOOTLOADER := true
TARGET_OTA_ASSERT_DEVICE := sycamore_row_5G,XT2575-4
# Stock first API level is 35, but twrp-12.1 is an API 32 build and rejects a
# BOARD_SHIPPING_API_LEVEL newer than its platform SDK. Keep the measured value
# in the bring-up log rather than emitting a false API-32 build property.
# The stock Beanpod KeyMint service configures its TA from these properties.
# Pristine A16 vendor_boot supplies 2026-07-05 for both, and the live metadata
# key blob is bound to OS patch level 202607. Leaving the TWRP 12.1 defaults
# (202204 / empty) makes secure world reject that newer blob as a downgrade.
# These are exact stock inputs, not the old twrpdtgen 2099 bypass.
PLATFORM_SECURITY_PATCH := 2026-07-05
VENDOR_SECURITY_PATCH := 2026-07-05
# Exact factory kernel, DTB, and vendor_boot v4 header addresses. These values
# are mechanically extracted from the pristine ZUI 17.5 vendor_boot image.
TARGET_PREBUILT_KERNEL := $(DEVICE_PATH)/prebuilt/kernel
BOARD_INCLUDE_DTB_IN_BOOTIMG := true
BOARD_PREBUILT_DTBIMAGE_DIR := $(DEVICE_PATH)/prebuilt/dtb
BOARD_BOOT_HEADER_VERSION := 4
BOARD_KERNEL_PAGESIZE := 4096
BOARD_KERNEL_BASE := 0x40000000
BOARD_RAMDISK_USE_LZ4 := true
BOARD_KERNEL_SEPARATED_DTBO := true
BOARD_MKBOOTIMG_ARGS += --header_version $(BOARD_BOOT_HEADER_VERSION)
BOARD_MKBOOTIMG_ARGS += --kernel_offset 0x00000000
BOARD_MKBOOTIMG_ARGS += --ramdisk_offset 0x26f00000
BOARD_MKBOOTIMG_ARGS += --tags_offset 0x07c80000
BOARD_MKBOOTIMG_ARGS += --dtb_offset 0x07c80000
BOARD_MKBOOTIMG_ARGS += --vendor_cmdline "bootopt=64S3,32N2,64N2"
# Preserve the pristine stock vendor ramdisk byte-for-byte as the unnamed base
# PLATFORM ramdisk. AOSP then appends the generated TWRP RECOVERY fragment.
# This matches the factory vendor_boot v4 layout and preserves overlay ordering.
BOARD_PREBUILT_VENDOR_RAMDISK := \
$(DEVICE_PATH)/prebuilt/vendor_ramdisk/platform.cpio.lz4
# Physical partition sizes measured from GPT/factory images.
BOARD_BOOTIMAGE_PARTITION_SIZE := 67108864
BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE := 67108864
BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE := 8388608
BOARD_DTBOIMG_PARTITION_SIZE := 8388608
BOARD_PREBUILT_DTBOIMAGE := $(DEVICE_PATH)/prebuilt/dtbo.img
# Live liblp metadata: v10.2, 64 KiB max metadata, three slots, virtual A/B.
BOARD_SUPER_PARTITION_SIZE := 11811160064
BOARD_SUPER_PARTITION_GROUPS := main_dynamic_partitions
BOARD_MAIN_DYNAMIC_PARTITIONS_SIZE := 11809062912
# API-32 build/make cannot generate system_dlkm. It remains in recovery.fstab
# and live liblp metadata; this recovery-only target does not build super.
BOARD_MAIN_DYNAMIC_PARTITIONS_PARTITION_LIST := \
odm_dlkm product system system_ext vendor vendor_dlkm
TARGET_COPY_OUT_SYSTEM_EXT := system_ext
TARGET_COPY_OUT_PRODUCT := product
TARGET_COPY_OUT_VENDOR := vendor
TARGET_COPY_OUT_VENDOR_DLKM := vendor_dlkm
TARGET_COPY_OUT_ODM_DLKM := odm_dlkm
BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE := erofs
BOARD_SYSTEM_EXTIMAGE_FILE_SYSTEM_TYPE := erofs
BOARD_PRODUCTIMAGE_FILE_SYSTEM_TYPE := erofs
BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := erofs
BOARD_VENDOR_DLKMIMAGE_FILE_SYSTEM_TYPE := erofs
BOARD_ODM_DLKMIMAGE_FILE_SYSTEM_TYPE := erofs
BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE := f2fs
TARGET_USERIMAGES_USE_EXT4 := true
TARGET_USERIMAGES_USE_F2FS := true
# Recovery lives in vendor_boot. AOSP build/make emits a v4 RECOVERY ramdisk
# fragment when both switches below are true; stock's platform fragment already
# proves that all recovery resources belong in vendor_boot on this device.
TARGET_NO_RECOVERY := true
TW_HAS_NO_RECOVERY_PARTITION := true
BOARD_EXCLUDE_KERNEL_FROM_RECOVERY_IMAGE := true
BOARD_MOVE_RECOVERY_RESOURCES_TO_VENDOR_BOOT := true
BOARD_INCLUDE_RECOVERY_RAMDISK_IN_VENDOR_BOOT := true
TARGET_RECOVERY_FSTAB := $(DEVICE_PATH)/recovery.fstab
TARGET_RECOVERY_PIXEL_FORMAT := RGBX_8888
BOARD_HAS_NO_SELECT_BUTTON := true
# V18: exact production teei_daemon domain and narrowly scoped Microtrust
# device labels. The platform policy already defines tee/tee_exec and its
# init transition; this directory supplies only Sycamore-specific paths/types.
BOARD_VENDOR_SEPOLICY_DIRS += $(DEVICE_PATH)/sepolicy/vendor
# Display values measured from Android.
TARGET_SCREEN_WIDTH := 1600
TARGET_SCREEN_HEIGHT := 2560
TARGET_SCREEN_DENSITY := 320
TW_THEME := portrait_hdpi
TW_FRAMERATE := 90
# A/B, dynamic partitions, fastbootd and storage.
AB_OTA_UPDATER := true
TW_INCLUDE_FASTBOOTD := true
TW_INTERNAL_STORAGE_PATH := "/data/media/0"
TW_INTERNAL_STORAGE_MOUNT_POINT := "data"
TW_BACKUP_DATA_MEDIA := true
TW_USB_STORAGE := false
# Runtime diagnostic: the initial configfs ADB gadget works, but entering the
# GUI makes TWRP request mtp,adb. This tree has no configfs mtp,adb property
# action, so that transition unbinds the UDC and loses all host enumeration.
# Keep the proven adb-only gadget until MTK configfs MTP is implemented.
TW_EXCLUDE_MTP := true
# Tree-only FBE diagnostic: avoid twrpApex::loadApexImage(), whose TWRP 12.1
# implementation seeks an already-closed payload fd. Recovery's own crypto
# binaries and libraries are packaged in the ramdisk, so first prove the stock
# KeyMint/TEE chain without depending on Android's runtime APEX mounts. The
# generic source correction is retained separately as patch 0002.
TW_EXCLUDE_APEX := true
# Stock FBE v2 + metadata encryption. Branch must provide Android 15/16 crypto.
# Temporary first-hardware-boot diagnostic: keep /data encrypted and unmounted,
# and bypass the synchronous Android 16 metadata/FBE decrypt path so the GUI
# can start. Re-enable these only after the KeyMint/Keystore2 dependency chain
# is made compatible with the stock Android 16 vendor environment.
SYCAMORE_DIAGNOSTIC_NO_DECRYPT := false
ifneq ($(SYCAMORE_DIAGNOSTIC_NO_DECRYPT),true)
TW_INCLUDE_CRYPTO := true
TW_INCLUDE_CRYPTO_FBE := true
TW_INCLUDE_FBE_METADATA_DECRYPT := true
endif
BOARD_USES_METADATA_PARTITION := true
# Bring-up/debug essentials; no missing-dependency escape hatch.
TARGET_USES_LOGD := true
TWRP_INCLUDE_LOGCAT := true
TW_INCLUDE_REPACKTOOLS := true
TW_INCLUDE_RESETPROP := true
TW_INCLUDE_LIBRESETPROP := true
TW_EXCLUDE_DEFAULT_USB_INIT := true
TW_DEFAULT_LANGUAGE := en
TW_EXTRA_LANGUAGES := true
# Preserve the exact factory vendor_boot AVB fingerprint independently of the
# recovery build fingerprint.
BOARD_AVB_VENDOR_BOOT_FINGERPRINT := Motorola/XT2575-4/XT2575-4:15/AP3A.240905.015.A2/9bdeac_017:user/release-keys
# Match the stock algorithm-NONE vendor_boot hash-footer design. The salt is
# extracted from the pristine footer; no signing key is used or invented.
BOARD_AVB_ENABLE := true
BOARD_AVB_VENDOR_BOOT_ADD_HASH_FOOTER_ARGS += \
--salt 11503e95ee971adc6c444e3ae47f564f178032ee9bbcf99d2ccfdc0895c67ed7
# Removable storage filesystem support.
TW_INCLUDE_NTFS_3G := true

View file

@ -1,228 +0,0 @@
# Sycamore Android 16 FBE cmd 0x18 investigation
Date: 2026-08-27
Baseline: hardware-tested V14 wrapped-first vendor_boot, SHA-256
`d657365e5c14ba0bc1e93e9fc0ec38acb18f935e222d1bae66377011b96b9d15`.
Evidence labels in this report are **PROVEN**, **EXPECTED**, **UNKNOWN**, and
**EXCLUDED**.
## A. Recovery state immediately before the first cmd 0x18
The first V14 conversion is at `v14-native-runtime-failure/logcat-all.txt:2942-2957`,
at 19:01:29.957-19:01:29.959. Before that point recovery had already proven:
- `vendor.soter.teei.init=INIT_OK`
- `vendor.soter.teei.km.init=config_patch_level_sucess`
- `vendor.soter.teei.km.version=v2.0.0`
- `vendor.soter.teei.persist=OPEN`
- `vendor.soter.teei.rpmb.flag=ok`
- persist selector 3
- successful c09 TA load, secure-storage manager startup, physical RPMB commands,
`rpmb key is programmed`, KeyMint configuration, SharedSecret, metadata unwrap,
systemwide outer unwrap, and one stock-shaped Begin/Update/Finish sequence.
The retained recovery property dump does not contain:
- `vendor.soter.teei.googlekey.status`
- `vendor.soter.teei.logini`
Recovery later logs `logini thread failed` at 19:02:05.108, about 35 seconds after
the first failure. This proves a final recovery-state difference, but does not prove
that logini participates in cmd 0x18.
## B. Healthy-stock Soter comparison
The archived stock snapshot contains:
| Property | Stock snapshot | V14 retained state before/around failure |
|---|---|---|
| `vendor.soter.teei.googlekey.status` | `ok` | absent |
| `vendor.soter.teei.init` | `INIT_OK` | `INIT_OK` |
| `vendor.soter.teei.km.init` | `config_patch_level_sucess` | same |
| `vendor.soter.teei.km.version` | `v2.0.0` | `v2.0.0` |
| `vendor.soter.teei.logini` | `start` | absent; later logini thread failure |
| `vendor.soter.teei.persist` | `OPEN` | `OPEN` |
| `vendor.soter.teei.rpmb.flag` | `ok` | `ok` |
Stock `microtrust.rc:245-246` sets `vendor.soter.teei.logini=start` on the Android
`post-fs-data` trigger. It is an init-set request to `teei_daemon`, not proof by
itself that a secure-world transition completed. The stock property snapshot was
captured after DE storage was available, so it cannot prove that logini preceded
stock's first storage-key conversion. Android init describes `post-fs-data` as the
stage at which `/data` has already been mounted; therefore forcing logini before
conversion would not reproduce a proven stock ordering.
No local rc file was found that directly sets `googlekey.status`. The value is
therefore **EXPECTED** to be service/secure-world-derived, but its exact setter and
pre-conversion timing remain **UNKNOWN**.
Conclusion: `persist=OPEN` and `rpmb.flag=ok` are matched and correspond to observed
real VFS/RPMB activity. `logini` and `googlekey.status` differ in final visibility,
but neither is yet connected to cmd 0x18 timing.
## C. Exact 64-byte storage-key provenance
The source directory is `/data/unencrypted/key`:
1. `keymaster_key_blob` is a 444-byte ordinary KeyMint AES wrapping-key blob,
SHA-256
`24449b28dedeecc82b0abfb571ef6aa93151608e841fbbf9dd9bdb907ff89c87`.
2. `secdiscardable` contributes to the application ID computed by
`KeyStorage.cpp::generateAppId()`.
3. `encrypted_key` is a 92-byte AES-GCM container: 12-byte nonce, 64-byte
ciphertext/plaintext length, and 16-byte tag. Its SHA-256 is
`7700695d0e5c1605d9d1c56669cb4130588c1054766ac735488fa76f4fd47312`.
4. `retrieveKey()` reads the files at `system/vold/KeyStorage.cpp:630-652`.
5. `decryptWithKeymasterKey()` authenticates and decrypts the 92-byte container.
6. The resulting 64-byte plaintext is the proprietary `TAG_STORAGE_KEY` blob.
7. `exportWrappedStorageKey()` at `system/vold/KeyStorage.cpp:189-197` copies it
without transformation into `Keymaster::exportKey()`.
8. `Keymaster::exportKey()` at `system/vold/Keymaster.cpp:167-191` places the same
bytes in a `Domain::BLOB` descriptor.
9. Keystore2 at `system/security/keystore2/src/security_level.rs:892-962` passes
the byte vector unchanged to `IKeyMintDevice::convertStorageKeyToEphemeral()`.
10. Beanpod serializes the legacy export request as 12-byte empty AuthorizationSet,
4-byte RAW KeyFormat, 4-byte blob length, and the 64-byte blob: 84 bytes total.
V14 hash-only checkpoints A, B, C, and D all report 64 bytes with SHA-256
`3c36a06c93c07adeda069dd413b2df8f2e9b54371f3920e5de40ea6f318e8f83`.
The complete 84-byte request SHA-256 is
`7c4f5fdd21de15b396f5b739cbb41f32a3944046902c786ceed9a2b829e56647`.
No raw key, nonce, HMAC, or credential bytes are recorded. This is intentional:
lengths and hashes prove transport identity without exposing live key material.
The 64-byte length is **PROVEN expected for this exact existing Sycamore blob**:
stock decrypts the same key lineage, the authenticated outer container has a
64-byte plaintext, and the TA reports `DeserializeAuthEncryptedBlob ... (64)`.
## D. Recovery code path and cmd 0x18 construction
`fscrypt_initialize_systemwide_keys()` at `system/vold/FsCrypt.cpp:452-495`
retrieves `/data/unencrypted/key`, then `install_storage_key()` at lines 268-279
calls `exportWrappedStorageKey()` when hardware-wrapped mode is selected.
The request contains:
- empty client/application AuthorizationSets;
- `KeyFormat::RAW`;
- the unmodified 64-byte opaque blob;
- no credential, SID, auth token, application ID, or application data.
Beanpod command `0x18` is its legacy Keymaster export-key command encoding. It is
not a distinct 0x18-only userspace serializer invented by TWRP.
## E. Android 16 comparison
Android 16 AOSP `system/vold` retains the same architecture:
- vold passes the opaque storage key as `Domain::BLOB` to Keystore2;
- Keystore2 calls `convertStorageKeyToEphemeral()` directly;
- only `KEY_REQUIRES_UPGRADE` invokes `upgradeKey()` and retries;
- vold intentionally continues storing its original storage blob because its outer
wrapper already handles version binding.
V14 follows this behavior. Beanpod returns `INVALID_KEY_BLOB`, not
`KEY_REQUIRES_UPGRADE`, so the absent upgrade retry is correct.
Material source drift found in the old tree is creation-side, not conversion-side:
- the local `generateWrappedStorageKey()` requests rollback resistance through its
generic generator and adds private `KM_TAG_FBE_ICE`;
- newer AOSP avoids rollback resistance for newly generated storage keys.
Neither changes the already-existing 64-byte stock blob or its conversion request.
The exact stock A16 vold binary contains `wrappedkey_v0`,
`fscrypt_initialize_systemwide_keys`, and the same ephemeral-key path. A
syntactically or semantically obsolete recovery request is therefore **EXCLUDED at
the presently visible boundary**.
## F. Public recovery references
- Agate: credible working TWRP + Microtrust/Beanpod + FBE/metadata reference, but
userdata lacks `wrappedkey_v0`; it does not exercise cmd 0x18.
- Pissarro: useful Beanpod/TEEI startup ordering, but no proven hardware-wrapped
storage-key decryption.
- Air: closest MT6835 architecture reference, but crypto flags are disabled and the
tree is explicitly WIP.
- Dew: modern AIDL KeyMint/Keystore2 architecture, but WIP and no verified
hardware-wrapped-key decryption result.
- TB351FU: valuable modern Lenovo Soter property control; its published recovery
reports encrypted internal storage inaccessible and its stock fstab does not
establish hardware-wrapped-key use.
No verified public “unicorn” was found that simultaneously demonstrates MediaTek,
Microtrust/TEEI, Beanpod, `wrappedkey_v0`, and successful recovery decryption.
## G. Microtrust hidden state
The MT6895 public driver names `boot_decryto_lock`, `boot_soter_flag`,
`keymaster_call_flag`, `soter_error_flag`, and `teei_capi_ready`, and enforces
`teei_daemon` identity for VFS calls. These establish that hidden kernel/secure-world
state exists. Sycamore runtime proves VFS, TA load, RPMB, and ordinary KeyMint calls
advance far enough to work.
No local Sycamore kernel source exposes equivalent variables, and no retained trace
connects any one of them to cmd 0x18. They remain architectural context, not a
root-cause result.
The exact Sycamore TA is a 930,857-byte signed/encrypted Microtrust container, not
an ELF image, so normal `readelf`/`objdump` analysis cannot isolate its dispatcher.
Runtime secure-world diagnostics nevertheless identify the decisive path:
`ParseKeyBlob()` -> `DeserializeAuthEncryptedBlob()` -> `AES_decrypt_ctr()` ->
integrity/hash comparison failure -> `-33`.
This is after the 64-byte blob has reached authenticated blob decoding. It strongly
favors a structurally recognized blob whose authentication/derivation context does
not reproduce stock over a malformed 84-byte request.
## H. Ranked remaining causes
1. **Medium-high:** secure-world storage-key authentication/KDF context differs
between normal boot and recovery. This best matches the TA's integrity comparison
failure while ordinary blobs and the same session work.
2. **Medium:** a storage-specific secure-world initialization transition occurs in
stock but not recovery before conversion. `googlekey.status`/logini are observable
leads, but their timing and causal relationship are unproven.
3. **Medium-low:** the retained 64-byte blob depends on secure-storage lineage/state
not exercised by ordinary metadata keys. RPMB transport works, but that does not
prove every SST namespace/derived key is identical.
4. **Low:** userspace serialization or Android-version drift. A16 and recovery paths
match, and A/B/C/D plus the complete request hash exclude mutation.
5. **Low:** malformed length/version presented by vold. The outer container
authenticates, 64 bytes is the actual stored object, and TA reaches integrity
comparison rather than rejecting request structure.
Root-of-Trust/device-lock state remains a possible input to item 1, not a proven
cause. Current-stock success under the same raw unlocked/orange boot properties
prevents asserting a simple property-level ROT mismatch.
## I. Best next controlled experiment
The smallest justified next artifact is diagnostic-only: snapshot the seven Soter
properties inside `Keymaster::exportKey()` immediately before the first
`convertStorageKeyToEphemeral()` call. This proves exact boundary-time recovery
state without setting properties, changing service order, exposing secrets, or
altering the request.
Do **not** set `logini=start` yet. Stock sets it on `post-fs-data`, and available
evidence does not prove that doing so before cmd 0x18 is stock-equivalent or safe.
The stock-side unresolved requirement is a trustworthy early-boot timing capture.
The existing post-DE stock property dump cannot answer it, and invasive stock
instrumentation could invalidate the control.
## J. Exact proposed change
One diagnostic addition in `system/vold/Keymaster.cpp`, immediately before
`securityLevel->convertStorageKeyToEphemeral(...)`:
- read and log only the seven public `vendor.soter.teei.*` property strings;
- keep the existing 64-byte length/SHA-256 checkpoint;
- do not set any property or alter control flow.
No TA, Beanpod, Keystore2, KeyStorage, init, fstab, DTB, PLATFORM fragment, or key
file would change functionally.

View file

@ -36,57 +36,48 @@ Vendor Boot Header | Version 4
Current state of features:
- [x] Correct screen/recovery size
- [x] Working display
- [x] Working touch
- [x] Screen brightness control
- [x] Power off
- [x] Reboot to system
- [x] Reboot to bootloader
- [x] Reboot to recovery
- [x] Fastboot / fastbootd
- [x] ADB
- [x] Internal storage detected
- [x] External SD card detected
- [x] exFAT external storage
- [x] F2FS userdata support
- [x] EXT4 support
- [x] EROFS support
- [x] Dynamic partition support
- [x] A/B slot handling
- [x] `vendor_boot` v4 support
- [x] Stock PLATFORM vendor ramdisk preserved
- [x] TWRP RECOVERY vendor ramdisk fragment
- [x] Metadata encryption successfully decrypted
- [x] `/data` block device successfully decrypted and mounted
- [x] KeyMint service
- [x] Gatekeeper service
- [x] Keystore2 service
- [ ] Full FBE decryption
- [ ] User PIN/password decryption
- [ ] Decrypted `/data/media`
- [ ] MTP
- [ ] Vibration / haptics
- [ ] USB mass storage export
- [ ] TWRP native `vendor_boot` installation from pristine stock image
- [ ] All commonly modified partitions exposed for image flashing
- Correct screen/recovery size
- Working touch and display
- ADB
- Support EROFS/F2FS/EXT4/exFAT/NTFS
- External SD card support
- Dynamic partition support
- A/B slot handling
- `vendor_boot` v4 support
- Stock PLATFORM vendor ramdisk preserved
- TWRP RECOVERY vendor ramdisk fragment
- Decrypt `/data` with user PIN/password
- Decrypted `/data/media`
- Metadata encryption
- KeyMint service
- Gatekeeper service
- Keystore2 service
- MediaTek/Microtrust TEE
- MTP export
- SELinux enforcing
- Vibrate and set vibration
## Encryption status
Still to validate before final release:
Metadata encryption is working and TWRP successfully creates and mounts the decrypted userdata block device.
- Backup/restore to/from internal/external storage and ADB
- ADB sideload
- Poweroff and all reboot targets
- Flashing zip/images from the TWRP UI
- All important partitions listed in wipe/mount/backup lists
- Input devices via USB-OTG
- Correct date/time configuration
- Battery level reporting
- Brightness adjustment
- Screenshot
- Advanced recovery features
Current testing reaches the Android hardware-wrapped storage key path but fails during system-wide fscrypt key initialization.
# Building
The current failure occurs in the MediaTek Beanpod KeyMint trusted application while processing storage-key conversion:
```bash
export ALLOW_MISSING_DEPENDENCIES=true
source build/envsetup.sh
lunch twrp_sycamore_row_5G-eng
mka vendorbootimage -j$(nproc --all)
```
```text
cmd 0x18 / cmd 24
km_error = -33
AES_decrypt_ctr:
decrypt keyblob compare hash failed
DeserializeAuthEncryptedBlob:
decrypt keyblob failed (-33)
**Copyright (C) 2023 A-Team Digital Solutions**
**Copyright (C) 2026 BOBtheBlinker | A-Team Digital Solutions**

View file

@ -1,85 +0,0 @@
# V15 Soter pre-0x18 state snapshot
Date: 2026-08-27
Result: **PASS — diagnostic-only one-variable build; not flashed.**
Artifact SHA-256:
`d2f542f8d475bc3699487647a041e16235f20847ee43d23e5545b55e6f2b8b1c`
Artifact size: 67,108,864 bytes.
## Hypothesis and change scope
The retained V14 property dump did not prove the exact values of seven public
Microtrust/Soter properties at the instant immediately before the first cmd 0x18.
The only functional source delta from V14 is in
`system/vold/Keymaster.cpp::Keymaster::exportKey()`: immediately after the existing
length/SHA-256 checkpoint B and before
`securityLevel->convertStorageKeyToEphemeral()`, recovery reads and logs:
- `vendor.soter.teei.googlekey.status`
- `vendor.soter.teei.init`
- `vendor.soter.teei.km.init`
- `vendor.soter.teei.km.version`
- `vendor.soter.teei.logini`
- `vendor.soter.teei.persist`
- `vendor.soter.teei.rpmb.flag`
The marker is `SYCA_SOTER_PRE_0X18`. The patch sets no property, changes no
service ordering, changes no request bytes, and exposes no key material.
## Final-image differential
Against the preserved pre-V15 current recovery fragment, complete unpacked-file
SHA-256 manifests differ only at:
- `system/bin/recovery`
- before: `439d1fa5a5080e3ff5f293d18deb1e34aa21b48dc9ba9fd01e7e982fa83840e3`
- V15: `53683ad4e34ffb6ebe4ffb705037f224f62334d2e355b5359230cc60e106077a`
- `ramdisk-files.sha256sum`
- `ramdisk-files.txt`
The final recovery binary contains `SYCA_SOTER_PRE_0X18`, the requested property
names, and the existing `SYCA_DEKEY_A/B` diagnostics.
## Frozen final-image hashes
- PLATFORM:
`06738f638a745075511c571347c5511331dda16b84d1ee88cda160c2dc7ebb14`
- DTB:
`0e93b71aacf707a5fbb7a58eff73995b92d766a31a98d8d70e91f548c9e1d5af`
- Beanpod:
`e066ff6e4f0aaa803e6633aa8fad1f54335e5b969f6422fedc44f77b033851e9`
- `libTEECommon.so`:
`d700e663bd3f68611cadef9bfc929aeb819e199cc9ef3f61a9c8d0afc2bed5b0`
- KeyMint TA:
`af4d1dc971c80b539de9e73ee792285944dd9b132d267be3bb0496bd82bb75ab`
- `teei_daemon`:
`fb79a0c59dab04edbf5ff4cd10af601c4d3dba5378b5ba3d981553f818fbb014`
- `libteei_daemon_vfs.so`:
`6012c5ccb298a411c8f7c0572b26ca237c3209ad348cd6e509a2cf71f4fccc13`
- Keystore2:
`31a9f7d9de497e06c465343ddb4d3aa3e8064c3051059c206b53d061d59f6256`
- `libkeystore2_crypto.so`:
`6e46dbfbf135c41131d64b91ce93fedf7c62077059fdbc24a5ca62b94e195132`
## vendor_boot audit
- header v4; page size 4096
- cmdline: `bootopt=64S3,32N2,64N2`
- fragment 0: exact stock PLATFORM, 27,422,144 bytes
- fragment 1: RECOVERY named `recovery`, 31,678,798 bytes
- total vendor ramdisk: 59,100,942 bytes
- stock DTB exact
- bootconfig empty
- PLATFORM first, RECOVERY second
- all board_id words zero
- recovery fragment `.ko` count: zero
- only five expected module metadata files retained
- algorithm-NONE AVB footer and vendor_boot hash verify
- post-AVB image re-unpacks successfully
- final size exactly 67,108,864 bytes
Static audit: **PASS. Stop before flashing.**

View file

@ -1,115 +0,0 @@
# V16 boot-decrypt-unlock static audit
Date: 2026-08-27
Result: **PASS — one-variable boot-decrypt lifecycle experiment; not flashed.**
Artifact SHA-256:
`1fe86baa602403638e2f0c0b2b7a29bc4cd768ec2bed9256b12aa92c8ca81e09`
Artifact size: 67,108,864 bytes.
## Hypothesis
The exact stock `teei_daemon` snapshots `ro.crypto.state` and
`ro.crypto.type` in its boot-decrypt thread. With `ro.crypto.type=file`, it
logs `fbe mode late` and issues the `/dev/teei_config` boot-decrypt-unlock
ioctl. V15 did not expose that initial FBE state and never set
`vendor.soter.teei.logini=start`; consequently it showed neither the daemon
unlock message nor a boot-decrypt-lock result before cmd 0x18.
V16 tests whether reproducing those stock lifecycle inputs before the first
storage-key conversion changes cmd 0x18 from `KM_ERROR_INVALID_KEY_BLOB`.
## Exact source changes
- `device/motorola/sycamore_row_5G/device.mk:16-22`
- adds `ro.crypto.state=encrypted` and `ro.crypto.type=file` through
`PRODUCT_SYSTEM_DEFAULT_PROPERTIES`, placing both in the initial recovery
`prop.default` before `teei_daemon` starts.
- `device/motorola/sycamore_row_5G/recovery/root/init.recovery.crypto.rc:69-73`
- sets `vendor.soter.teei.logini=start` once the existing Soter init,
persist-VFS, and RPMB health properties simultaneously report their stock
terminal values.
- `system/vold/Keymaster.cpp:187-213`
- adds the secret-free `SYCA_V16_PRE_0X18` state snapshot immediately before
`convertStorageKeyToEphemeral()`; V15 tracing remains present.
No other functional source was changed for V16. Cmd 0x18 serialization,
wrapped-key bytes, Beanpod, TA, private libraries, SharedSecret, patch levels,
DTB, PLATFORM, and kernel modules are unchanged.
## Implemented ordering
1. Initial property load exposes the real recovery FBE mode:
`ro.crypto.state=encrypted`, `ro.crypto.type=file`.
2. `on init` prepares the existing TEE device nodes and starts the exact stock
`teei_daemon`.
3. `init.svc.teei_daemon=running` starts Beanpod and Gatekeeper as in V15.
4. Once `vendor.soter.teei.init=INIT_OK`,
`vendor.soter.teei.persist=OPEN`, and
`vendor.soter.teei.rpmb.flag=ok` are all true, init sets
`vendor.soter.teei.logini=start`.
5. Existing vold flow reaches the first storage-key conversion, where V16 logs
the complete pre-0x18 public-state snapshot.
No sleep or repeated trigger was added. `vold.post_fs_data_done` and
`vendor.soter.teei.crypto.state` were not set: the exact daemon does not
reference the former, and its `ro.crypto.type=file` startup branch does not
require the latter.
## Final recovery-fragment differential against archived V15
Complete relative-path SHA-256 manifests differ only at:
- `init.recovery.crypto.rc` (intentional logini trigger)
- `prop.default` (intentional two FBE defaults)
- `system/bin/recovery` (intentional V16 marker)
- `ramdisk-files.sha256sum` and `ramdisk-files.txt` (generated inventory)
There are no added or removed payload paths.
## Frozen binary/content verification
- stock PLATFORM:
`06738f638a745075511c571347c5511331dda16b84d1ee88cda160c2dc7ebb14`
- stock DTB:
`0e93b71aacf707a5fbb7a58eff73995b92d766a31a98d8d70e91f548c9e1d5af`
- exact stock `teei_daemon`:
`fb79a0c59dab04edbf5ff4cd10af601c4d3dba5378b5ba3d981553f818fbb014`
- Beanpod:
`e066ff6e4f0aaa803e6633aa8fad1f54335e5b969f6422fedc44f77b033851e9`
- KeyMint TA:
`af4d1dc971c80b539de9e73ee792285944dd9b132d267be3bb0496bd82bb75ab`
- Keystore2:
`31a9f7d9de497e06c465343ddb4d3aa3e8064c3051059c206b53d061d59f6256`
- `libkeystore2_crypto.so`:
`6e46dbfbf135c41131d64b91ce93fedf7c62077059fdbc24a5ca62b94e195132`
All nine stock KeyMint private-library hashes and the V15 keytrace library hash
match the frozen V15 family. The recovery fragment contains zero `.ko` files
and only the same five module metadata files.
## Final vendor_boot audit
- header version 4; page size 4096
- command line `bootopt=64S3,32N2,64N2`
- bootconfig empty
- fragment 0: unnamed PLATFORM, type 1, 27,422,144 bytes, exact stock hash
- fragment 1: `recovery`, RECOVERY type 2, 31,679,640 bytes
- total vendor ramdisk size: 59,101,784 bytes
- all board IDs zero; PLATFORM first and RECOVERY second
- exact stock DTB, 192,119 bytes
- algorithm-NONE AVB footer verifies
- final image re-unpacks successfully
- final partition-padded size exactly 67,108,864 bytes
## Expected hardware-test markers
- `SYCA_V16_PRE_0X18`
- `daemon unlock keymaster signal to tz-driver`
- `keymaster unlock boot_decrypt_lock success` or `failed!`
- existing `SYCA_SOTER_PRE_0X18`, `SYCA_DEKEY_A/B/C/D`, `SYCA_TA_TRACE`,
cmd 0x18 hashes, and cmd result
Static audit: **PASS. Stop before flashing.**

View file

@ -1,148 +0,0 @@
# V17 stock THH identity static audit
Date: 2026-08-27
Result: **PASS — controlled stock-THH/product-identity experiment; not flashed.**
Artifact SHA-256:
`f23330a09d0b0ea4a7c902342dd62f36dcf5179cd72ed40d316819deb7c9ec50`
Artifact size: 67,108,864 bytes.
## Hypothesis
V16 initialized Microtrust with an incomplete `/vendor/thh/ta` namespace and
the recovery codename as `ro.product.device`. The exact signed stock model
configuration recognizes `platform=mt8755`, `model=XT2575-4`, while V16 secure
world logged `model:sycamore_row_5G`, model verification failures, and TA load
error 18. V17 tests whether presenting the complete exact-stock THH payload
and production Microtrust-facing identity before the first `teei_daemon`
launch restores cold TA/model validation and changes cmd 0x18 behavior.
All V16 FBE/logini behavior and crypto diagnostics are retained unchanged.
## Exact stock source
The files were copied from the preserved exact-firmware vendor extraction:
`/home/nicholas/Downloads/sycamore-twrp-info/first-hardware-boot/fbe-a16-v3/ta-forensics/stock-vendor-thh/ta`
This extraction belongs to factory baseline
`XT2575-4_ROW_OPEN_USER_M1317.3_W_ZUI_17.5.10.017_ST`. Both the staged source
tree and the final unpacked recovery fragment were compared byte-for-byte with
all 15 source files. Both comparisons pass.
## Stock THH manifest
| File | Bytes | SHA-256 |
|---|---:|---|
| `0102030405060708090a0b0c0d0e0f10.ta` | 20,777 | `19a5e15a2f17a6c1418c5edc6fc63a3ddd279966540930b2e97f227ce0d897ae` |
| `020f0000000000000000000000000000.ta` | 22,649 | `aba910dfbdccbf177eb107853669c6eff689b4f36e9afb2f8e04e30d8e97108b` |
| `06090000000000000000000000000000.ta` | 6,953 | `2d5cd2e906a1dab1636c59bbe037f8502aec7c25edc9172cba8da158fc6d8c36` |
| `08030000000000000000000000000000.ta` | 24,393 | `ba29286b7d24edc04275b195db120032e116828ff73241241d6d8c40855b4f03` |
| `08110000000000000000000000000000.ta` | 72,073 | `0fb3e0b70a972d4a58088978aec706399009f32f5133061efe6b7033f1ae9f17` |
| `40188311faf343488db888ad39496f9a.ta` | 9,177 | `5cb79b594721523700fe4708ea764c80144979dc698db27a18a2383159028a1c` |
| `5020170115e016302017012521300000.ta` | 10,393 | `0865a891c965a201d4e64f3b9e2f4a3f0fe899f80ff24ab88cf75b1622dc5d40` |
| `5f7a5b3b29b041bca249524a031a00e3.ta` | 32,737 | `2911bd3726ae4110877409d501329f36f5958a6686262b93814d8bb89fdb629c` |
| `8888c04fc30c4dd0a319ea29643d4d4c.ta` | 32,129 | `5b812b524f5eea79c1bc944b06d00cddc8738274166d888bf255080ab0feab09` |
| `abcd270ea5c44c58bcd3384a2fa2539e.ta` | 39,833 | `c4d5811efd695ba0550960f9c5649e6476289cbb00cb8c9d7f5cb11b7a2e2f18` |
| `c09c9c5daa504b78b0e46eda61556c3a.ta` | 930,857 | `af4d1dc971c80b539de9e73ee792285944dd9b132d267be3bb0496bd82bb75ab` |
| `c1882f2d885e4e13a8c8e2622461b2fa.ta` | 55,537 | `0a5f34be1d73535c563aaece231b2e93193ae5f2c69b8050e71b14f48956081d` |
| `d91f322ad5a441d5955110eda3272fc0.ta` | 22,177 | `4432d3f85370e41f57bf5fb6b5945326c441a394d0cbe298be5c29b2b056b954` |
| `e97c270ea5c44c58bcd3384a2fa2539e.ta` | 447,769 | `c76352a8115aba85e963d2e39466530daa8ac5db411ccea403eaf84d2c308e96` |
| `isee_model.json` | 2,794 | `67c019209942f9a68408d998e5d478b0dba5e3f5dbbc6582b146af8aaa05e3c6` |
## Source/change scope
- `device/motorola/sycamore_row_5G/device.mk`
- packages all 15 stock THH files and the early diagnostic script;
- adds only global `ro.product.device=XT2575-4` to the existing V16 initial
system-default property set.
- `build/make/core/Makefile`
- recovery-only, target-gated, fail-closed replacement of the two generated
vendor device/name values in final `prop.default`; vendor model was already
stock-correct.
- `device/motorola/sycamore_row_5G/recovery/root/init.recovery.crypto.rc`
- synchronously executes the readiness diagnostic immediately before the
existing first `start teei_daemon`.
- `device/motorola/sycamore_row_5G/recovery/root/system/bin/syca_v17_thh_ready.sh`
- logs only public properties, four existence results, and total file count.
- fourteen stock THH files were added under
`device/motorola/sycamore_row_5G/recovery/root/vendor/thh/ta`; the fifteenth,
the KeyMint TA, was already present and byte-identical.
## Final initial properties
- `ro.product.device=XT2575-4`
- `ro.product.vendor.device=XT2575-4`
- `ro.product.vendor.name=XT2575-4`
- `ro.product.vendor.model=XT2575-4`
- `ro.build.product=sycamore_row_5G` (preserved)
- `ro.crypto.type=file` (V16 preserved)
- `ro.crypto.state=encrypted` (V16 preserved)
`PRODUCT_DEVICE=sycamore_row_5G`, the TWRP product name, target assertions, and
`ro.twrp.target.devices` behavior were not changed.
## Cold-boot ordering
1. Recovery ramdisk, all 15 THH files, production identity, and V16 FBE
properties exist before init actions.
2. Existing TEE/RPMB nodes and read-only persist mount are prepared.
3. Init synchronously runs `syca_v17_thh_ready.sh` and emits
`SYCA_V17_THH_READY`; expected `thh_file_count=15`.
4. Init launches the unchanged exact-stock `teei_daemon` for the first time.
5. The daemon performs cold secure-world TA/model validation.
6. Existing `init.svc.teei_daemon=running` action starts Beanpod/Gatekeeper.
7. Existing V16 healthy-state conjunction sets `logini=start`.
8. Existing vold/Keystore2 path reaches the first cmd 0x18.
No sleep, restart, bind mount, or post-initialization substitution was added.
## V16-to-V17 final-image differential
Complete unpacked relative-path SHA-256 manifests show only:
- modified: `init.recovery.crypto.rc`, `prop.default`, and generated ramdisk
inventory files;
- added: readiness script and the 14 THH files absent from V16;
- unchanged: `system/bin/recovery`, existing KeyMint TA, all secure binaries,
private libraries, Keytrace, and every other ramdisk payload.
## Frozen architecture/binary verification
- stock PLATFORM:
`06738f638a745075511c571347c5511331dda16b84d1ee88cda160c2dc7ebb14`
- stock DTB:
`0e93b71aacf707a5fbb7a58eff73995b92d766a31a98d8d70e91f548c9e1d5af`
- exact stock `teei_daemon`:
`fb79a0c59dab04edbf5ff4cd10af601c4d3dba5378b5ba3d981553f818fbb014`
- Beanpod:
`e066ff6e4f0aaa803e6633aa8fad1f54335e5b969f6422fedc44f77b033851e9`
- KeyMint TA:
`af4d1dc971c80b539de9e73ee792285944dd9b132d267be3bb0496bd82bb75ab`
- Keystore2:
`31a9f7d9de497e06c465343ddb4d3aa3e8064c3051059c206b53d061d59f6256`
- `libkeystore2_crypto.so`:
`6e46dbfbf135c41131d64b91ce93fedf7c62077059fdbc24a5ca62b94e195132`
- Keytrace:
`0642e36b25589ebdf16423cb3a81c8ba5dab3ffc0dcb32a58386efa8b2d7293d`
The final recovery has zero `.ko` files and the same five module metadata
files. V16 `SYCA_V16_PRE_0X18`, `SYCA_SOTER_PRE_0X18`,
`SYCA_DEKEY_A/B/C/D`, and `SYCA_TA_TRACE` markers remain present.
## Final vendor_boot audit
- header v4; page size 4096
- cmdline `bootopt=64S3,32N2,64N2`; bootconfig empty
- fragment 0: unnamed PLATFORM/type 1, 27,422,144 bytes, exact stock hash
- fragment 1: `recovery`/type 2, 32,078,301 bytes
- total vendor ramdisk: 59,500,445 bytes
- stock DTB exact; all board IDs zero
- PLATFORM first, RECOVERY second
- algorithm-NONE AVB footer and vendor_boot hash verify
- final image re-unpacks successfully
- final partition-padded size exactly 67,108,864 bytes
Static audit: **PASS. Stop before flashing.**

View file

@ -1,177 +0,0 @@
# V18.1 cold stock tee identity static audit
Date: 2026-08-27
Result: **PASS — surgical init/DAC/tee-permissive experiment; not flashed.**
Immutable baseline:
`fbe-a16-v18-stock-tee-identity`
Baseline SHA-256:
`7c6817d5b29055ac337b26a87e3c29281e8ff2df2209521546c75bb8064642ac`
V18.1 artifact SHA-256:
`5f57030d1cd10d6ef0c3987c8a1b3119f7e51ef23ddc21f647970cf4efb6a26d`
Artifact size: 67,108,864 bytes.
## Task-scoped source changes
- `device/motorola/sycamore_row_5G/recovery/root/init.recovery.crypto.rc`
- moves exact stock Microtrust DAC and first daemon start to `on fs`;
- restores the daemon executable context before starting it;
- gates Beanpod/Gatekeeper on `vendor.soter.teei.init=INIT_OK`;
- uses stock `post-fs-data` logini lifecycle.
- `device/motorola/sycamore_row_5G/sepolicy/vendor/teei_device.te`
- adds only `permissive tee;` for this diagnostic build.
No other source file was modified for V18.1.
Task-scoped diff stat:
```text
recovery/root/init.recovery.crypto.rc | 48 +++++++++++++++++++++++++++--------
sepolicy/vendor/teei_device.te | 4 +++
2 files changed, 41 insertions(+), 11 deletions(-)
```
## A. teei_daemon service
The final unpacked recovery contains the complete V18 `-r`/`-t` UUID sequence
unchanged and exactly:
```rc
user system
group system
disabled
capabilities SYS_RAWIO
seclabel u:r:tee:s0
```
There is one primary `group system` declaration and no supplementary group.
`SYS_RAWIO` is the only capability. The final daemon binary is byte-identical
to V18:
`fb79a0c59dab04edbf5ff4cd10af601c4d3dba5378b5ba3d981553f818fbb014`
## B. executable runtime context
Final `vendor_file_contexts` still contains:
```text
/vendor/bin/teei_daemon u:object_r:tee_exec:s0
```
The final init action executes:
```rc
on fs
restorecon /vendor/bin/teei_daemon
...
start teei_daemon
```
`restorecon` precedes every Microtrust DAC operation and the first daemon start.
## C. exact stock DAC sequence
The final `on fs` action contains, in the requested order:
```rc
restorecon /vendor/bin/teei_daemon
chmod 0660 /dev/teei_client
chown system system /dev/teei_client
chmod 0660 /dev/teei_config
chown system system /dev/teei_config
chmod 0666 /dev/isee_tee0
chown system drmrpc /dev/isee_tee0
chmod 0660 /dev/tz_vfs
chown system system /dev/tz_vfs
chmod 0660 /dev/teei_fp
chown system /dev/teei_fp
chown system drmrpc /dev/ut_keymaster
chmod 0660 /dev/ut_keymaster
chmod 0660 /dev/0:0:0:49476
chown system system /dev/0:0:0:49476
chmod 0660 /dev/rpmb0
chown system system /dev/rpmb0
chmod 0660 /dev/emmcrpmb0
chown system system /dev/emmcrpmb0
chown system system /dev/utr_tui
chmod 0660 /dev/utr_tui
start teei_daemon
```
No node is manufactured. `/dev/teeperf` remains separately handled in
`on init` at mode 0660.
The persist setup remains byte-for-byte equivalent to V18:
```rc
mkdir /mnt/vendor/persist 0771 system system
mount ext4 /dev/block/sdc14 /mnt/vendor/persist ro noatime nosuid nodev wait noload
```
## D. sequencing
- no `init.svc.teei_daemon=running` action starts security services;
- `vendor.soter.teei.init=INIT_OK` starts Beanpod and Gatekeeper;
- `on post-fs-data` sets `vendor.soter.teei.logini=start`;
- no init property action sets `vendor.soter.teei.persist` or
`vendor.soter.teei.rpmb.flag`;
- no sleep was introduced.
## E. SELinux
The final compiled-policy permissive-domain set differs from V18 by exactly one
entry: `tee`. Existing recovery-build permissive domains are unchanged.
`tee` is intentionally permissive for V18.1. Global kernel/recovery enforcing
configuration was not changed, no other domain was added, existing node types
and allow rules were preserved, and policy/neverallow compilation passed.
Final policy SHA-256:
`5d9a65cc5a28d3f7ef8ca79f1a40ba4d2548b91a6be0f115085df54b3ae7d055`
## F. frozen crypto comparison against V18
Complete unpacked-file manifests differ only at:
- `init.recovery.crypto.rc`;
- `sepolicy`;
- generated `ramdisk-files.sha256sum` and `ramdisk-files.txt`.
Everything else is byte-identical, including:
| Payload | SHA-256 |
|---|---|
| `teei_daemon` | `fb79a0c59dab04edbf5ff4cd10af601c4d3dba5378b5ba3d981553f818fbb014` |
| Beanpod | `e066ff6e4f0aaa803e6633aa8fad1f54335e5b969f6422fedc44f77b033851e9` |
| Gatekeeper | `7460ce26460376b24c29d2f46820ecc5646505fe24090f57aa7d05141e77d3b9` |
| Keymaster TA | `af4d1dc971c80b539de9e73ee792285944dd9b132d267be3bb0496bd82bb75ab` |
| diagnostic preload | `0642e36b25589ebdf16423cb3a81c8ba5dab3ffc0dcb32a58386efa8b2d7293d` |
| Keystore2 | `31a9f7d9de497e06c465343ddb4d3aa3e8064c3051059c206b53d061d59f6256` |
| `libkeystore2_crypto.so` | `6e46dbfbf135c41131d64b91ce93fedf7c62077059fdbc24a5ca62b94e195132` |
| cmd0x18-bearing recovery binary | `986d25bac8ceb0df6edee2731c5b92c30090f30c84977229022e33c97e9a3a89` |
All eight private KeyMint libraries compare byte-for-byte with V18. The full
15-file THH directory, including `isee_model.json`, compares byte-for-byte with
V18. Product/model/platform and FBE property subsets are identical to V18.
## G. stock hybrid / final image
- header v4; page size 4096
- cmdline `bootopt=64S3,32N2,64N2`; bootconfig empty
- fragment 0: unnamed PLATFORM/type 1, 27,422,144 bytes
- PLATFORM SHA-256:
`06738f638a745075511c571347c5511331dda16b84d1ee88cda160c2dc7ebb14`
- fragment 1: `recovery`/type 2, 32,078,214 bytes
- total vendor ramdisk: 59,500,358 bytes
- DTB SHA-256:
`0e93b71aacf707a5fbb7a58eff73995b92d766a31a98d8d70e91f548c9e1d5af`
- recovery `.ko` count: zero; same five module metadata files
- algorithm-NONE AVB footer and vendor_boot hash verify
- image re-unpacks successfully
- final size exactly 67,108,864 bytes
Static audit: **PASS. Stop before flashing.**

View file

@ -1,158 +0,0 @@
# V18 stock tee identity static audit
Date: 2026-08-27
Result: **PASS — controlled teei_daemon execution-identity experiment; not flashed.**
Artifact SHA-256:
`7c6817d5b29055ac337b26a87e3c29281e8ff2df2209521546c75bb8064642ac`
Artifact size: 67,108,864 bytes.
## Hypothesis
V17 fixed cold THH/model validation but still ran the unchanged stock
`teei_daemon` as root in `u:r:recovery:s0`. V18 tests whether the missing
boot-decrypt-unlock transition and cmd 0x18 key-blob failure depend on the
daemon's production process identity: UID/GID 1000, no supplementary groups,
only `CAP_SYS_RAWIO`, and enforcing `u:r:tee:s0`.
No KeyMint, wrapped-key, FBE, secure-storage, vendor_boot, kernel, or binary
behavior was otherwise changed.
## Service declaration differential
V17:
```rc
user root
group root system
capabilities SYS_RAWIO
seclabel u:r:recovery:s0
```
V18:
```rc
user system
group system
capabilities SYS_RAWIO
seclabel u:r:tee:s0
```
The complete 21-entry `-r`/`-t` UUID argument sequence is byte-for-byte
unchanged. A single `group system` entry establishes the primary GID only; no
supplementary group is declared. `SYS_RAWIO` is the sole capability token.
## SELinux audit and implementation
The pre-V18 platform policy already defined:
- `tee` with the `domain` attribute;
- `tee_exec` as an executable vendor-file type;
- `init_daemon_domain(tee)`, producing
`type_transition init tee_exec:process tee`.
V17 lacked a `tee_exec` path label for `/vendor/bin/teei_daemon`, so merely
changing `seclabel` could not prove a valid launch environment.
V18 adds the exact executable context and the narrowly scoped stock Microtrust
device contexts under `device/motorola/sycamore_row_5G/sepolicy/vendor`. The
final combined policy:
- compiles successfully;
- passes neverallow checks;
- contains `tee` in the `domain` attribute;
- contains the init→`tee` transition;
- permits `tee` to use only the declared Microtrust node types;
- permits `tee` `sys_rawio` capability use;
- does **not** mark `tee` permissive.
Final policy SHA-256:
`0b23e52b72848a03649e78fe005b88827d35a37bcab2ce8d394fc6d395fd94d3`
## Exact node contexts
These are copied from the exact stock vendor_boot `vendor_file_contexts`:
| Path | Final type |
|---|---|
| `/dev/isee_tee0` | `teei_client_device` |
| `/dev/teei_client` | `teei_client_device` |
| `/dev/teei_config` | `teei_config_device` |
| `/dev/tz_vfs` | `teei_vfs_device` |
| `/dev/teei_fp` | `teei_fp_device` |
| `/dev/ut_keymaster` | `ut_keymaster_device` |
| `/dev/0:0:0:49476` | `teei_rpmb_device` |
| `/dev/rpmb0` | `teei_rpmb_device` |
| `/dev/utr_tui` | `utr_tui_device` |
| `/vendor/bin/teei_daemon` | `tee_exec` |
No non-Microtrust device path was relabeled. These labels are required for the
enforcing `tee` domain to use the same interfaces that V17 accessed from the
permissive recovery domain.
## Removed failed V17 diagnostic
The packaged `syca_v17_thh_ready.sh` and its synchronous init `exec` were
removed. This eliminates the known invalid-domain exec failure and does not add
a replacement delay or process. V16/V17 crypto diagnostics remain intact.
## Frozen V17/V16 state
- all 15 stock THH files: byte-identical to the exact stock extraction;
- `isee_model.json`: unchanged;
- `ro.product.device=XT2575-4`;
- all three vendor product identity fields: `XT2575-4`;
- `ro.build.product=sycamore_row_5G`;
- `ro.crypto.type=file` and `ro.crypto.state=encrypted`;
- healthy-state `vendor.soter.teei.logini=start` ordering;
- `SYCA_V16_PRE_0X18`, `SYCA_SOTER_PRE_0X18`,
`SYCA_DEKEY_A/B/C/D`, and `SYCA_TA_TRACE`.
## Frozen hashes
- stock PLATFORM:
`06738f638a745075511c571347c5511331dda16b84d1ee88cda160c2dc7ebb14`
- stock DTB:
`0e93b71aacf707a5fbb7a58eff73995b92d766a31a98d8d70e91f548c9e1d5af`
- exact stock `teei_daemon`:
`fb79a0c59dab04edbf5ff4cd10af601c4d3dba5378b5ba3d981553f818fbb014`
- Beanpod:
`e066ff6e4f0aaa803e6633aa8fad1f54335e5b969f6422fedc44f77b033851e9`
- KeyMint TA:
`af4d1dc971c80b539de9e73ee792285944dd9b132d267be3bb0496bd82bb75ab`
- Keystore2:
`31a9f7d9de497e06c465343ddb4d3aa3e8064c3051059c206b53d061d59f6256`
- Keytrace:
`0642e36b25589ebdf16423cb3a81c8ba5dab3ffc0dcb32a58386efa8b2d7293d`
## V17-to-V18 final-image differential
Complete unpacked relative-path SHA-256 manifests differ only at:
- `init.recovery.crypto.rc` — intended service identity and failed-diagnostic
removal;
- `sepolicy`, `vendor_file_contexts`, and `file_contexts.bin` — intended narrow
tee-domain implementation;
- removal of `system/bin/syca_v17_thh_ready.sh`;
- generated ramdisk inventory files.
No secure binary, THH payload, property file, kernel module, or crypto
diagnostic binary changed.
## Final vendor_boot audit
- header v4; page size 4096
- cmdline `bootopt=64S3,32N2,64N2`; bootconfig empty
- fragment 0: unnamed PLATFORM/type 1, 27,422,144 bytes, exact stock hash
- fragment 1: `recovery`/type 2, 32,078,200 bytes
- total vendor ramdisk: 59,500,344 bytes
- exact stock DTB; all board IDs zero
- PLATFORM first, RECOVERY second
- recovery `.ko` count: zero; same five module metadata files
- algorithm-NONE AVB footer and vendor_boot hash verify
- final image re-unpacks successfully
- final partition-padded size exactly 67,108,864 bytes
Static audit: **PASS. Stop before flashing.**

View file

@ -1,114 +0,0 @@
# V19 stock Beanpod UID static audit
Date: 2026-08-27
Result: **PASS — one-line Beanpod Unix-identity experiment; not flashed.**
Immutable baseline:
`fbe-a16-v18.1-cold-stock-tee-identity`
Baseline SHA-256:
`5f57030d1cd10d6ef0c3987c8a1b3119f7e51ef23ddc21f647970cf4efb6a26d`
V19 artifact SHA-256:
`549e214d0e58888e6d9b449fd9dafb3fa2912d76295bef18a1409e1ca60b761a`
Artifact size: 67,108,864 bytes.
## Hypothesis and exact change
V19 tests whether Microtrust KeyMint storage-key cmd 0x18 depends on Beanpod's
stock Linux UID 9999. It intentionally retains the V18.1 recovery SELinux
domain so the Unix identity is the only runtime variable.
The sole task source change is:
`device/motorola/sycamore_row_5G/recovery/root/init.recovery.crypto.rc`
```diff
- user root
+ user nobody
```
Task-scoped V18.1-to-V19 diff stat:
```text
init.recovery.crypto.rc | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
```
## 1–3. Final Beanpod service
The final unpacked ramdisk contains:
```rc
service vendor.keymint-beanpod /vendor/bin/hw/android.hardware.security.keymint@2.0-service.beanpod
class early_hal
user nobody
group root
disabled
seclabel u:r:recovery:s0
setenv LD_LIBRARY_PATH /vendor/lib64:/vendor/lib64/hw:/system/lib64:/system/lib64/hw
setenv LD_PRELOAD /vendor/lib64/libsycamore_keytrace.so
```
There is no capability declaration and no supplementary group. Expected Linux
credentials are UID 9999, primary GID 0, empty supplementary groups, and zero
inheritable/permitted/effective/ambient capabilities.
## 4–7. Frozen secure payloads
Every listed final file compares byte-for-byte with the unpacked archived
V18.1 baseline:
| Payload | SHA-256 |
|---|---|
| Beanpod | `e066ff6e4f0aaa803e6633aa8fad1f54335e5b969f6422fedc44f77b033851e9` |
| `teei_daemon` | `fb79a0c59dab04edbf5ff4cd10af601c4d3dba5378b5ba3d981553f818fbb014` |
| Gatekeeper | `7460ce26460376b24c29d2f46820ecc5646505fe24090f57aa7d05141e77d3b9` |
| Keymaster TA | `af4d1dc971c80b539de9e73ee792285944dd9b132d267be3bb0496bd82bb75ab` |
| diagnostic preload | `0642e36b25589ebdf16423cb3a81c8ba5dab3ffc0dcb32a58386efa8b2d7293d` |
| Keystore2 | `31a9f7d9de497e06c465343ddb4d3aa3e8064c3051059c206b53d061d59f6256` |
| `libkeystore2_crypto.so` | `6e46dbfbf135c41131d64b91ce93fedf7c62077059fdbc24a5ca62b94e195132` |
| cmd0x18-bearing recovery binary | `986d25bac8ceb0df6edee2731c5b92c30090f30c84977229022e33c97e9a3a89` |
All eight private KeyMint libraries are byte-identical. The complete 15-file
THH directory, including `isee_model.json`, is byte-identical.
## 8–11. Frozen ordering/configuration/diagnostics
Replacing the V18.1 `user root` line with `user nobody` produces a file
byte-identical to V19 `init.recovery.crypto.rc`; therefore every other byte of
the service definitions, UUID arguments, cold `on fs` DAC sequence, INIT_OK
gate, post-fs-data logini action, persist mount, and RPMB handling is unchanged.
Final `prop.default`, compiled SELinux policy, and `vendor_file_contexts` are
byte-identical to V18.1. This preserves:
- V18.1 tee-domain policy and permissive state;
- all product/model/platform and FBE properties;
- all Microtrust file contexts;
- `SYCA_V16_PRE_0X18`, `SYCA_SOTER_PRE_0X18`,
`SYCA_DEKEY_A/B/C/D`, and `SYCA_TA_TRACE` instrumentation.
## 12–16. Final vendor_boot audit
- header v4; page size 4096
- cmdline `bootopt=64S3,32N2,64N2`; bootconfig empty
- fragment 0: unnamed PLATFORM/type 1, 27,422,144 bytes
- PLATFORM SHA-256:
`06738f638a745075511c571347c5511331dda16b84d1ee88cda160c2dc7ebb14`
- fragment 1: `recovery`/type 2, 32,078,223 bytes
- total vendor ramdisk: 59,500,367 bytes
- DTB SHA-256:
`0e93b71aacf707a5fbb7a58eff73995b92d766a31a98d8d70e91f548c9e1d5af`
- no kernel payload was changed; recovery `.ko` count is zero and the five
module metadata filenames match V18.1
- algorithm-NONE AVB footer and vendor_boot hash verify
- final image re-unpacks successfully
- final partition-padded size exactly 67,108,864 bytes
Complete final ramdisk manifests differ from V18.1 only at
`init.recovery.crypto.rc` and the two generated ramdisk inventory files.
Static audit: **PASS. Stop before flashing.**

View file

@ -18,8 +18,7 @@ PRODUCT_SOONG_NAMESPACES += $(DEVICE_PATH)
# passthrough stub while keeping the generic fastbootd logical-partition path.
PRODUCT_PACKAGES += \
android.hardware.fastboot@1.1-impl-mock \
sycamore_boot_hal_stock_libbase \
sycamore_fscryptd
sycamore_boot_hal_stock_libbase
# Let TWRP publish ro.crypto.state/type when it detects /data FBE.
# Stock teei_daemon begins polling before ro.crypto.type=file appears; Beanpod
@ -33,7 +32,6 @@ PRODUCT_COPY_FILES += \
$(DEVICE_PATH)/recovery/root/init.recovery.mt6835.rc:$(TARGET_COPY_OUT_RECOVERY)/root/init.recovery.mt6835.rc \
$(DEVICE_PATH)/recovery/root/init.recovery.mt8755.rc:$(TARGET_COPY_OUT_RECOVERY)/root/init.recovery.mt8755.rc \
$(DEVICE_PATH)/recovery/root/init.recovery.crypto.rc:$(TARGET_COPY_OUT_RECOVERY)/root/init.recovery.crypto.rc \
$(DEVICE_PATH)/recovery/root/system/etc/init/zz_sycamore_fscryptd.rc:$(TARGET_COPY_OUT_RECOVERY)/root/system/etc/init/zz_sycamore_fscryptd.rc \
$(DEVICE_PATH)/recovery/root/system/etc/vintf/manifest.xml:$(TARGET_COPY_OUT_RECOVERY)/root/system/etc/vintf/manifest.xml \
$(DEVICE_PATH)/recovery/root/system/etc/vintf/manifest/android.hardware.health-service.example.xml:$(TARGET_COPY_OUT_RECOVERY)/root/system/etc/vintf/manifest/android.hardware.health-service.example.xml \
$(DEVICE_PATH)/recovery/root/vendor/manifest.xml:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/manifest.xml \
@ -79,7 +77,6 @@ PRODUCT_PACKAGES += \
sycamore_tee_imsg_log \
sycamore_tee_vfs \
sycamore_teei_daemon \
libsycamore_keytrace
PRODUCT_VENDOR_PROPERTIES += \
ro.vendor.mtk_ufs_support=1 \
@ -94,3 +91,7 @@ PRODUCT_COPY_FILES += \
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/recovery/root/system/etc/init/zz_sycamore_hwservicemanager.rc:$(TARGET_COPY_OUT_RECOVERY)/root/system/etc/init/zz_sycamore_hwservicemanager.rc
# Device-side Keystore2 database staging for Android 16 FBE.
PRODUCT_COPY_FILES += \
$(DEVICE_PATH)/recovery/root/system/bin/sycamore_keystore2_stage.sh:$(TARGET_COPY_OUT_RECOVERY)/root/system/bin/sycamore_keystore2_stage.sh

View file

@ -1,82 +0,0 @@
DEVICE_PATH := device/motorola/sycamore_row_5G
PRODUCT_USE_DYNAMIC_PARTITIONS := true
ENABLE_VIRTUAL_AB := true
# This is the exact list exposed by ro.product.ab_ota_partitions on the live build.
AB_OTA_PARTITIONS := \
init_boot \
product \
system \
system_ext \
vendor
PRODUCT_SOONG_NAMESPACES += $(DEVICE_PATH)
# V16 boot-decrypt-unlock: expose the real FBE mode before teei_daemon starts.
# The stock daemon snapshots these read-only properties in its startup thread;
# setting them later from TWRP's partition scan leaves that thread waiting on
# the legacy vold.decrypt fallback instead of issuing the FBE unlock ioctl.
PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
ro.product.device=XT2575-4 \
ro.crypto.state=encrypted \
ro.crypto.type=file
PRODUCT_COPY_FILES += \
$(DEVICE_PATH)/recovery.fstab:$(TARGET_COPY_OUT_RECOVERY)/root/system/etc/recovery.fstab \
$(DEVICE_PATH)/recovery/root/init.recovery.mt6835.rc:$(TARGET_COPY_OUT_RECOVERY)/root/init.recovery.mt6835.rc \
$(DEVICE_PATH)/recovery/root/init.recovery.mt8755.rc:$(TARGET_COPY_OUT_RECOVERY)/root/init.recovery.mt8755.rc \
$(DEVICE_PATH)/recovery/root/init.recovery.crypto.rc:$(TARGET_COPY_OUT_RECOVERY)/root/init.recovery.crypto.rc \
$(DEVICE_PATH)/recovery/root/system/etc/vintf/manifest.xml:$(TARGET_COPY_OUT_RECOVERY)/root/system/etc/vintf/manifest.xml \
$(DEVICE_PATH)/recovery/root/system/etc/vintf/manifest/android.hardware.health-service.example.xml:$(TARGET_COPY_OUT_RECOVERY)/root/system/etc/vintf/manifest/android.hardware.health-service.example.xml \
$(DEVICE_PATH)/recovery/root/vendor/manifest.xml:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/manifest.xml \
$(DEVICE_PATH)/recovery/root/vendor/etc/vintf/manifest/android.hardware.health-service.example.xml:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/etc/vintf/manifest/android.hardware.health-service.example.xml \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/0102030405060708090a0b0c0d0e0f10.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/0102030405060708090a0b0c0d0e0f10.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/020f0000000000000000000000000000.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/020f0000000000000000000000000000.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/06090000000000000000000000000000.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/06090000000000000000000000000000.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/08030000000000000000000000000000.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/08030000000000000000000000000000.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/08110000000000000000000000000000.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/08110000000000000000000000000000.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/40188311faf343488db888ad39496f9a.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/40188311faf343488db888ad39496f9a.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/5020170115e016302017012521300000.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/5020170115e016302017012521300000.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/5f7a5b3b29b041bca249524a031a00e3.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/5f7a5b3b29b041bca249524a031a00e3.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/8888c04fc30c4dd0a319ea29643d4d4c.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/8888c04fc30c4dd0a319ea29643d4d4c.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/abcd270ea5c44c58bcd3384a2fa2539e.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/abcd270ea5c44c58bcd3384a2fa2539e.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/c09c9c5daa504b78b0e46eda61556c3a.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/c09c9c5daa504b78b0e46eda61556c3a.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/c1882f2d885e4e13a8c8e2622461b2fa.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/c1882f2d885e4e13a8c8e2622461b2fa.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/d91f322ad5a441d5955110eda3272fc0.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/d91f322ad5a441d5955110eda3272fc0.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/e97c270ea5c44c58bcd3384a2fa2539e.ta:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/e97c270ea5c44c58bcd3384a2fa2539e.ta \
$(DEVICE_PATH)/recovery/root/vendor/thh/ta/isee_model.json:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/thh/ta/isee_model.json \
$(DEVICE_PATH)/recovery/root/vendor/etc/vintf/manifest/android.hardware.security.keymint-service.beanpod.xml:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/etc/vintf/manifest/android.hardware.security.keymint-service.beanpod.xml \
$(DEVICE_PATH)/recovery/root/vendor/etc/vintf/manifest/android.hardware.security.secureclock-service.beanpod.xml:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/etc/vintf/manifest/android.hardware.security.secureclock-service.beanpod.xml \
$(DEVICE_PATH)/recovery/root/vendor/etc/vintf/manifest/android.hardware.security.sharedsecret-service.beanpod.xml:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/etc/vintf/manifest/android.hardware.security.sharedsecret-service.beanpod.xml \
$(DEVICE_PATH)/recovery/root/vendor/etc/vintf/manifest/android.hardware.gatekeeper@1.0-service.xml:$(TARGET_COPY_OUT_RECOVERY)/root/vendor/etc/vintf/manifest/android.hardware.gatekeeper@1.0-service.xml
PRODUCT_PACKAGES += \
sycamore_gatekeeper_impl \
sycamore_gatekeeper_hidl \
sycamore_gatekeeper_service \
sycamore_gatekeeper_soft \
sycamore_gatekeeper_tee \
sycamore_keymint_ndk_v2 \
sycamore_keymint_private_utils \
sycamore_keymaster_messages \
sycamore_keymaster_portable \
sycamore_keymint_private \
sycamore_puresoft_keymaster \
sycamore_soft_attestation \
sycamore_cppbor_external \
sycamore_cppcose_rkp \
sycamore_keymint_service \
sycamore_secureclock_ndk_v1 \
sycamore_sharedsecret_ndk_v1 \
sycamore_tee_common \
sycamore_tee_imsg_log \
sycamore_tee_vfs \
sycamore_teei_daemon \
libsycamore_keytrace
PRODUCT_VENDOR_PROPERTIES += \
ro.vendor.mtk_ufs_support=1 \
ro.vendor.mtk_boot_devices=soc/112b0000.ufshci \
ro.hardware.gatekeeper=beanpod \
ro.crypto.volume.filenames_mode=aes-256-cts

View file

@ -1,298 +0,0 @@
// Diagnostic-only Beanpod STORAGE_KEY boundary tracer.
// Logs only length and SHA-256, then calls the stock A16 implementation.
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <dlfcn.h>
#include <string>
#include <android/log.h>
#include <openssl/sha.h>
namespace {
constexpr const char* kSetKeyMaterialSymbol =
"_ZN9keymaster16ExportKeyRequest14SetKeyMaterialEPKvm";
constexpr const char* kGetPropertySymbol =
"_ZN7android4base11GetPropertyERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_";
// Microtrust uses the GlobalPlatform client ABI, but its headers are not
// shipped in this recovery tree. These declarations contain only the stable
// ABI prefix needed to inspect the four operation parameters. The 24-byte
// parameter union and 112-byte operation layout are also verified against the
// exact stock libTEECommon.so used by Beanpod.
struct TEEC_Context;
struct TEEC_Session;
struct TEEC_SharedMemory {
void* buffer;
size_t size;
};
struct TEEC_TempMemoryReference {
void* buffer;
size_t size;
};
struct TEEC_RegisteredMemoryReference {
TEEC_SharedMemory* parent;
size_t size;
size_t offset;
};
union TEEC_Parameter {
TEEC_TempMemoryReference tmpref;
TEEC_RegisteredMemoryReference memref;
uint8_t abi_size[24];
};
struct TEEC_Operation {
uint32_t started;
uint32_t paramTypes;
TEEC_Parameter params[4];
void* session;
};
static_assert(sizeof(TEEC_Parameter) == 24);
static_assert(sizeof(TEEC_Operation) == 112);
using TEEC_Result = uint32_t;
using InvokeCommand = TEEC_Result (*)(TEEC_Session*, uint32_t, TEEC_Operation*, uint32_t*);
constexpr uint32_t kTeecSuccess = 0;
constexpr uint32_t kTempInput = 0x5;
constexpr uint32_t kTempOutput = 0x6;
constexpr uint32_t kTempInout = 0x7;
constexpr uint32_t kWhole = 0xc;
constexpr uint32_t kPartialInput = 0xd;
constexpr uint32_t kPartialOutput = 0xe;
constexpr uint32_t kPartialInout = 0xf;
struct ByteRange {
const uint8_t* data = nullptr;
size_t size = 0;
bool found = false;
};
uint32_t ParamType(const TEEC_Operation* operation, size_t index) {
return (operation->paramTypes >> (index * 4)) & 0xf;
}
ByteRange FindInput(const TEEC_Operation* operation) {
if (operation == nullptr) return {};
for (size_t i = 0; i < 4; ++i) {
const uint32_t type = ParamType(operation, i);
if (type == kTempInput || type == kTempInout) {
const auto& ref = operation->params[i].tmpref;
return {static_cast<const uint8_t*>(ref.buffer), ref.size, true};
}
if (type == kWhole || type == kPartialInput || type == kPartialInout) {
const auto& ref = operation->params[i].memref;
if (ref.parent == nullptr) return {};
const size_t offset = type == kWhole ? 0 : ref.offset;
const size_t size = type == kWhole ? ref.parent->size : ref.size;
return {static_cast<const uint8_t*>(ref.parent->buffer) + offset, size, true};
}
}
return {};
}
ByteRange FindOutput(const TEEC_Operation* operation) {
if (operation == nullptr) return {};
for (size_t i = 0; i < 4; ++i) {
const uint32_t type = ParamType(operation, i);
if (type == kTempOutput || type == kTempInout) {
const auto& ref = operation->params[i].tmpref;
return {static_cast<const uint8_t*>(ref.buffer), ref.size, true};
}
if (type == kWhole || type == kPartialOutput || type == kPartialInout) {
const auto& ref = operation->params[i].memref;
if (ref.parent == nullptr) return {};
const size_t offset = type == kWhole ? 0 : ref.offset;
const size_t size = type == kWhole ? ref.parent->size : ref.size;
return {static_cast<const uint8_t*>(ref.parent->buffer) + offset, size, true};
}
}
return {};
}
void DigestHex(const uint8_t* data, size_t size, char (&hex)[SHA256_DIGEST_LENGTH * 2 + 1]) {
static constexpr uint8_t empty = 0;
uint8_t digest[SHA256_DIGEST_LENGTH];
SHA256(size == 0 ? &empty : data, size, digest);
static constexpr char digits[] = "0123456789abcdef";
for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
hex[i * 2] = digits[digest[i] >> 4];
hex[i * 2 + 1] = digits[digest[i] & 0x0f];
}
hex[sizeof(hex) - 1] = '\0';
}
bool HasKeymasterError(uint32_t command) {
switch (command) {
case 0x04:
case 0x08:
case 0x0c:
case 0x18:
case 0x48:
case 0x4c:
case 0x50:
case 0x84:
case 0x340000:
return true;
default:
return false;
}
}
void LogDigest(const void* data, size_t size) {
if (size != 64) return;
static std::atomic_flag logged = ATOMIC_FLAG_INIT;
if (logged.test_and_set()) return;
uint8_t digest[SHA256_DIGEST_LENGTH];
SHA256(static_cast<const uint8_t*>(data), size, digest);
char hex[SHA256_DIGEST_LENGTH * 2 + 1];
static constexpr char digits[] = "0123456789abcdef";
for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
hex[i * 2] = digits[digest[i] >> 4];
hex[i * 2 + 1] = digits[digest[i] & 0x0f];
}
hex[sizeof(hex) - 1] = '\0';
__android_log_print(ANDROID_LOG_INFO, "SYCA_DEKEY",
"SYCA_DEKEY_D len=%zu sha256=%s", size, hex);
}
} // namespace
// Diagnostic V13: interpose the single GlobalPlatform boundary used by both
// Beanpod request wrappers. This observes the registered-memory ranges but
// never writes to the operation, shared memory, result, or return-origin.
extern "C" TEEC_Result TEEC_InvokeCommand(TEEC_Session* session, uint32_t command,
TEEC_Operation* operation, uint32_t* return_origin) {
static const InvokeCommand original =
reinterpret_cast<InvokeCommand>(dlsym(RTLD_NEXT, "TEEC_InvokeCommand"));
if (original == nullptr) {
__android_log_print(ANDROID_LOG_FATAL, "SYCA_TA_TRACE",
"stock TEEC_InvokeCommand symbol unavailable");
__builtin_trap();
}
static std::atomic<uint64_t> next_sequence{0};
const uint64_t sequence = next_sequence.fetch_add(1, std::memory_order_relaxed) + 1;
const ByteRange input = FindInput(operation);
const ByteRange output_before = FindOutput(operation);
const uint8_t* input_data = input.found ? input.data : nullptr;
const size_t input_size = input.found ? input.size : 0;
char input_hash[SHA256_DIGEST_LENGTH * 2 + 1];
DigestHex(input_data, input_size, input_hash);
__android_log_print(ANDROID_LOG_INFO, "SYCA_TA_TRACE",
"SYCA_TA_SEQ=%llu session=0x%llx cmd=0x%x in_len=%zu "
"in_sha256=%s out_capacity=%zu",
static_cast<unsigned long long>(sequence),
static_cast<unsigned long long>(reinterpret_cast<uintptr_t>(session)),
command, input_size, input_hash,
output_before.found ? output_before.size : 0);
const TEEC_Result result = original(session, command, operation, return_origin);
const ByteRange output_after = FindOutput(operation);
// A failed TEEC transport did not return a serialized TA response. The
// memref can still retain its pre-call capacity, which must not be logged
// or hashed as though it were returned data.
const bool has_response = result == kTeecSuccess && output_after.found;
const uint8_t* output_data = has_response ? output_after.data : nullptr;
const size_t output_size = has_response ? output_after.size : 0;
char output_hash[SHA256_DIGEST_LENGTH * 2 + 1];
DigestHex(output_data, output_size, output_hash);
char origin[16];
if (return_origin == nullptr) {
memcpy(origin, "NA", 3);
} else {
snprintf(origin, sizeof(origin), "%u", *return_origin);
}
if (result == kTeecSuccess && HasKeymasterError(command) && output_size >= sizeof(int32_t)) {
int32_t keymaster_error;
memcpy(&keymaster_error, output_data, sizeof(keymaster_error));
__android_log_print(ANDROID_LOG_INFO, "SYCA_TA_TRACE",
"SYCA_TA_RET_SEQ=%llu cmd=0x%x teec_ret=%u origin=%s out_len=%zu "
"out_sha256=%s km_error=%d",
static_cast<unsigned long long>(sequence), command, result, origin,
output_size, output_hash, keymaster_error);
} else {
__android_log_print(ANDROID_LOG_INFO, "SYCA_TA_TRACE",
"SYCA_TA_RET_SEQ=%llu cmd=0x%x teec_ret=%u origin=%s out_len=%zu "
"out_sha256=%s",
static_cast<unsigned long long>(sequence), command, result, origin,
output_size, output_hash);
}
return result;
}
namespace android::base {
// V10-IDENTITY one-variable experiment. Beanpod obtains these two fields
// through android::base::GetProperty() while constructing BPConfigureRequest
// for command 0x48. Override only these Beanpod-facing lookups and delegate
// every other property unchanged.
std::string GetProperty(const std::string& key, const std::string& default_value) {
if (key == "ro.product.name" || key == "ro.product.device") {
constexpr const char* kStockIdentity = "XT2575-4";
__android_log_print(ANDROID_LOG_INFO, "SYCA_IDENTITY",
"%s=%s", key.c_str(), kStockIdentity);
return kStockIdentity;
}
using Original = std::string (*)(const std::string&, const std::string&);
static const Original original =
reinterpret_cast<Original>(dlsym(RTLD_NEXT, kGetPropertySymbol));
if (original == nullptr) {
__android_log_print(ANDROID_LOG_FATAL, "SYCA_IDENTITY",
"stock GetProperty symbol unavailable");
__builtin_trap();
}
return original(key, default_value);
}
} // namespace android::base
namespace keymaster {
// V9-OSVERSION one-variable experiment. Beanpod dynamically imports this
// helper when building BPConfigureRequest for command 0x48. Keep recovery's
// global Android 12 properties intact and change only the value observed by
// this Beanpod process.
uint32_t GetOsVersion() {
constexpr uint32_t kAndroid16OsVersion = 160000;
__android_log_print(ANDROID_LOG_INFO, "SYCA_OSVERSION",
"Beanpod ConfigDeviceInfo os_version=%u",
kAndroid16OsVersion);
return kAndroid16OsVersion;
}
class ExportKeyRequest {
public:
void SetKeyMaterial(const void* key_material, size_t length);
};
void ExportKeyRequest::SetKeyMaterial(const void* key_material, size_t length) {
using Original = void (*)(ExportKeyRequest*, const void*, size_t);
static const Original original = reinterpret_cast<Original>(
dlsym(RTLD_NEXT, kSetKeyMaterialSymbol));
LogDigest(key_material, length);
if (original == nullptr) {
__android_log_print(ANDROID_LOG_FATAL, "SYCA_DEKEY",
"stock SetKeyMaterial symbol unavailable");
__builtin_trap();
}
original(this, key_material, length);
}
} // namespace keymaster

View file

@ -1,222 +0,0 @@
#include <android-base/logging.h>
#include <errno.h>
#include <linux/un.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#include "FsCrypt.h"
#include "SycamoreFscryptIpc.h"
namespace sycamore = android::vold::sycamore;
namespace {
bool ReadFully(int fd, void* data, size_t size) {
auto* p = static_cast<uint8_t*>(data);
while (size != 0) {
ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, size));
if (n <= 0) return false;
p += n;
size -= n;
}
return true;
}
bool WriteFully(int fd, const void* data, size_t size) {
const auto* p = static_cast<const uint8_t*>(data);
while (size != 0) {
ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, size));
if (n <= 0) return false;
p += n;
size -= n;
}
return true;
}
template <typename T>
bool Consume(const std::vector<uint8_t>& payload, size_t* offset, T* value) {
if (*offset > payload.size() || sizeof(T) > payload.size() - *offset) return false;
memcpy(value, payload.data() + *offset, sizeof(T));
*offset += sizeof(T);
return true;
}
template <typename T>
void Append(std::vector<uint8_t>* payload, const T& value) {
const auto* p = reinterpret_cast<const uint8_t*>(&value);
payload->insert(payload->end(), p, p + sizeof(value));
}
bool IsRecoveryPeer(int fd) {
ucred cred = {};
socklen_t cred_len = sizeof(cred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) == -1 || cred.uid != 0) {
return false;
}
char context[128] = {};
socklen_t context_len = sizeof(context);
if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, context, &context_len) == -1) return false;
return std::string(context, strnlen(context, context_len)) == "u:r:recovery:s0";
}
int32_t Dispatch(sycamore::Command command, std::vector<uint8_t>* request,
std::vector<uint8_t>* response) {
size_t offset = 0;
switch (command) {
case sycamore::Command::kPing:
return request->empty() ? 0 : -EINVAL;
case sycamore::Command::kInitSystemwide:
if (!request->empty()) return -EINVAL;
LOG(INFO) << "sycamore_fscryptd: INIT_SYSTEMWIDE begin";
if (!fscrypt_initialize_systemwide_keys()) {
LOG(ERROR) << "sycamore_fscryptd: INIT_SYSTEMWIDE fail";
return -EIO;
}
LOG(INFO) << "sycamore_fscryptd: INIT_SYSTEMWIDE success";
return 0;
case sycamore::Command::kInitUser0:
if (!request->empty()) return -EINVAL;
LOG(INFO) << "sycamore_fscryptd: INIT_USER0 begin";
if (!fscrypt_init_user0()) {
LOG(ERROR) << "sycamore_fscryptd: INIT_USER0 fail";
return -EIO;
}
LOG(INFO) << "sycamore_fscryptd: INIT_USER0 success";
return 0;
case sycamore::Command::kUnlockUser: {
int32_t user_id;
int32_t serial;
uint32_t secret_size;
if (!Consume(*request, &offset, &user_id) || !Consume(*request, &offset, &serial) ||
!Consume(*request, &offset, &secret_size) || user_id < 0 || user_id > 9999 ||
secret_size > 1024 || secret_size != request->size() - offset) {
return -EINVAL;
}
std::string secret(reinterpret_cast<const char*>(request->data() + offset), secret_size);
LOG(INFO) << "sycamore_fscryptd: UNLOCK_USER user=" << user_id << " begin";
bool ok = fscrypt_unlock_user_key(user_id, serial, secret);
std::fill(secret.begin(), secret.end(), '\0');
std::fill(request->begin(), request->end(), 0);
if (ok) {
LOG(INFO) << "sycamore_fscryptd: UNLOCK_USER user=" << user_id << " success";
} else {
LOG(ERROR) << "sycamore_fscryptd: UNLOCK_USER user=" << user_id << " fail";
}
return ok ? 0 : -EIO;
}
case sycamore::Command::kPrepareUserStorage: {
int32_t user_id;
int32_t serial;
int32_t flags;
uint32_t uuid_size;
if (!Consume(*request, &offset, &user_id) || !Consume(*request, &offset, &serial) ||
!Consume(*request, &offset, &flags) || !Consume(*request, &offset, &uuid_size) ||
user_id < 0 || user_id > 9999 || uuid_size > 128 ||
uuid_size != request->size() - offset || (flags & ~3) != 0 || flags == 0) {
return -EINVAL;
}
std::string uuid(reinterpret_cast<const char*>(request->data() + offset), uuid_size);
return fscrypt_prepare_user_storage(uuid, user_id, serial, flags) ? 0 : -EIO;
}
case sycamore::Command::kClassifyPolicy: {
uint32_t ref_size;
if (!Consume(*request, &offset, &ref_size) || ref_size == 0 || ref_size > 64 ||
ref_size != request->size() - offset) {
return -EINVAL;
}
std::string ref(reinterpret_cast<const char*>(request->data() + offset), ref_size);
FscryptPolicyKind kind = FscryptPolicyKind::kUnknown;
userid_t user_id = 0;
if (!fscrypt_classify_policy_ref(ref, &kind, &user_id)) return -ENOENT;
int32_t kind_value = static_cast<int32_t>(kind);
int32_t uid = user_id;
Append(response, kind_value);
Append(response, uid);
return 0;
}
case sycamore::Command::kResolvePolicy: {
int32_t kind_value;
int32_t user_id;
if (!Consume(*request, &offset, &kind_value) || !Consume(*request, &offset, &user_id) ||
offset != request->size() || user_id < 0 || user_id > 9999) {
return -EINVAL;
}
std::string ref;
if (!fscrypt_resolve_policy_ref(static_cast<FscryptPolicyKind>(kind_value), user_id,
&ref) ||
ref.empty() || ref.size() > 64) {
return -ENOENT;
}
response->assign(ref.begin(), ref.end());
return 0;
}
default:
return -ENOTSUP;
}
}
void HandleClient(int fd) {
if (!IsRecoveryPeer(fd)) {
LOG(ERROR) << "sycamore_fscryptd: rejected unauthorized peer";
return;
}
sycamore::RequestHeader header = {};
if (!ReadFully(fd, &header, sizeof(header)) || header.magic != sycamore::kMagic ||
header.version != sycamore::kVersion || header.payload_size > sycamore::kMaxPayload) {
return;
}
std::vector<uint8_t> request(header.payload_size);
if (!request.empty() && !ReadFully(fd, request.data(), request.size())) return;
std::vector<uint8_t> response;
int32_t status = Dispatch(static_cast<sycamore::Command>(header.command), &request, &response);
sycamore::ResponseHeader reply{sycamore::kMagic, sycamore::kVersion, header.command, status,
static_cast<uint32_t>(response.size())};
WriteFully(fd, &reply, sizeof(reply));
if (!response.empty()) WriteFully(fd, response.data(), response.size());
std::fill(request.begin(), request.end(), 0);
}
int CreateServerSocket() {
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (fd == -1) return -1;
sockaddr_un addr = {};
addr.sun_family = AF_UNIX;
static_assert(sizeof(sycamore::kSocketName) <= sizeof(addr.sun_path));
memcpy(addr.sun_path + 1, sycamore::kSocketName, sizeof(sycamore::kSocketName) - 1);
socklen_t len = offsetof(sockaddr_un, sun_path) + 1 + sizeof(sycamore::kSocketName) - 1;
if (bind(fd, reinterpret_cast<sockaddr*>(&addr), len) == -1 || listen(fd, 4) == -1) {
close(fd);
return -1;
}
return fd;
}
} // namespace
int main() {
signal(SIGPIPE, SIG_IGN);
int server = CreateServerSocket();
if (server == -1) {
PLOG(ERROR) << "sycamore_fscryptd: unable to create private socket";
return 1;
}
LOG(INFO) << "sycamore_fscryptd: started";
for (;;) {
int client = TEMP_FAILURE_RETRY(accept4(server, nullptr, nullptr, SOCK_CLOEXEC));
if (client == -1) {
if (errno == EINTR) continue;
PLOG(ERROR) << "sycamore_fscryptd: accept failed";
return 1;
}
HandleClient(client);
close(client);
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more