摘要:本文系统讲解 BSP(板级支持包)的安全体系与 SBOM(软件物料清单)实践。文章从 BSP 安全整体认识出发,说明 BSP 安全不是简单的安全宏,而是覆盖 Source、Build、Runtime 的完整链路;随后深入介绍 SBOM 的定义、价值与常见格式(SPDX/CycloneDX),强调 BSP 因生命周期长、第三方组件漏洞频发而尤其需要 SBOM 实现可追溯。文章进一步将 BSP Security 划分为 Source Security、Dependency Security、SBOM、Firmware Signing、Debug Port 防护、Security Profile 等层次,并给出 Security CI Pipeline 与安全事件响应流程,最终串联前 42~46 篇内容,勾勒出公司级 BSP Engineering System 的完整蓝图。BSP Security / SBOM前面已经把BSP 的架构、Driver、Board、HAL、CI/CD、HIL、Regression、Version/Release串起来了。到了这一篇,需要再加上一层:你的 BSP 到底"带了什么东西"?这些东西有没有安全问题?发布出去以后,出了漏洞能不能快速知道影响了哪些版本?这就是BSP Security + SBOM(Software Bill of Materials,软件物料清单)。一、先建立整体认识一个公司的 BSP 并不只是你自己写的代码。例如:Company BSP │ ├── Zephyr │ ├── Company SoC HAL │ ├── CMSIS │ ├── Vendor SDK │ ├── Device Drivers │ ├── Middleware │ ├── USB │ ├── BLE │ ├── TCP/IP │ ├── TLS │ └── File System │ ├── Bootloader │ ├── Toolchain │ └── Third-party libraries因此最终产品实际上是:Application │ ▼ Zephyr │ ▼ Company BSP │ ├── HAL ├── Drivers ├── Middleware ├── Libraries └── Bootloader │ ▼ Firmware安全问题可能出现在任何一层。所以:BSP Security 不是"给代码加几个安全宏"。而是要建立:Source ↓ Dependency ↓ Build ↓ Firmware ↓ Release ↓ Security tracking ↓ Vulnerability response完整链路。二、什么是 SBOM?SBOM 可以简单理解成:这个 Firmware 是由哪些软件组件组成的?例如你的 BSP Release:company-bsp-2.3.0对应的 SBOM 可能描述:Firmware │ ├── Zephyr4.2.0├── Company HAL1.8.2├── CMSIS6.x ├── mbedTLS3.x ├── LittleFS2.x ├── lwIP x.x └── Bootloader1.4.0进一步还应该记录:component version supplier license source commit dependency例如:zephyr version=4.2.0source=github.com/zephyrproject-rtos/zephyr commit=abc123... license=Apache-2.0这样以后出现漏洞:CVE-XXXX-YYYY │ ▼ affected component │ ▼ mbedTLS │ ▼ 哪些 BSP Release 使用了这个版本? │ ├── BSP1.8├── BSP2.0└── BSP2.3实战:用 syft 生成 CycloneDX 格式的 SBOM下面用一个真实可运行的例子,演示如何用 syft 对 Zephyr 构建产物生成cyclonedx-json格式的 SBOM。先安装 syft:# macOS / Linuxcurl-sSfLhttps://raw.githubusercontent.com/anchore/syft/main/install.sh|sh-s---b/usr/local/bin# 或使用 Homebrewbrewinstallsyft对 Zephyr 构建产物(这里以build/zephyr/zephyr.elf为例)生成 CycloneDX JSON 格式的 SBOM:syft build/zephyr/zephyr.elf-ocyclonedx-jsonfirmware.cdx.json生成的关键输出片段如下(已截取核心字段并加注释):{"bomFormat":"CycloneDX",// 格式标识:CycloneDX"specVersion":"1.5",// CycloneDX 规范版本"serialNumber":"urn:uuid:3f2a...",// 该 SBOM 的唯一序列号(UUID)"version":1,// SBOM 文档版本号,每次更新递增"metadata":{"timestamp":"2026-09-24T10:30:00Z",// 生成时间(UTC)"tools":[{"vendor":"anchore",// 生成工具厂商"name":"syft",// 生成工具名称"version":"1.14.0"// 生成工具版本}],"component":{"type":"application",// 组件类型:应用/固件"name":"zephyr.elf",// 被扫描的构建产物名称"version":"2.4.0"// BSP 版本号}},"components":[{"type":"library",// 组件类型:库"bom-ref":"pkg:github/zephyrproject-rtos/zephyr@4.2.0",// 组件唯一引用(包 URL)"name":"zephyr",// 组件名称"version":"4.2.0",// 组件版本"purl":"pkg:github/zephyrproject-rtos/zephyr@4.2.0",// 包 URL,用于跨工具识别"licenses":[{"license":{"id":"Apache-2.0"// SPDX 许可证标识}}],"externalReferences":[{"type":"vcs",// 引用类型:版本控制系统"url":"https://github.com/zephyrproject-rtos/zephyr"// 源码仓库地址}]},{"type":"library","bom-ref":"pkg:github/ARMmbed/mbedtls@3.6.0","name":"mbedtls",// TLS 库组件"version":"3.6.0","purl":"pkg:github/ARMmbed/mbedtls@3.6.0","licenses":[{"license":{"id":"Apache-2.0"}}]}],"dependencies":[{"ref":"pkg:github/zephyrproject-rtos/zephyr@4.2.0",// 依赖方"dependsOn":["pkg:github/ARMmbed/mbedtls@3.6.0"// 被依赖的组件]}]}字段含义速查:bomFormat/specVersion:声明这是 CycloneDX 格式及规范版本,便于下游工具解析。serialNumber:每个 SBOM 的唯一 ID,用于区分不同构建产物的 SBOM。metadata.component:描述这份 SBOM 描述的对象(这里是zephyr.elf固件)。components:固件中包含的每个软件组件,记录名称、版本、许可证、源码地址。purl(Package URL):组件的标准化标识,让漏洞数据库(如 OSV、NVD)能自动匹配 CVE。dependencies:组件之间的依赖关系,用于回答"哪个组件依赖了哪个库"。生成后可以配合漏洞扫描工具(如 Grype)做 CVE 匹配。先安装 Grype:# macOS / Linuxcurl-sSfLhttps://raw.githubusercontent.com/anchore/grype/main/install.sh|sh-s---b/usr/local/bin# 或使用 Homebrewbrewinstallgrype对刚才生成的firmware.cdx.json做漏洞扫描:grype firmware.cdx.json也可以直接扫描固件产物本身(Grype 会自动识别并生成 SBOM 再匹配 CVE):grype build/zephyr/zephyr.elf扫描结果输出如下(已截取核心字段并加注释):NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY mbedtls 3.6.0 3.6.1 library CVE-2027-4821 Critical zephyr 4.2.0 (won't fix) library CVE-2027-1133 High littlefs 2.9.0 2.10.0 library CVE-2027-2044 Medium lwip 2.2.0 (won't fix) library CVE-2027-3310 Low关键字段含义:NAME:存在漏洞的软件组件名称(对应 SBOM 中的components[].name)。INSTALLED:当前 BSP 中锁定的组件版本(对应 SBOM 中的version)。FIXED-IN:修复该漏洞所需升级到的版本;若显示(won't fix),表示上游暂无修复版本,需通过配置缓解或替换组件。TYPE:组件类型(library / application 等),与 SBOM 中的type字段对应。VULNERABILITY:漏洞编号(CVE ID),Grype 通过 SBOM 中的purl自动匹配 OSV / NVD 漏洞数据库。SEVERITY:漏洞严重等级(Critical / High / Medium / Low),基于 CVSS 评分。如何把 SBOM 与漏洞扫描串联起来:syft 生成 SBOM │ ▼ firmware.cdx.json │ ▼ grype 扫描 │ ▼ CVE 报告 │ ▼ 定位受影响 BSP Release实战:完整的自动化脚本(SBOM 生成 + 漏洞扫描 + CVE 报告)下面用一个完整的 Bash 脚本,把「生成 SBOM → 扫描漏洞 → 输出 CVE 报告」全流程自动化。脚本包含错误处理、参数校验和详细注释,可直接放进 CI 或本地使用。#!/usr/bin/env bash## generate_sbom_and_scan.sh## 功能:对 Zephyr 构建产物生成 CycloneDX 格式 SBOM,并用 Grype 扫描漏洞,# 最终输出一份 CVE 报告(文本 + JSON 两种格式)。## 用法:# ./generate_sbom_and_scan.sh [构建产物路径] [BSP版本号]## 示例:# ./generate_sbom_and_scan.sh build/zephyr/zephyr.elf 2.4.0## 依赖:# - syft (SBOM 生成工具)# - grype (漏洞扫描工具)# - jq (JSON 解析工具,用于生成报告)set-euopipefail# 出错即停、未定义变量报错、管道失败即停# ---------- 1. 参数解析与校验 ----------# 默认值ARTIFACT="${1:-build/zephyr/zephyr.elf}"# 构建产物路径(可覆盖)BSP_VERSION="${2:-2.4.0}"# BSP 版本号(可覆盖)OUTPUT_DIR="security_output"# 输出目录# 检查构建产物是否存在if[!-f"$ARTIFACT"];thenecho"❌ 错误:构建产物不存在:$ARTIFACT"echo" 请先构建 Zephyr,或通过参数指定正确的产物路径。"exit1fi# 检查必需工具是否安装fortoolinsyft grype jq;doif!command-v"$tool"/dev/null21;thenecho"❌ 错误:未找到工具 '$tool',请先安装。"echo" syft: curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin"echo" grype: curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin"echo" jq: brew install jq (或 apt install jq)"exit1fidone# ---------- 2. 创建输出目录 ----------mkdir-p"$OUTPUT_DIR"echo"📁 输出目录:$OUTPUT_DIR"# ---------- 3. 生成 SBOM ----------SBOM_FILE="$OUTPUT_DIR/firmware.cdx.json"echo"🔍 步骤 1/4:用 syft 生成 CycloneDX 格式 SBOM..."# 生成 CycloneDX JSON 格式的 SBOM# 注意:如果 syft 失败,脚本会因 set -e 立即退出if!syft"$ARTIFACT"-ocyclonedx-json"$SBOM_FILE";thenecho"❌ 错误:syft 生成 SBOM 失败。"exit1fi# 校验 SBOM 是否为合法 JSONif!jq empty"$SBOM_FILE"2/dev/null;thenecho"❌ 错误:生成的 SBOM 不是合法 JSON,请检查 syft 输出。"exit1fiecho"✅ SBOM 已生成:$SBOM_FILE"echo" 组件数量:$(jq'.components | length'"$SBOM_FILE")"# ---------- 4. 用 Grype 扫描漏洞 ----------SCAN_TEXT="$OUTPUT_DIR/cve-report.txt"SCAN_JSON="$OUTPUT_DIR/cve-report.json"echo"🔍 步骤 2/4:用 Grype 扫描漏洞..."# 对 SBOM 文件做漏洞扫描,输出文本格式报告# --fail-on 参数:可设置阈值,例如 --fail-on high 表示存在 high 及以上漏洞时返回非零退出码if!grype"$SBOM_FILE"-otable"$SCAN_TEXT";thenecho"⚠️ Grype 扫描完成,但发现达到阈值的漏洞(详见报告)。"elseecho"✅ Grype 扫描完成,未发现达到阈值的漏洞。"fi# 同时输出 JSON 格式,便于后续程序化处理grype"$SBOM_FILE"-ojson"$SCAN_JSON"2/dev/null||trueecho"✅ 漏洞报告已生成:"echo" - 文本格式:$SCAN_TEXT"echo" - JSON 格式:$SCAN_JSON"# ---------- 5. 统计漏洞并生成汇总 ----------echo"🔍 步骤 3/4:统计漏洞严重等级..."# 用 jq 统计各严重等级的漏洞数量CRITICAL=$(jq'[.matches[] | select(.vulnerability.severity == "Critical")] | length'"$SCAN_JSON"2/dev/null||echo0)HIGH=$(jq'[.matches[] | select(.vulnerability.severity == "High")] | length'"$SCAN_JSON"2/dev/null||echo0)MEDIUM=$(jq'[.matches[] | select(.vulnerability.severity == "Medium")] | length'"$SCAN_JSON"2/dev/null||echo0)LOW=$(jq'[.matches[] | select(.vulnerability.severity == "Low")] | length'"$SCAN_JSON"2/dev/null||echo0)echo"📊 漏洞统计:"echo" Critical:$CRITICAL"echo" High:$HIGH"echo" Medium:$MEDIUM"echo" Low:$LOW"# ---------- 6. 生成汇总报告 ----------SUMMARY_FILE="$OUTPUT_DIR/summary.txt"echo"🔍 步骤 4/4:生成汇总报告..."cat"$SUMMARY_FILE"EOF ======================================== BSP Security 扫描汇总报告 ======================================== 构建产物 :$ARTIFACTBSP 版本 :$BSP_VERSION生成时间 :$(date-u+"%Y-%m-%dT%H:%M:%SZ")SBOM 文件 :$SBOM_FILESBOM 格式 : CycloneDX$(jq-r'.specVersion'"$SBOM_FILE")组件数量 :$(jq'.components | length'"$SBOM_FILE")漏洞统计: Critical :$CRITICALHigh :$HIGHMedium :$MEDIUMLow :$LOW合计 :$((CRITICAL+HIGH+MEDIUM+LOW))======================================== 高风险漏洞明细(Critical / High) ======================================== EOF# 提取 Critical 和 High 级别的漏洞明细jq-r'.matches[] | select(.vulnerability.severity == "Critical" or .vulnerability.severity == "High") | "\(.vulnerability.id) | \(.vulnerability.severity) | \(.artifact.name) \(.artifact.version) | 修复版本: \(.vulnerability.fix.versions // "无")"'"$SCAN_JSON"2/dev/null"$SUMMARY_FILE"||echo"(无高风险漏洞)""$SUMMARY_FILE"echo"✅ 汇总报告已生成:$SUMMARY_FILE"# ---------- 7. 输出最终结果 ----------echo""echo"========================================"echo" 🎉 全流程完成!输出文件如下:"echo"========================================"ls-lh"$OUTPUT_DIR"
阅读完成 · 觉得有帮助?