历史快照:本文记录当时布局;现行 rootfs 路径见
docs/ROOTFS_LAYOUT_AND_MIGRATION.md。
安全审计报告:LeonOS 4
范围
本次是一次标准源码安全审计,重点关注 LeonOS 的 kernel、middlelayer、文件系统 ACL/认证、网络、installer/update、loader 完整性,以及 GUI/window 信任边界。
- 扫描模式:repository
- 目标类型:git_revision
- 目标 ID:target_sha256_c9ce7b7efe8039b8499cc5fa37622a227599978aa656347d6d67d7c6a1718fd7
- Revision:e6a051315ed13903da8a633dfa9ed00683113ec0
- 清单策略:custom
- 包含路径:.
- 排除路径:无
- 运行或测试状态:仅做源码审计;未执行 QEMU 或运行时 exploit smoke 测试。
- 已审计产物:kernel/ntclks/syscall.c、kernel/ntclks/gui_ipc.c、kernel/ntclks/net.c、include/leonos/net.h、kernel/ntclks/user/userland.c、kernel/ntclks/sched/sched.c、middlelayer/osmlayer/runtime.c、tools/gen_loader_integrity.py、boot/loader/main.c、docs/FILESYSTEM.md
- 扫描上下文:用户请求使用 Codex Security 审计操作系统源码。
限制与排除项:
- 这不是一次覆盖整个仓库的深度穷尽扫描。
- 本报告优先列出高影响的本地信任边界问题和架构风险。
- 未执行 fuzzing、符号执行或运行时 exploit 验证。
扫描摘要
| 字段 | 值 |
|---|---|
| 可报告问题 | 6 |
| 严重性分布 | high:2,medium:4 |
| 置信度分布 | high:4,medium:2 |
| 覆盖率 | partial |
| 验证模式 | 人工源码验证,并使用 Codex Security triage 渲染结果。 |
规范产物:scan-manifest.json、findings.json 和 coverage.json。本报告是这些文件的确定性投影。
威胁模型
本地非特权 LeonOS 应用程序和普通用户不应跨越 kernel、middlelayer、GUI、文件系统或网络管理信任边界。
资产
- kernel 内存和 task 状态
- middlelayer 策略决策
- 用户账号和 ACL 数据
- 网络配置
- 桌面/window 会话状态
- 启动组件
信任边界
- 用户 task 到 kernel syscall
- kernel 到 middlelayer policy callback
- 普通应用到 desktop/window service
- 普通用户到 administrator/system service
- boot loader 到 kernel/middlelayer image
攻击者能力
- 运行普通用户态应用程序
- 调用公开 syscall/ioctl
- 打开或列出 ACL 允许的文件
- 观察普通用户可见的错误
安全目标
- 强制执行按用户和角色划分的授权
- 保护全局网络状态和 GUI 状态
- 避免跨用户元数据泄露
- 让启动完整性声明明确且准确
假设
- FAT32 ACL 元数据由 LeonOS kernel syscall 进行中介访问
- 普通用户不应获得 service/window-server task flag
- installer 模式可以有意绕过部分普通运行时策略
问题列表
| 问题 | 严重性 | 置信度 |
|---|---|---|
| 普通用户 task 可以调用 GUI/window-server ioctl | high | high |
| 任意用户进程都可以触发 DHCP 续租并修改全局网络配置 | high | high |
| Service 权限由可执行文件路径授予,而不是由可信启动权限授予 | medium | medium |
stat() 检查 Execute/Traverse,而不是 Read/List | medium | high |
| 网络连接列表暴露所有用户的 TCP socket 元数据 | medium | high |
| Loader SHA256 完整性检查不是经过认证的信任根 | medium | medium |
置信度说明
| 标签 | 含义 |
|---|---|
| high | 直接证据支持该问题,且没有实质性未解决阻塞点。 |
| medium | 证据支持该问题可能成立,但仍缺少重要的运行时或可达性证明。 |
| low | 证据不完整,该项仅保留为明确的后续跟进项。 |
<a id="finding-1"></a>
[1] 普通用户 task 可以调用 GUI/window-server ioctl
| 字段 | 值 |
|---|---|
| 严重性 | high |
| 置信度 | high |
| 置信度理由 | 已通过源码审计 syscall 或权限边界及其被调函数进行验证。 |
| 分类 | authorization-bypass |
| CWE | CWE-862、CWE-284 |
| 受影响行 | kernel/ntclks/syscall.c:1923-2058、kernel/ntclks/gui_ipc.c:381-475 |
摘要
kernel 在分发 framebuffer 绘制、window fetch、event injection 和 display publish ioctl 时,没有要求调用方必须是 desktop/window-server task。因此普通进程可以向共享屏幕路径绘制内容、耗尽或获取窗口,并跨进程边界注入窗口事件。
验证
已通过源码审计 syscall 或权限边界及其被调函数进行验证。未单独记录额外验证细节。
数据流
规范 finding 记录了受影响路径:kernel/ntclks/syscall.c:1923-2058、kernel/ntclks/gui_ipc.c:381-475,但未记录展开后的 source-to-sink 叙述。
可达性
除规范 finding 摘要和受影响位置外,未记录额外可达性证明。
严重性
High:本地非特权应用可以跨越 GUI/window 信任边界,并影响其它应用或用户会话。
额外运行时或部署证据可能提高或降低该严重性。
修复建议
将 window-service-only ioctl 放在一个统一 helper 后面进行保护,该 helper 要求 current_task 具有 TASK_FLAG_WINDOW_SERVER。同时在 gui_ipc_fetch_window 和 gui_ipc_push_event 内部也强制检查调用方权限,避免这些 callee 在其它路径中被不安全地复用。
测试:
- 启动一个普通用户应用,确认 FB/window-server-only ioctl 返回
EPERM。 - 确认 desktop/window-server 仍能正常接收、发布和分发事件。
预防性控制:
- 将 window-server-only ioctl 保持在专用 dispatch block 中,并进行显式 task flag 检查。
<a id="finding-2"></a>
[2] 任意用户进程都可以触发 DHCP 续租并修改全局网络配置
| 字段 | 值 |
|---|---|
| 严重性 | high |
| 置信度 | high |
| 置信度理由 | 已通过源码审计 syscall 或权限边界及其被调函数进行验证。 |
| 分类 | authorization-bypass |
| CWE | CWE-862、CWE-269 |
| 受影响行 | kernel/ntclks/syscall.c:2336-2340、kernel/ntclks/net.c:1248-1293、kernel/ntclks/net.c:1373-1382 |
摘要
LEONOS_IOCTL_NET_DHCP 只验证用户指针,然后就调用 net_dhcp_renew。DHCP 路径会把收到的租约直接应用到全局 net_config,因此任意用户进程都可以强制重新配置网络。
验证
已通过源码审计 syscall 或权限边界及其被调函数进行验证。未单独记录额外验证细节。
数据流
规范 finding 记录了受影响路径:kernel/ntclks/syscall.c:2336-2340、kernel/ntclks/net.c:1248-1293、kernel/ntclks/net.c:1373-1382,但未记录展开后的 source-to-sink 叙述。
可达性
除规范 finding 摘要和受影响位置外,未记录额外可达性证明。
严重性
High:本地用户可以反复修改全局网络状态,从而干扰所有用户和服务的网络。
额外运行时或部署证据可能提高或降低该严重性。
修复建议
在允许 DHCP renew 或网络配置变更前,要求调用方具有管理员权限或可信网络服务权限。将只读网络状态 ioctl 与会改变配置的操作分离。
测试:
- 确认非管理员执行 DHCP renew 返回
EPERM。 - 确认可信网络控制器或服务仍能续租 DHCP 并发布状态。
预防性控制:
- 将网络 ioctl 分类为只读操作和状态变更操作,并对后者强制策略检查。
<a id="finding-3"></a>
[3] Service 权限由可执行文件路径授予,而不是由可信启动权限授予
| 字段 | 值 |
|---|---|
| 严重性 | medium |
| 置信度 | medium |
| 置信度理由 | 已通过源码审计 syscall 或权限边界及其被调函数进行验证。 |
| 分类 | privilege-management |
| CWE | CWE-266、CWE-269 |
| 受影响行 | kernel/ntclks/user/userland.c:118-123、kernel/ntclks/user/userland.c:357-370、kernel/ntclks/sched/sched.c:229-237、middlelayer/osmlayer/runtime.c:1328-1333 |
摘要
启动精确路径 /system/apps/serviced/serviced.elf 会授予 TASK_FLAG_SERVICE,而 scheduler/middlelayer 逻辑会把 service task 视为 system-level actor。目前系统 ACL 可能保护着这个文件,但从路径相等性派生权限在 update、installer、recovery 和未来文件系统 bug 面前都比较脆弱。
验证
已通过源码审计 syscall 或权限边界及其被调函数进行验证。未单独记录额外验证细节。
数据流
规范 finding 记录了受影响路径:kernel/ntclks/user/userland.c:118-123、kernel/ntclks/user/userland.c:357-370、kernel/ntclks/sched/sched.c:229-237、middlelayer/osmlayer/runtime.c:1328-1333,但未记录展开后的 source-to-sink 叙述。
可达性
除规范 finding 摘要和受影响位置外,未记录额外可达性证明。
严重性
Medium:这是一个设计加固问题。当前 ACL 可能已经阻止直接利用,但权限来源不是稳固的信任根。
额外运行时或部署证据可能提高或降低该严重性。
修复建议
只允许 kernel init 路径或管理员控制的 service manager 创建 TASK_FLAG_SERVICE task。把可执行文件路径当作要验证的输入,而不是授予权限的来源。
测试:
- 确认用户直接执行
/system/apps/serviced/serviced.elf不会获得 service 权限。 - 确认 boot/service-manager 启动仍会授予精确预期的 service flag。
预防性控制:
- 将 service launch authority 表示为 kernel-private capability 或 launch token,而不是 basename/path 约定。
<a id="finding-4"></a>
[4] stat() 检查 Execute/Traverse,而不是 Read/List
| 字段 | 值 |
|---|---|
| 严重性 | medium |
| 置信度 | high |
| 置信度理由 | 已通过源码审计 syscall 或权限边界及其被调函数进行验证。 |
| 分类 | incorrect-authorization |
| CWE | CWE-863、CWE-200 |
| 受影响行 | kernel/ntclks/syscall.c:1637-1654、docs/FILESYSTEM.md:88-99 |
摘要
LINUX_SYS_STAT 路径在返回 storage_stat_path 结果前,使用 LEONOS_AUTHZ_EXEC 授权元数据访问。文件系统文档将 stat/metadata 读取映射到 Read/List,因此只有 traverse 权限但没有 read/list 权限的用户,也可能收到他们不应能 list/read 的元数据。
验证
已通过源码审计 syscall 或权限边界及其被调函数进行验证。未单独记录额外验证细节。
数据流
规范 finding 记录了受影响路径:kernel/ntclks/syscall.c:1637-1654、docs/FILESYSTEM.md:88-99,但未记录展开后的 source-to-sink 叙述。
可达性
除规范 finding 摘要和受影响位置外,未记录额外可达性证明。
严重性
Medium:这是一个直接的权限位不匹配 bug,会在新的 ACL 模型下泄露文件元数据。
额外运行时或部署证据可能提高或降低该严重性。
修复建议
将 stat 授权改为 LEONOS_AUTHZ_READ 或项目中等价的 Read/List 权限,同时将祖先目录 traversal 检查保留在路径解析内部并与目标对象读取权限分开。
测试:
- 创建一个用户有 traverse 但没有 read/list 的目录,确认
stat返回EACCES。 - 确认可读路径上的普通
stat仍然成功。
预防性控制:
- 为
open/read/write/stat/readdir/exec/unlink/rename增加 syscall 级权限映射测试。
<a id="finding-5"></a>
[5] 网络连接列表暴露所有用户的 TCP socket 元数据
| 字段 | 值 |
|---|---|
| 严重性 | medium |
| 置信度 | high |
| 置信度理由 | 已通过源码审计 syscall 或权限边界及其被调函数进行验证。 |
| 分类 | information-disclosure |
| CWE | CWE-200、CWE-862 |
| 受影响行 | kernel/ntclks/syscall.c:2409-2425、kernel/ntclks/net.c:2169-2200、include/leonos/net.h:146-163 |
摘要
LEONOS_IOCTL_NET_CONNECTIONS 调用 net_connections 时没有传入调用者身份或策略上下文。返回的记录包含所有 TCP socket 的 owner pid、state、endpoint、port 和 byte counter。
验证
已通过源码审计 syscall 或权限边界及其被调函数进行验证。未单独记录额外验证细节。
数据流
规范 finding 记录了受影响路径:kernel/ntclks/syscall.c:2409-2425、kernel/ntclks/net.c:2169-2200、include/leonos/net.h:146-163,但未记录展开后的 source-to-sink 叙述。
可达性
除规范 finding 摘要和受影响位置外,未记录额外可达性证明。
严重性
Medium:跨用户 socket 元数据是敏感信息,可能泄露其它用户活动和内部服务 endpoint。
额外运行时或部署证据可能提高或降低该严重性。
修复建议
将当前 uid/role/pid 传入网络连接查询。普通用户只返回自己的 socket,或者对跨用户元数据进行脱敏;管理员和可信服务可以看到完整列表。
测试:
- 确认普通用户只能看到自己的 TCP socket。
- 确认管理员在
netctl/netstat中仍能看到所有 socket。
预防性控制:
- 枚举全局资源的 API 应显式接收 actor,并执行策略决策。
<a id="finding-6"></a>
[6] Loader SHA256 完整性检查不是经过认证的信任根
| 字段 | 值 |
|---|---|
| 严重性 | medium |
| 置信度 | medium |
| 置信度理由 | 已通过源码审计 syscall 或权限边界及其被调函数进行验证。 |
| 分类 | integrity-verification |
| CWE | CWE-345、CWE-347 |
| 受影响行 | tools/gen_loader_integrity.py:19-34、boot/loader/main.c:657-703、boot/loader/main.c:1042-1128 |
摘要
构建时会把 kernel.sys 和 middlelayer.sys 的 SHA256 hash 嵌入 loader,loader 在 hash 不匹配时给出警告。但由于 loader 本身没有通过 Secure Boot 或签名链认证,并且提示允许用户按 Y 继续启动,所以该机制能检测意外漂移,却不能阻止离线攻击者替换 loader 和 boot components。
验证
已通过源码审计 syscall 或权限边界及其被调函数进行验证。未单独记录额外验证细节。
数据流
规范 finding 记录了受影响路径:tools/gen_loader_integrity.py:19-34、boot/loader/main.c:657-703、boot/loader/main.c:1042-1128,但未记录展开后的 source-to-sink 叙述。
可达性
除规范 finding 摘要和受影响位置外,未记录额外可达性证明。
严重性
Medium:这是一个架构限制,不是普通的 OS 内 exploit。SHA256 检查缺少经过认证的信任根,并且可以被显式绕过。
额外运行时或部署证据可能提高或降低该严重性。
修复建议
将当前功能记录为 tamper warning,或者增加经过认证的信任锚,例如由不可变 loader 状态验证签名后的 boot components、集成 Secure Boot,或为受保护安装提供不可绕过的策略模式。
测试:
- 篡改
kernel.sys并确认警告会出现。 - 在测试镜像中替换 loader 和 kernel,确认当前设计是否仍能检测该变化;除非有认证,否则不应把它视为安全控制。
预防性控制:
- 避免在用户文档中将未认证检查称为 secure boot 或 trusted integrity。
已审计表面
| 表面 | 风险区域 | 结果 | 说明 |
|---|---|---|---|
| GUI/window-server syscall boundary | GUI 隔离 | 已报告 | 审计了 framebuffer、window queue、display publish 和 event ioctl。 |
| Network control and status ioctls | 网络配置和元数据隔离 | 已报告 | 审计了 DHCP renew 和 connection-listing 路径。 |
| Filesystem ACL syscall permission mapping | 文件系统授权 | 已报告 | 审计了 stat 授权,并与文档中的权限映射进行了对比。 |
| Service task identity and launch privilege | 权限模型 | 需要跟进 | 审计了 service flag 赋值和 policy matching;由于当前 ACL 可能阻止直接利用,因此作为需要复核的加固项报告。 |
| Loader component hash integrity | 启动完整性 | 需要跟进 | 审计了构建时 SHA256 生成,以及启动时 warning/bypass 行为。 |
| Selected mmap/auth/install paths | 进程内存和 installer 授权 | 未发现问题 | 抽查了 mmap/munmap 用户范围处理、auth actor 覆写和 installer format/mount gate,本轮未发现可报告问题。 |
未决问题与后续跟进
- Service authority 是否应由 kernel-private launch token 或 service manager 表示,而不是由可执行文件路径表示?
- 后续提示:在重构
TASK_FLAG_SERVICE赋值前,先决定 service launch 的信任根。 - Loader hash check 目标是仅作为警告,还是作为安全边界?
- 后续提示:如果它应成为安全边界,需要设计签名或 firmware trust-anchor 流程。
- 本次是一次标准 parent-agent 扫描,重点关注高影响信任边界,不是对每个 driver、syscall、parser 或 user app 的深度穷尽审计。
- 后续提示:审计 deferred unit
deferred-exhaustive-kernel-review并关闭它记录的 proof gap。路径:kernel、middlelayer、userland、boot、tools、docs。 - 未执行 QEMU 或运行时 exploit smoke 测试;验证基于源码审计。
- 后续提示:审计 deferred unit
deferred-runtime-exploit-smoke并关闭它记录的 proof gap。路径:.