第 40 章:安全 📅 发布时间:2026/8/29 6:24:56 👁 浏览次数: Android 的安全架构是消费级设备领域一套完备且分层的防御体系。从引导加载程序、内核、系统服务到应用框架,每一个组件都参与多层次的 “深度防御” 策略。本章将逐一讲解各个主要子系统:SELinux 强制访问控制、验证启动、硬件密钥存储、Trusty TEE、生物识别认证、应用沙箱、加密以及网络安全,每一部分均结合 AOSP 实际源码进行解读。40.1 Android 安全模型40.1.1 设计原则Android 安全模型建立在四项基础原则之上:应用沙箱—— 每个应用使用独立的 Linux UID 运行在独立进程,拥有私有数据目录。最小权限原则—— 应用启动时几乎不具备任何权限,必须显式申请权限,由用户或系统策略授予 / 拒绝权限。深度防御—— 不单独信任任意单一安全机制。内核沙箱、SELinux 强制访问控制、seccomp‑BPF 以及用户态权限检查构成相互独立的多层防护。默认安全—— 新功能默认处于严格受限状态,需要显式放开限制。40.1.2 分层防御总览40.1.3 应用签名所有 APK 在安装前必须完成签名。Android 支持多种签名方案:方案引入版本工作原理v1(JAR)Android 1.0通过 META‑INF/ 对 ZIP 内部条目逐一签名v2Android 7.0将整个 APK 作为二进制块整体签名v3Android 9在 v2 基础上增加密钥轮换支持v3.1Android 13新增 rotation‑min‑sdk‑version 字段v4Android 11生成独立.idsig 文件,用于增量安装签名用于确定开发者身份。包管理器将签名用于如下场景:升级校验 —— 更新包必须与已安装包使用相同密钥签名。共享 UID —— 使用相同密钥签名的多个包可以申请同一个 Linux UID,实现数据共享。签名权限 —— 部分权限仅允许授予使用平台密钥签名的应用。40.1.4 权限模型Android 将权限划分为三个保护等级:normal—— 安装时自动授予(例如 INTERNET)。dangerous—— 需要运行时用户显式授权(例如 CAMERA、READ_CONTACTS)。signature—— 仅授予与权限定义方使用同一证书签名的应用,或平台自身。权限在多个层级完成校验:框架层检查 —— Java/Kotlin 代码中Context.checkPermission()。Binder 服务检查 —— 服务校验调用方 UID 与 PID。内核层检查 —— SELinux 与 Linux 自主访问控制,即便绕过框架层校验也会阻止非法访问。40.1.5 从硬件到应用的信任链信任链起始于不可修改的硬件(SoC Boot ROM 中烧录的公钥),逐层延伸直至应用层。如果信任链任意一环被破坏,设备能够检测并作出响应,根据策略选择拒绝启动、弹出警告或清除用户数据。40.1.6 安全边界定义理解 Android 安全需要明确各个信任边界:边界受信任(内部)不受信任(外部)硬件信任根烧录密钥、Boot ROM全部软件TEE 边界Trusty 内核 + 可信应用 TALinux 内核、Android 框架内核边界内核代码、已加载模块全部用户态进程系统服务边界system_server、特权守护进程应用、不可信代码应用沙箱边界应用自身进程与私有数据其他应用、系统内部组件各个边界依靠不同机制强制隔离:硬件信任根:物理熔丝、一次性可编程存储。TEE 边界:ARM TrustZone 硬件(TZASC、EL3 安全监控程序)。内核边界:CPU 特权级别(EL0 对比 EL1)、页表隔离。系统服务边界:SELinux 类型强制 + Linux 自主访问控制。应用沙箱:UID 隔离 + SELinux + seccomp‑BPF + 挂载命名空间。40.1.7 威胁模型Android 安全模型考虑如下威胁主体:恶意应用—— 试图窃取其他应用数据、提升权限、卸载后依然驻留的应用。网络攻击者—— 可以观测、篡改网络流量的对手(例如公共 WiFi 环境)。物理攻击者—— 拿到设备物理控制权(被盗手机、取证分析)。供应链攻击者—— 尝试向系统镜像或引导加载程序注入恶意代码。内部威胁—— 被攻陷的厂商代码或拥有高权限的 HAL 组件。各个安全子系统分别应对特定威胁:40.1.8 多用户安全单台 Android 设备支持多用户。每个用户拥有:独立 userId(0, 10, 11 …)。独立加密存储(每个用户拥有 CE、DE 密钥)。独立已安装应用,每个应用拥有按用户生成的 UID(appId + userId * 100000)。独立锁屏凭据。SELinux MLS(多级安全)分类标签,防止同一应用内跨用户数据访问。SELinux MLS 分类依据用户 ID 分配,在强制访问控制层面实现用户之间的密码学隔离。40.1.9 工作资料安全Android 工作资料(托管配置文件)将多用户安全能力扩展至企业场景:工作应用运行在独立用户 ID 之下(例如 user 10)。独立加密密钥保护工作数据。IT 管理员可远程擦除工作资料,不会影响个人数据。跨资料数据共享由设备策略控制器管控。工作资料应用与个人应用并排显示,但处于沙箱隔离。40.2 SELinuxSELinux(安全增强型 Linux)为 Android 提供强制访问控制(MAC)。传统自主访问控制(DAC)由文件所有者管控权限;与之不同,SELinux 执行一套集中式策略,即便是 root 进程也无法绕过。40.2.1 Android 上的 SELinux 架构Android 自 Android 5.0 起默认启用 SELinux 强制模式。策略在编译阶段由system/sepolicy/下的源文件编译生成。目录结构包含 15 个子目录,用途如下:目录用途public/可供厂商策略引用的类型与属性定义private/平台私有策略(allow、neverallow 规则)vendor/厂商 HAL 策略contexts/文件、属性、服务上下文配置mac_permissions/用于应用签名的 MAC 权限 XML 配置build/构建系统集成脚本compat/平台版本之间的兼容映射tools/策略分析工具tests/兼容 CTS 的策略测试用例apex/针对 APEX 模块的策略prebuilts/用于 API 版本兼容的预编译策略reqd_mask/策略必需掩码flagging/由特性开关控制的策略microdroid/pVM microdroid 虚拟机相关策略treble_sepolicy_tests_for_release/Treble 兼容性测试40.2.2 类型强制(TE)类型强制是 SELinux 的核心机制。每一个进程被分配一个域(type),每一个对象(文件、socket、binder 等)分配一个类型。访问行为仅在存在显式 allow 规则时才被允许。基础规则语法:allow source_domain target_type:object_class permissions;下面是system/sepolicy/public/app.te中,所有由 zygote 孵化的应用的基础策略片段:### ### Domain for all zygote spawned apps ### ### This file is the base policy for all zygote spawned apps. ### Other policy files, such as isolated_app.te, untrusted_app.te, etc ### extend from this policy. Only policies which should apply to ALL ### zygote spawned apps should be added here. ### type appdomain_tmpfs, file_type;设计说明:public / 目录仅存放类型、属性定义,不包含 allow 或 neverallow 语句;这类规则放置在 private / 目录。40.2.3 域与属性属性是一组类型的集合,可以编写规则一次性作用于多个域。取自system/sepolicy/public/attributes(共 490 行):# All types used for devices. attribute dev_type; # All types used for processes. attribute domain; # All types used for filesystems. attribute fs_type; # All types used for files that can exist on a labeled fs. attribute file_type; # All types used for domain entry points. attribute exec_type; # All types used for /data files. attribute data_file_type; # All types used for app private data files in seapp_contexts. attribute app_data_file_type;domain属性至关重要,所有进程类型都会继承该属性。private/domain.te中的规则作用于系统全部进程:# Rules for all domains. # Allow reaping by init. allow domain init:process sigchld; # Intra‑domain accesses. allow domain self:process { fork sigchld sigkill sigstop signull signal getsched setsched getsession getpgid getcap setcap getattr setrlimit }; allow domain self:fd use; allow domain proc:dir r_dir_perms;40.2.4 类型转换当进程执行新二进制程序时,SELinux 可以自动将进程切换至新域。init 启动守护进程并赋予正确域就是依靠该机制:# When init runs /system/bin/vold, transition to vold domain domain_auto_trans(init, vold_exec, vold)domain_auto_trans宏展开后等价于:type_transition init vold_exec:process vold; allow init vold:process transition; allow vold vold_exec:file { read getattr map execute entrypoint };40.2.5 通过 seapp_contexts 分配应用域文件system/sepolicy/private/seapp_contexts(216 行)根据应用属性映射到 SELinux 域。输入筛选条件:isSystemServer(布尔)isEphemeralApp(布尔)user(字符串)seinfo(字符串)name(字符串)isPrivApp(布尔)minTargetSdkVersion(无符号整数)fromRunAs(布尔)示例映射:筛选条件域isSystemServer=truesystem_serveruser=system seinfo=platformsystem_appuser=_app minTargetSdkVersion=37untrusted_appuser=_app minTargetSdkVersion=34untrusted_app_34user=_app minTargetSdkVersion=32untrusted_app_32user=_app minTargetSdkVersion=30untrusted_app_30user=_app minTargetSdkVersion=29untrusted_app_29user=_isolatedisolated_app带版本后缀的域(untrusted_app_25、untrusted_app_27 等)用于在保持向下兼容的前提下,对旧版本应用施加越来越严格的限制。targetSdkVersion 版本更高的应用会执行最严格的规则。40.2.6 Neverallow 规则neverallow 属于编译期断言。它不会生成运行时策略,但会阻止任何人(包括厂商策略编写者)编写违反约束的规则。一旦策略改动触发 neverallow,构建直接失败。取自system/sepolicy/private/app_neverallows.te(338 行)的示例:define(`all_untrusted_apps',`{ ephemeral_app isolated_app isolated_app_all isolated_compute_app mediaprovider mediaprovider_app untrusted_app untrusted_app_25 untrusted_app_27 untrusted_app_29 untrusted_app_30 untrusted_app_all }') # Receive or send uevent messages. neverallow all_untrusted_apps domain:netlink_kobject_uevent_socket *; # Do not allow untrusted apps to register services. neverallow all_untrusted_apps service_manager_type:service_manager add; # Do not allow untrusted apps to use VendorBinder neverallow all_untrusted_apps vndbinder_device:chr_file *; # Do not allow untrusted apps to connect to the property service neverallow { all_untrusted_apps -mediaprovider } property_socket:sock_file write; neverallow { all_untrusted_apps -mediaprovider } init:unix_stream_socket connectto; neverallow { all_untrusted_apps -mediaprovider } property_type:property_service set; # Block calling execve() on files in an apps home directory. # This is a W^X violation. For compatibility, allow for targetApi = 28. neverallow { all_untrusted_apps -untrusted_app_25 -untrusted_app_27 -runas_app } { app_data_file privapp_data_file }:file execute_no_trans;针对不可信应用的关键 neverallow 约束分类:禁止注册服务 —— 应用不能向 servicemanager 新增服务。禁止访问 VendorBinder —— 应用不能直接和厂商 HAL 通信。禁止修改系统属性。禁止访问内核接口 —— 禁止 uevent 套接字、sysfs 写、debugfs 读、读取 /proc 下敏感文件。禁止 W^X 违背行为 —— targetSdk =29 的应用不能执行自身目录下文件。禁止硬链接,规避 installd 删除防护。套接字类型受限,仅允许 TCP/UDP/VSOCK,禁止 raw、netlink 套接字。40.2.7 HAL NeverallowsHAL 服务同样存在限制,取自system/sepolicy/private/hal_neverallows.te:# only HALs responsible for network hardware should have privileged # network capabilities neverallow { halserverdomain -hal_bluetooth_server -hal_wifi_server -hal_wifi_hostapd_server -hal_wifi_supplicant_server -hal_telephony_server -hal_uwb_server ... } self:global_capability_class_set { net_admin net_raw };该规则确保被攻陷的音频 HAL、相机 HAL 无法获取网络特权能力。40.2.8 Treble 厂商 SEPolicy 拆分Project Treble 将平台与厂商 SEPolicy 做隔离,支持平台、厂商分区独立升级。兼容性关系:拆分规则:public / 下类型、属性作为 API,厂商策略可以引用。private / 下类型与规则对厂商策略不可见;厂商策略不能编写针对 private 类型的 allow 规则。compat / 存放跨平台版本的类型名称映射。vendor / 存放厂商 HAL 实现专属策略。厂商 sepolicy 目录示例文件:vendor/ file.te file_contexts hal_atrace_default.te hal_audio_default.te hal_bluetooth_default.te hal_camera_default.te hal_fingerprint_default.te hal_gatekeeper_default.te hal_keymint_default.te ...40.2.9 全局域规则private/domain.te包含作用于系统全部进程的规则,是最重要的策略文件之一,节选示例:# Root fs. allow domain tmpfs:dir { getattr search }; allow domain rootfs:dir search; allow domain rootfs:lnk_file { read getattr }; # Device accesses. allow domain device:dir search; allow domain dev_type:lnk_file r_file_perms; allow domain null_device:chr_file rw_file_perms; allow domain zero_device:chr_file rw_file_perms; # /dev/binder can be accessed by ... everyone! :) allow { domain -hwservicemanager -vndservicemanager } binder_device:chr_file rw_file_perms; # Restrict binder ioctls to an allowlist. allowxperm domain binder_device:chr_file ioctl { unpriv_binder_ioctls }; # /dev/binderfs needs to be accessed by everyone too! allow domain binderfs:dir { getattr search }; allow domain binderfs_features:dir search; allow domain binderfs_features:file r_file_perms; # Global access to cacerts, seccomp_policy, system libs allow domain system_seccomp_policy_file:file r_file_perms; allow domain system_security_cacerts_file:file r_file_perms; allow domain system_linker_exec:file { execute read open getattr map }; allow domain system_lib_file:file { execute read open getattr map };即使是全局规则同样做精细范围约束。Binder 作为 IPC 基础组件全部进程均可访问,但 ioctl 操作被限制为非特权集合。hwservicemanager、vndservicemanager 被排除在标准 binder 设备访问之外,它们使用 hwbinder_device、vndbinder_device。40.2.10 应用域策略(private/app.te)system/sepolicy/private/app.te(844 行)定义所有 zygote 孵化的应用进程规则。Keystore 访问片段:allow { appdomain -isolated_app_all -ephemeral_app -sdk_sandbox_all } keystore:keystore2_key { delete use get_info grant rebind update }; use_keystore({ appdomain -isolated_app_all -ephemeral_app -sdk_sandbox_all })应用沙箱文件访问:# App sandbox file accesses. allow { appdomain -isolated_app_all -mlstrustedsubject -sdk_sandbox_all } { app_data_file privapp_data_file }:dir create_dir_perms; allow { appdomain -isolated_app_all -mlstrustedsubject -sdk_sandbox_all } { app_data_file privapp_data_file }:file create_file_perms;Binder IPC:# Use the Binder. binder_use(appdomain) # Perform binder IPC to binder services. binder_call(appdomain, binderservicedomain) # Perform binder IPC to other apps. binder_call(appdomain, appdomain) # Perform binder IPC to ephemeral apps. binder_call(appdomain, ephemeral_app)app.te 中 neverallow 片段(节选,总计约 300 条 neverallow):# Superuser capabilities. neverallow { appdomain -bluetooth -network_stack -nfc } self:capability_class_set *; # Block device access. neverallow appdomain dev_type:blk_file { read write }; # ptrace access to non‑app domains. neverallow appdomain { domain -appdomain }:process ptrace; # The Android security model guarantees the confidentiality and # integrity of application data and execution state. Ptrace bypasses # those confidentiality guarantees. neverallow { domain -appdomain -crash_dump } appdomain:process ptrace; # Write to rootfs. neverallow appdomain rootfs:dir_file_class_set { create write setattr relabelfrom relabelto append unlink link rename }; # Write to /system. neverallow appdomain system_file_type:dir_file_class_set { create write setattr relabelfrom relabelto append unlink link rename }; # Write to system‑owned parts of /data. neverallow appdomain system_data_file:dir_file_class_set { create write setattr relabelfrom relabelto append unlink link rename }; # Transition to a non‑app domain (prevent domain escalation). neverallow { appdomain -shell } { domain -appdomain -crash_dump -rs -virtualizationmanager }:process { transition }; # Sensitive app domains are not allowed to execute from /data # to prevent persistence attacks. neverallow { bluetooth isolated_app_all nfc radio shared_relro sdk_sandbox_all system_app } { data_file_type -apex_art_data_file -dalvikcache_data_file -system_data_file -apk_data_file }:file no_x_file_perms; # Don't allow apps access to character devices. neverallow appdomain { audio_device camera_device dm_device radio_device rpmsg_device }:chr_file { read write }; # Apps cannot access proc/net tcp/udp tables. neverallow { appdomain -shell } proc_net_tcp_udp:file *;这一系列 neverallow 保证:即使框架层存在漏洞可以走到某条代码路径,内核层 MAC 策略依然会阻止该操作。40.2.11 策略编译与加载SELinux 策略编译发生在构建阶段,由 init 在开机早期加载。构建流程:m4 预处理 —— 展开 domain_auto_trans、app_domain、net_domain 等宏。策略编译 —— checkpolicy 将.te 编译为二进制策略。上下文编译 —— sefcontext_compile 将 file_contexts 编译为二进制格式。CIL 编译 —— Android 8.0 起,平台 / 厂商分离模式下策略编译为 CIL 通用中间语言。策略校验 —— sepolicy_tests 与 neverallow 作为构建期断言执行。加载 —— init 通过/sys/fs/selinux/load读取/system/etc/selinux/下编译完成的策略。分离策略加载流程:40.2.12 audit2allow 工具使用SELinux 拦截操作时会生成审计日志(denial 拒绝日志)。audit2allow 工具可以将拒绝日志转换为候选 allow 规则。# 抓取设备上的avc拒绝日志 adb shell dmesg | grep 'avc: denied' denials.txt # 生成allow规则 audit2allow -i denials.txt # 生成可加载策略模块 audit2allow -i denials.txt -M my_module拒绝日志示例以及对应输出规则:# Denial: avc: denied { read } for pid=1234 comm="my_daemon" dev="sda1" ino=5678 scontext=u:r:my_daemon:s0 tcontext=u:object_r:system_file:s0 tclass=file permissive=0 # audit2allow输出: allow my_daemon system_file:file read;注意:直接套用 audit2allow 输出是危险的。正确做法通常是为目标文件创建专属 type,而不是授予宽泛的 system_file 访问权限。40.2.13 SELinux 上下文文件一系列上下文文件将文件路径、系统属性、Binder 服务映射为 SELinux 标签。文件用途file_contexts文件系统路径映射到文件 typeproperty_contexts系统属性映射 typeservice_contextsBinder 服务映射 typehwservice_contextsHIDL 硬件服务映射 typeseapp_contexts应用映射域与数据 typemac_permissions.xml应用签名映射 seinfo 标签40.2.14 常用调试手段开发新系统服务或 HAL 时,经常遇到 SELinux 拒绝。标准排查步骤:步骤 1:定位拒绝日志avc: denied { write } for pid=2456 comm="my_service" path="/data/misc/my_service/config" scontext=u:r:my_service:s0 tcontext=u:object_r:system_data_file:s0 tclass=file permissive=0步骤 2:拆解拒绝日志要素source:my_service(尝试访问的进程)target:system_data_file(被访问对象)class:file(对象类型)permission:write(尝试执行的操作)步骤 3:确定正确修复方案错误写法(权限过宽):# BAD: Grants access to all system_data_file allow my_service system_data_file:file write;正确方案(新建专属 type):# file.te中定义 type my_service_data_file, file_type, data_file_type; # file_contexts中配置路径标签 /data/misc/my_service(/.*)? u:object_r:my_service_data_file:s0 # my_service.te编写访问规则 allow my_service my_service_data_file:file create_file_perms; allow my_service my_service_data_file:dir create_dir_perms;步骤 4:neverallow 校验写完策略后重新编译,确认没有触发 neverallow 规则。40.2.15 SELinux MLS/MCS 实现用户隔离Android 使用 MLS 多级安全分类标签隔离用户与应用。每个应用进程根据 user ID、app ID 分配分类标签。示例标签:u:r:untrusted_app:s0:c42,c256,c512,c768c42,c256,c512,c768是由 UID 推导的 MLS 分类。只有分类标签互相兼容的进程,才可以互相访问对方文件。在内核层面隔离:不同 Android 用户(user0 与 user10)同一用户下不同应用工作资料应用与个人应用分类标签分配由 seapp_contexts 控制:levelFrom=all:同时基于 UID 与 user ID 生成安全等级levelFrom=user:仅基于 user ID 生成安全等级levelFrom=app:仅基于进程 UID 生成安全等级40.3 验证启动(AVB)Android 验证启动(Android Verified Boot,AVB)保证执行的全部代码来自可信来源,没有被攻击者篡改或损坏。源码位于external/avb/。40.3.1 AVB 架构验证启动建立从硬件熔丝到各个分区完整的信任链。流程:40.3.2 vbmeta 镜像格式vbmeta 镜像为 AVB 核心数据结构,头文件external/avb/libavb/avb_vbmeta_image.h。/* Size of the vbmeta image header. */ #define AVB_VBMETA_IMAGE_HEADER_SIZE 256 /* Magic for the vbmeta image header. */ #define AVB_MAGIC "AVB0" #define AVB_MAGIC_LEN 4镜像由三块组成:+-----------------------------------------+ | Header data - fixed size (256 bytes) | +-----------------------------------------+ | Authentication data - variable size | +-----------------------------------------+ | Auxiliary data - variable size | +-----------------------------------------+头部结构体定义:typedef struct AvbVBMetaImageHeader { /* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */ uint8_t magic[AVB_MAGIC_LEN]; /* 4: The major version of libavb required for this header. */ uint32_t required_libavb_version_major; /* 8: The minor version of libavb required for this header. */ uint32_t required_libavb_version_minor; /* 12: The size of the signature block. */ uint64_t authentication_data_block_size; /* 20: The size of the auxiliary data block. */ uint64_t auxiliary_data_block_size; /* 28: The verification algorithm used. */ uint32_t algorithm_type; /* 32: Offset into the "Authentication data" block of hash data. */ uint64_t hash_offset; /* 40: Length of the hash data. */ uint64_t hash_size; /* 48: Offset into the "Authentication data" block of signature data. */ uint64_t signature_offset; /* 56: Length of the signature data. */ uint64_t signature_size; /* 64: Offset into the "Auxiliary data" block of public key data. */ uint64_t public_key_offset; /* 72: Length of the public key data. */ uint64_t public_key_size; /* 112: The rollback index for rollback protection. */ uint64_t rollback_index; /* 120: Flags from the AvbVBMetaImageFlags enumeration. */ uint32_t flags; /* 124: The location of the rollback index. */ uint32_t rollback_index_location; /* 128: The release string from avbtool. */ uint8_t release_string[AVB_RELEASE_STRING_SIZE]; /* 176: Padding to ensure struct is size 256 bytes. */ uint8_t reserved[80]; } AVB_ATTR_PACKED AvbVBMetaImageHeader;40.3.3 校验结果码校验返回结果在同一头文件中定义:typedef enum { AVB_VBMETA_VERIFY_RESULT_OK, AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED, AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER, AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION, AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH, AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH, } AvbVBMetaVerifyResult;非常重要:即便返回 AVB_VBMETA_VERIFY_RESULT_OK,仍然必须校验镜像内公钥是否属于设备信任公钥集合!40.3.4 Slot 校验用于完整 Slot 校验的高层 API 为avb_slot_verify(),位于external/avb/libavb/avb_slot_verify.h。AvbSlotVerifyResult avb_slot_verify( AvbOps* ops, const char* const* requested_partitions, const char* ab_suffix, AvbSlotVerifyFlags flags, AvbHashtreeErrorMode hashtree_error_mode, AvbSlotVerifyData** out_data);结果码:typedef enum { AVB_SLOT_VERIFY_RESULT_OK, AVB_SLOT_VERIFY_RESULT_ERROR_OOM, AVB_SLOT_VERIFY_RESULT_ERROR_IO, AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION, AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX, AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED, AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA, AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION, AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT } AvbSlotVerifyResult;external/avb/libavb/avb_slot_verify.c关键常量:/* Maximum number of partitions that can be loaded with avb_slot_verify(). */ #define MAX_NUMBER_OF_LOADED_PARTITIONS 32 /* Maximum number of vbmeta images that can be loaded. */ #define MAX_NUMBER_OF_VBMETA_IMAGES 32 /* Maximum size of a vbmeta image - 64 KiB. */ #define VBMETA_MAX_SIZE (64 * 1024)40.3.5 Chain Partition 描述符大型系统会将 vbmeta 拆分到多个分区。链式分区描述符指向另一个分区的 vbmeta,构成校验树。头文件external/avb/libavb/avb_chain_partition_descriptor.h。typedef struct AvbChainPartitionDescriptor { AvbDescriptor parent_descriptor; uint32_t rollback_index_location; uint32_t partition_name_len; uint32_t public_key_len; uint32_t flags; uint8_t reserved[60]; } AVB_ATTR_PACKED AvbChainPartitionDescriptor;举例:vendor_boot 分区可以拥有独立签名密钥与回滚索引,不依赖主 vbmeta。40.3.6 回滚保护每个 vbmeta 镜像包含rollback_index单调递增计数器。引导加载程序将最小可接受回滚索引存储在防篡改存储介质(通常 RPMB 或者熔丝)。攻击者刷入旧存在漏洞镜像时:旧镜像 rollback_index 小于设备存储阈值avb_slot_verify 返回AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX引导加载程序拒绝启动该镜像最多支持 32 个回滚索引位置:#define AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS 3240.3.7 AVB Footer对于镜像数据末尾追加 vbmeta 的分区,分区最尾部的 Footer 指向 vbmeta 位置。头文件external/avb/libavb/avb_footer.h。#define AVB_FOOTER_MAGIC "AVBf" #define AVB_FOOTER_SIZE 64 typedef struct AvbFooter { uint8_t magic[AVB_FOOTER_MAGIC_LEN]; uint32_t version_major; uint32_t version_minor; uint64_t original_image_size; uint64_t vbmeta_offset; uint64_t vbmeta_size; uint8_t reserved[28]; } AVB_ATTR_PACKED AvbFooter;40.3.8 dm‑verity 运行时防护仅有验证启动还不够,运行时完整性校验由 dm‑verity 完成。针对只读分区(system、vendor、product),AVB 配置 Linux device‑mapper 的 dm‑verity,读取每一个磁盘块时与 Merkle 树哈希比对。Hashtree 错误模式,定义发生损坏时的行为:typedef enum { AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, AVB_HASHTREE_ERROR_MODE_RESTART, AVB_HASHTREE_ERROR_MODE_EIO, AVB_HASHTREE_ERROR_MODE_LOGGING, AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO, AVB_HASHTREE_ERROR_MODE_PANIC } AvbHashtreeErrorMode