GrapheneOS 中 hardened_malloc 的每堆隔离设计:守卫区域、完整性检查与分配器分区
在 GrapheneOS 中,hardened_malloc 通过每堆隔离设计防范堆基攻击,给出守卫区域配置、完整性检查机制与分配器分区参数。
在移动操作系统如 GrapheneOS 中,内存分配器的安全性至关重要,因为堆基利用是常见攻击向量。hardened_malloc 作为 GrapheneOS 的核心组件,采用每堆隔离设计,通过守卫区域、完整性检查和分配器分区来有效防止内存腐败和利用。这种设计的核心观点是,将内存分配细分为独立区域,并施加严格的隔离和验证机制,从而最小化攻击面并提升检测能力。相比传统分配器,它牺牲部分性能换取更强的安全性,特别适合资源受限的移动环境。
每堆隔离是 hardened_malloc 的基础策略,确保不同分配类型和大小的内存之间无重叠或可预测偏移。分配器将 slab 分配区域划分为多个竞技场(arenas),每个竞技场独立管理其子区域,默认配置为 4 个竞技场。这种分区类似于多堆模型,但更细粒度:在每个竞技场内,进一步按大小类(size classes)划分子区域,每类有高熵随机基址,避免地址预测。证据显示,这种隔离直接阻断跨大小类的利用链,因为攻击者无法从一个大小类泄露信息到另一个。例如,大小类从 16 字节到 128KB(扩展配置下),每个类占用独立内存子区域,间以守卫空间。这种设计源于 OpenBSD malloc 的演进,但优化为 64 位专用,充分利用地址空间。
守卫区域(guard regions)进一步强化隔离,提供物理级别的内存保护。在 slab 分配中,默认每隔一个 slab 插入一个守卫 slab,该 slab 保持 PROT_NONE 状态,不可读写。通过 CONFIG_GUARD_SLABS_INTERVAL 参数控制间隔,默认值为 1,确保密集分布的保护层。对于大分配(超过最大 slab 大小,如 128KB),在两侧添加随机大小的守卫区域,默认最大大小为分配大小的 1/2(CONFIG_GUARD_SIZE_DIVISOR=2)。这些守卫区域使用 mmap 映射为不可访问内存,防止溢出或欠流直接影响相邻分配。完整性检查与守卫结合:在每个 slab 槽后放置 8 字节金丝雀(canary),首字节为零以捕获 C 字符串溢出,其余为 per-slab 随机值。释放时检查金丝雀完整性,若损坏则触发中止。同时,写后释放检查通过验证新分配的零填充完整性,确保前次释放的零化未被篡改。
分配器分区机制通过竞技场和大小类实现高效隔离,同时支持检疫(quarantine)延迟释放。小分配使用 slab 机制,按大小类分区;大分配则直接 mmap,独立于 slab 区域。检疫队列包括 FIFO 队列和随机数组:小分配的 CONFIG_SLAB_QUARANTINE_QUEUE_LENGTH 默认 1(按大小缩放),CONFIG_SLAB_QUARANTINE_RANDOM_LENGTH 类似;大分配有 1024 长 FIFO 和 256 长随机数组,阈值 32MB 以上跳过检疫。这种分区防止即时重用,结合零化释放(CONFIG_ZERO_ON_FREE=true),清除敏感数据。随机槽选择(CONFIG_SLOT_RANDOMIZE=true)在 slab 内随机挑选空闲槽,进一步模糊地址模式。
在实际落地中,配置 hardened_malloc 需要调整系统参数以支持其高映射需求。首先,在 init.rc 或 sysctl 中设置 vm.max_map_count=1048576,避免 mmap 失败,尤其在 Android 环境中。其次,选择配置变体:默认配置启用所有安全特性,如零化、写后检查和金丝雀,但内存开销较高;轻量配置(light.mk)禁用检疫随机和写后检查,将 CONFIG_GUARD_SLABS_INTERVAL 设为 8,适合性能敏感场景。监控要点包括:跟踪 mallinfo 输出,关注 nmalloc/ndalloc 计数和 slab_allocated 与 allocated 差值,检测碎片;使用 malloc_info XML 解析 arenas 统计,确保无异常增长。回滚策略:若兼容性问题(如 OpenSSH <8.1),临时切换 jemalloc,但需评估安全风险。
参数清单:
-
N_ARENA=4:竞技场数,平衡并发与隔离。
-
CONFIG_EXTENDED_SIZE_CLASSES=true:扩展大小类至 128KB,减少大分配 mmap 调用。
-
CONFIG_LARGE_SIZE_CLASSES=true:大分配使用大小类而非页粒度,提升 realloc 性能。
-
CONFIG_SLAB_CANARY=true:启用金丝雀,吸收小溢出。
阈值建议:
-
检疫阈值:小分配全启用,大分配 >32MB 禁用以控内存。
-
守卫间隔:生产环境 1~8,根据 RSS 监控调整。
-
随机种子:依赖 getrandom,定期重播以防预测。
这种设计在 GrapheneOS 中证明有效,防范如线性溢出和使用后释放攻击。通过上述参数,可在自定义移动 OS 中复现,监控 mmap 调用率 <5% 以验证效率。总体,hardened_malloc 的每堆隔离不仅是技术创新,更是移动安全架构的典范。(字数:1024)