本节不具规范性。它描述了在 Web 上公开此 API 所涉及的风险。
2.1. 安全考虑
WebGPU 的安全要求与 Web 上的其他内容相同,也是不可协商的。一般的方法是在 GPU 之前严格验证所有命令,确保页面只能使用自己的数据。
2.1.1. 基于 CPU 的未定义行为
WebGPU 实现将用户发出的工作负载转换为针对目标平台的 API 命令。本地 API 指定了命令的有效使用方法(例如,请参见 vkCreateDescriptorSetLayout),并且通常不保证如果未遵循有效使用规则将会发生什么结果。这被称为“未定义行为”,攻击者可以利用它来访问他们不拥有的内存或者强制驱动程序执行任意代码。
为了禁止不安全的使用,定义了任何输入的允许 WebGPU 行为范围。实现必须验证用户的所有输入,并仅使用有效的工作负载到达驱动程序。本文档指定了所有错误条件和处理语义。例如,在 copyBufferToBuffer()的“源”和“目标”中同时指定相交范围的同一缓冲区会导致 GPUCommandEncoder 生成一个错误,不会发生任何其他操作。 有关错误处理的更多信息,请参见 § 22 错误和调试。
2.1.2. 基于 GPU 的未定义行为
WebGPU 着色器是由 GPU 硬件内部的计算单元执行的。在本地 API 中,一些着色器指令可能会在 GPU 上导致未定义行为。为了解决这个问题,WebGPU 严格定义了着色器指令集及其定义的行为。当提供一个着色器给 createShaderModule() 函数时,WebGPU 实现必须在进行任何翻译(转换为特定平台的着色器)或转换 passes 之前验证它。
2.1.3. 未初始化数据
通常,分配新的内存可能会暴露在系统上运行的其他应用程序的剩余数据。为了解决这个问题,WebGPU 概念上将所有资源初始化为零,尽管实际上如果实现看到开发者手动初始化内容,它可以跳过此步骤。这包括着色器内的变量和共享工作组内存。
清除工作组内存的精确机制可能因平台而异。如果本地 API 不提供清除功能,则 WebGPU 实现会将计算着色器转换为首先在所有调用之间进行清除,进行同步,然后继续执行开发者的代码。
注意:队列操作中使用的资源的初始化状态只能在操作排队时知道(例如,而不是编码到命令缓冲区时)。因此,一些实现将需要在排队时进行未优化的延迟清除(例如,清除纹理,而不是将 GPULoadOp“load”更改为“clear”)。 因此,所有实现都应该发出开发者控制台警告,说明这种潜在的性能损失,即使在该实现中没有这种损失。
2.1.4. 着色器中的越界访问
着色器可以直接访问物理资源(例如作为“uniform”GPUBufferBinding),也可以通过纹理单元访问,纹理单元是处理纹理坐标转换的固定功能硬件块。WebGPU API 中的验证只能保证为着色器提供了所有输入,并且它们具有正确的使用和类型。如果纹理单元未涉及,则 WebGPU API 不能保证数据在范围内访问。
为了防止着色器访问应用程序未拥有的 GPU 存储器,WebGPU 实现可以在驱动程序中启用一个特殊模式(称为“稳健的缓冲区访问”),保证访问仅限于缓冲区边界。
或者,实现可以通过插入手动边界检查来转换着色器代码。当采取此路径时,越界检查仅适用于数组索引。对于着色器结构的简单字段访问不需要进行越界检查,因为主机端进行了 minBindingSize 验证。 如果着色器尝试加载超出物理资源边界之外的数据,则实现可以:
- 返回资源边界内的其他位置的值
- 返回值向量“(0,0,0,X)”和任何“X”
- 部分丢弃绘制或分派调用
如果着色器尝试在物理资源边界之外写入数据,则实现可以:
- 将值写入资源边界内的其他位置
- discard写操作
- 部分丢弃绘制或分派调用
2.1.5. 无效数据
当从CPU上传浮点数据到GPU,或在GPU上生成时,我们可能会得到一个不对应于有效数字的二进制表示,如无穷大或NaN(不是数字)。在这种情况下,GPU的行为取决于GPU硬件实现IEEE-754标准的准确性。WebGPU保证引入无效的浮点数只会影响算术计算的结果,并且不会有其他副作用。
2.1.6. 驱动错误
GPU 驱动程序可能会出现与任何其他软件一样的错误。如果出现错误,攻击者可能会利用驱动程序的不正确行为来访问未经特权的数据。为了减少风险,WebGPU 工作组将与 GPU 供应商协调,将 WebGPU 符合性测试套件 (CTS) 集成到他们的驱动程序测试流程中,就像在 WebGL 中一样。预期 WebGPU 实现将针对发现的一些错误有一些解决方案,并禁用已知存在不能解决的错误的驱动程序的 WebGPU。
2.1.7. 时间攻击
WebGPU 的设计旨在通过 Web Workers 支持多线程使用。因此,它的设计不会使用户面临现代高精度的时间攻击。一些对象,如 GPUBuffer 或 GPUQueue,具有共享状态,可以同时访问。这使得类似于从多个 Web Workers 访问 SharedArrayBuffer 时发生的竞争条件发生,从而使线程调度可观察。 WebGPU 通过仅将对象反序列化(或共享)限制在代理集群内部的代理以及仅在存在跨源隔离策略的情况下才能共享来解决这个问题。此限制与防范恶意使用 SharedArrayBuffer 的措施相匹配。同样,用户代理也可以序列化共享任何句柄的代理,以完全防止任何并发性。 最终,在 WebGPU 中共享状态的竞争攻击面将是 SharedArrayBuffer 攻击的一个小子集。 WebGPU 还规定了“timestamp-query”功能,它提供了GPU操作的高精度定时。该功能是可选的,WebGPU 实现可以仅将其暴露给受信任的情况。或者,时间戳查询结果可以由计算着色器处理并对齐到更低的精度。
2.1.8. Row hammer 攻击
行哈密尔顿攻击是一类利用DRAM单元中状态泄露的攻击,也可以用于GPU。WebGPU没有任何特定的缓解措施,依靠平台级别的解决方案,如减少内存刷新间隔。
2.1.9. 拒绝服务攻击
WebGPU 应用程序可以访问GPU内存和计算单元。WebGPU实现可以限制应用程序可用的GPU内存,以保持其他应用程序的响应性。对于GPU处理时间,WebGPU实现可以设置“看门狗”计时器,确保应用程序不会导致GPU超过几秒钟无响应。这些措施类似于WebGL中使用的措施。
2.1.10. 工作负载识别
WebGPU 提供了对在同一台机器上运行的不同程序(和网页)之间共享的受限全局资源的访问。一个应用程序可以间接地探测这些共享资源的受限程度,以推断出其他打开的网页执行的工作负载,基于这些共享资源的使用模式。这些问题通常类似于 Javascript 的问题,如系统内存和 CPU 执行吞吐量。WebGPU 不提供任何额外的缓解措施。
2.1.11. 内存资源
WebGPU 公开了来自机器全局内存堆的易失性分配,如 VRAM。这允许通过尝试分配并观察分配失败来探测系统剩余可用内存的大小(对于给定的堆类型)。 GPU 内部有一个或多个(通常只有两个)堆,由所有运行的应用程序共享。当一个堆用尽时,WebGPU 将无法创建资源。这是可观察到的,这可能允许恶意应用程序猜测其他应用程序使用的堆以及它们从中分配了多少。
2.1.12. 计算资源
如果一个站点同时使用 WebGPU 和另一个站点,它可能会观察到处理某些工作所需的时间增加。例如,如果一个站点不断提交计算工作负载并跟踪队列上的工作完成情况,它可能会观察到其他应用程序也开始使用 GPU。 GPU 有许多部件可以独立测试,如算术单元、纹理采样单元、原子单元等。一个恶意应用程序可以感知到一些这些部件何时受到压力,并尝试通过分析压力模式来猜测另一个应用程序的工作负载。这类似于 Javascript 执行 CPU 的现实。
2.1.13. 滥用能力
恶意站点可以滥用WebGPU公开的功能来运行不利于用户或用户体验的计算,只为了让该站点受益。例如,隐藏的加密货币挖掘、密码破解或彩虹表计算等。 无法防范这些类型的API滥用,因为浏览器无法区分有效工作负载和滥用工作负载。这是Web上所有通用计算能力的一般问题:JavaScript、WebAssembly或WebGL。WebGPU只是使某些工作负载更容易实现,或比使用WebGL运行时略微更高效。 为了缓解这种滥用,浏览器可以限制哪些上下文可以使用WebGPU,可以对后台标签上的操作进行限制,并警告某个标签正在使用大量资源。 用户代理可以使用启发式警告用户高功率使用,特别是由于潜在的恶意使用。如果用户代理实现了这样的警告,它应该将WebGPU使用包括在启发式中,除了JavaScript、WebAssembly、WebGL等。
2.2. 隐私方面的考虑
WebGPU 的隐私方面的考虑与 WebGL 类似。GPU API 是复杂的,必须出于必要性而公开设备的各种功能,以使开发人员能够有效地利用这些功能。一般的缓解方法包括规范化或分组可能识别信息,并在可能的情况下强制实施统一行为。 用户代理不得透露超过 32 个可区分的配置或桶。
2.2.1. 机器特定的功能和限制
WebGPU 可以公开底层 GPU 架构和设备几何的许多详细信息。这包括可用的物理适配器,可以使用的 GPU 和 CPU 资源的许多限制(例如最大纹理大小),以及可用的任何可选硬件特定功能。 用户代理不必公开真实的硬件限制,它们完全控制着机器细节的公开程度。减少指纹识别的一种策略是将所有目标平台分为几个箱子。总的来说,公开硬件限制的隐私影响与 WebGL 相同。 默认限制也故意设得足够高,以便大多数应用程序无需请求更高的限制即可工作。所有 API 的使用都根据请求的限制进行验证,因此实际的硬件功能不会意外地暴露给用
2.2.2. 机器特定的痕迹
有一些机器特定的光栅化/精度痕迹和性能差异,可以通过大致相同的方式观察,就像在WebGL中一样。这适用于光栅化覆盖和模式、着色器阶段之间的变量插值精度、计算单元调度和执行的更多方面。 一般来说,光栅化和精度指纹在每个供应商的大多数或所有设备上都是相同的。性能差异相对难以解决,但也相对低信号(就像JS执行性能一样)。 对于隐私关键应用程序和用户代理,应该使用软件实现来消除这些痕迹。
2.2.3. 机器特定的性能
另一个区分用户的因素是测量GPU上特定操作的性能。即使使用低精度计时,重复执行操作也可以显示出用户的机器在特定工作负载上的速度。这是一个相当常见的向量(在WebGL和Javascript中都存在),但它也是低信号和相对难以真正归一化的。 WebGPU计算管道公开了对GPU的无障碍访问,这增加了唯一设备指纹识别的风险。用户代理可以采取措施将逻辑GPU调用与实际计算单元分离,以减少这种风险。
2.2.4. 用户代理状态
本规范没有为来源定义任何额外的用户代理状态。但是,预计用户代理将具有编译缓存,用于存储 GPUShaderModule、GPURenderPipeline 和 GPUComputePipeline 的昂贵编译结果。这些缓存对于提高 WebGPU 应用程序在首次访问后的加载时间非常重要。 对于规范来说,这些缓存与非常快速的编译无异,但对于应用程序来说,衡量 createComputePipelineAsync() 所需的时间是很容易的。这可能会跨来源泄露信息(例如“用户是否访问了具有特定着色器的站点”),因此用户代理应遵循存储分区的最佳实践。 系统的 GPU 驱动程序也可能具有自己的编译着色器和管道的缓存。用户代理可能希望在尽可能的情况下禁用这些缓存,或者以使 GPU 驱动程序认为它们不同的方式添加每个分区数据到着色器中。
2.2.5. 驱动程序错误
除了安全考虑中概述的问题外,驱动程序错误可能会引入行为差异,这些差异可以作为区分用户的方法。在此处也适用于安全考虑中提到的缓解措施,包括与 GPU 供应商协调并在用户代理中实现已知问题的解决方案。
2.2.6. 适配器标识符
以往关于 WebGL 的经验表明,开发人员有合法的需要能够识别其代码运行的 GPU,以创建和维护强大的基于 GPU 的内容。例如,为了识别已知的驱动程序错误并解决它们,或避免在给定硬件类别上表现比预期更差的功能。 但是,公开适配器标识符也自然地扩大了可用的指纹信息量,因此有必要限制标识适配器的精度。 有几个缓解措施可以应用于在启用强大的内容和保护隐私之间达到平衡。首先,用户代理可以通过识别和解决已知的驱动程序问题来减轻开发人员的负担,就像自从浏览器开始使用 GPU 以来一样。 默认情况下公开适配器标识符时,应尽可能地广泛,同时仍然有用。例如,可能会识别适配器的供应商和一般体系结构,而不是识别正在使用的特定适配器。同样,在某些情况下,可能会报告被认为是实际适配器的合理代理的适配器标识符。 在某些情况下,当详细信息有用时(例如:提交错误报告时),可以要求用户同意向页面公开有关其硬件的附加信息。 最后,用户代理始终有权酌情决定不报告适配器标识符,如果认为适当的话,例如在增强隐私模式下。