云计算百科
云计算领域专业知识百科平台

ESP32 WebAssembly 小应用权限模型:Manifest、API 检查与资源配额

摘要

在 ESP32 上运行可独立安装的 WebAssembly 小应用时,只把 display、touch、storage 写进 Manifest,并不能自动形成安全边界。权限声明必须由应用包签名保护,并在安装校验、WASM 加载、事件分发和每一次系统 API 调用中真正执行。

本文介绍 ESP Mini App Platform 当前权限模型的实现思路,包括导入限制、显示与触摸权限检查、应用独立 NVS 数据空间、指令和绘图配额,以及这套原型目前仍然存在的边界。

1. 为什么 ESP32 小应用也需要权限

权限并不只是为了防范恶意程序。在微控制器上,更常见的风险是普通代码错误:

  • 坐标计算错误,绘图越过应用画布;
  • 错误的内存偏移被传给原生函数;
  • 死循环或过长计算持续占用 CPU;
  • 高频写入不断消耗 Flash 擦写寿命;
  • 一个应用访问了另一个应用的数据。

当系统首页、触摸驱动、网络、存储和多个应用共用同一颗 MCU 时,一个应用失控就可能拖累整台设备。

因此,这个平台把限制分成两类:

  • 权限:决定应用能否使用某项能力。
  • 配额:决定它最多能消耗多少资源。
  • 可以把核心判断概括为:权限回答“能不能做”,配额回答“最多能做多少”。

    2. Manifest 是权限申请表,不是执行器

    当前应用包可以声明三种权限:

    {
    "permissions": ["display", "touch", "storage"]
    }

    • display:使用清屏、矩形和文字绘制 API;
    • touch:接收平台分发的触摸释放事件;
    • storage:访问该应用自己的键值数据空间。

    Manifest 会与 WASM 一起打进 .app,Manifest 本身由 P-256 ECDSA 私钥签名。权限列表因此也属于签名内容,包生成以后不能在不破坏签名的情况下增加权限。

    设备安装时还会检查权限数组:未知权限、重复权限和不支持的字段都会被拒绝。不过,这一步只证明“申请表有效”。真正的执行仍然要落在平台代码中。

    3. 权限模型的整体结构

    当前链路可以表示为:

    签名 .app

    验证 Manifest 与 permissions

    检查 WASM 导入、内存和入口约束

    启动 WAMR 实例

    事件分发与每一次系统 API 调用再次检查权限

    检查参数、地址、坐标和资源配额

    权限不是集中在一个函数里完成的,而是贯穿应用包、加载器、Runtime、系统 API 和存储后端。

    4. 第一层限制:只公开最小系统 API

    普通 ESP-IDF 程序可以直接调用 GPIO、I²C、SPI、文件系统和网络接口。当前 WASM ABI v1 不把这些原生能力直接交给应用。

    应用只能导入平台注册的函数:

    clear
    rect
    text
    millis
    kv_get
    kv_set

    平台不开放 WASI、线程、原生 GPIO、LVGL 对象、驱动句柄和原生地址。WASM 模块的 Import Section 目前只允许函数导入;导入内存、表、全局变量或未知函数都会在加载阶段失败。

    这种做法的重点不是接口少,而是让所有硬件交互都经过可检查的入口。

    5. 第二层限制:每一次调用都检查权限

    5.1 显示权限

    绘图 API 调用前先检查 PERM_DISPLAY,同时统计本次入口已经使用的绘图次数:

    static bool allowed(wasm_exec_env_t env) {
    if (!(permissions & PERM_DISPLAY) || ++draw_calls > 96) {
    wasm_runtime_set_exception(
    wasm_runtime_get_module_inst(env),
    "display permission/quota exceeded"
    );
    return false;
    }
    return true;
    }

    即使拥有显示权限,参数也必须继续校验:

    • rect 的坐标和尺寸不能越过 480×400 应用画布;
    • text 最多接收 160 字节;
    • 文本偏移和长度必须落在当前 WASM 实例的线性内存中;
    • 检查通过后,平台才把文本复制到受控缓冲区。

    5.2 触摸权限

    应用不能直接读取触摸控制器。触摸先由系统读取,再由 Runtime 决定是否分发事件:

    if (state != APP_RUNNING ||
    (event == 2 && !(permissions & PERM_TOUCH))) {
    return;
    }

    其中事件 2 表示触摸释放。没有 touch 权限时,坐标不会进入应用的 app_event()。

    5.3 存储权限

    只有声明 storage 的应用,启动时才会打开自己的 NVS 句柄。kv_get 和 kv_set 的入口也会再次检查权限:

    if (!(permissions & PERM_STORAGE) || !data_handle) {
    wasm_runtime_set_exception(instance,
    "storage permission denied");
    return 1;
    }

    每个应用的数据空间由应用 ID 映射为独立 NVS namespace,并额外保存原始 ID 校验归属。如果发生命名空间映射冲突,平台会拒绝打开,而不会交出另一个应用的数据。

    存储接口不接受任意文件路径,只接受受限键名和位于 WASM 线性内存中的缓冲区。

    6. 资源配额:有权限也不能无限使用

    当前版本设置了以下边界:

    资源当前限制目的
    WASM 指令 每次 app_init() 或 app_event() 最多 50000 条 避免单次回调长期占用 CPU
    绘图调用 每次入口最多 96 次 避免无限提交绘制请求
    线性内存 最多 4 页,即 256 KiB 限制单应用内存占用
    文本参数 最多 160 字节 限制原生缓冲区使用
    单个存储值 最多 128 字节 限制数据规模
    键数量 每个应用最多 8 个 防止耗尽 NVS 条目
    写入频率 整个 Runtime 每秒最多 4 次有效写入 控制 Flash 写入压力

    相同内容的重复写入不会真正落盘。NVS 剩余条目少于安全阈值时,平台也会拒绝应用继续写入,为系统数据保留空间。

    如果 WASM 超过指令预算,WAMR 会终止执行;如果出现越界地址、未授权调用或无效参数,平台会设置异常并停止当前应用,随后释放模块实例、执行环境和数据句柄。

    7. Snake 应用中的实际调用链

    Snake 同时声明了 display、touch 和 storage,可以覆盖完整链路:

  • 启动时通过显示 API 绘制蛇身、食物和分数;
  • 平台检查显示权限、坐标和绘图次数;
  • 用户触摸后,系统读取坐标并确认触摸权限;
  • Runtime 把触摸释放事件交给 app_event();
  • 最高分变化时,Snake 调用 kv_set("best", …);
  • 平台检查存储权限、键名、地址、长度、键数量和写入额度;
  • 数据写入 Snake 自己的 NVS namespace。
  • 如果从 Manifest 中移除 storage,但程序仍然调用 kv_set,设备会产生 storage permission denied 异常。函数被编译进 WASM,并不代表应用能够绕过权限声明。

    8. WASM 隔离与系统 API 边界的关系

    WASM 线性内存让应用不能像原生 C 程序那样随意构造地址访问系统内存,WAMR 提供模块加载、实例化和异常机制。

    但 WASM 本身不知道画布尺寸,也不知道 Flash 的写入寿命。宿主一旦开放某项能力,它的具体边界仍由系统 API 决定。

    WASM / WAMR:隔离代码与线性内存
    系统 API:检查权限、参数、资源配额和硬件访问

    两层需要同时存在。只使用 WASM 而没有受限宿主 API,仍可能把危险能力直接暴露给应用;只有 API 检查而没有内存隔离,又很难安全接收应用传来的地址。

    9. 当前实现边界

    这套权限模型仍处于工程原型阶段:

    • 当前只有 display、touch 和 storage;
    • 网络、GPIO、I²C、SPI、音频和传感器没有直接开放给应用;
    • 权限在构建阶段写入 Manifest,设备暂时没有首次调用弹窗、动态授权和单项撤销;
    • 当前机制依赖签名包、WAMR、加载策略、API 检查和配额共同工作;
    • 它不能简单等同于桌面或手机操作系统的进程沙箱。

    当前思路是先把每一种能力的入口和限制做清楚,再根据真实应用需求扩展权限,而不是先列出大量没有实际执行逻辑的权限名称。

    10. 总结

    一个可执行的权限模型至少需要四个部分:

  • 权限声明被应用包签名保护;
  • 加载阶段只允许受控导入和内存结构;
  • 每次 API 调用和事件分发都检查权限;
  • 对指令、绘图、内存和存储继续设置配额。
  • Manifest 负责描述,平台负责执行。只有两者连起来,permissions 才不是一段展示文字。

    下一篇将继续讨论独立存储:多个应用共用一块 Flash 时,如何使用应用 ID、NVS namespace、键数量和写入额度避免数据互相覆盖。

    标签

    ESP32 WebAssembly WAMR 嵌入式开发 权限模型 系统API Manifest NVS 软件架构 物联网

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » ESP32 WebAssembly 小应用权限模型:Manifest、API 检查与资源配额
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!