Zephyr如何生成软件物料清单

Creative Commons
本作品采用知识共享署名

本文说明如何为Zephyr生成SPDX标准的软件物料清单。

背景知识

SBOM(Software Bill of Materials)软件物料清单:包含用于构建软件的各种组件的详细信息和供应链关系的正式记录。SBOM 是描述软件包依赖树的一系列元数据,包括多种关键信息如提供商、版本号和组件名称。这些基本详情在分析软件漏洞时发挥着关键作用。实施SBOM可以增强软件供应链的可见性。SBOM可帮助软件使用者确定产品是否容易受到软件组件中已被发现的安全漏洞的影响,无论这些组件是内部开发的、商业采购的还是开源的软件库。SBOM会生成并验证有关代码出处和组件之间关系的信息,这有助于软件工程团队在开发和部署期间检测恶意攻击。

SPDX(Software Package Data Exchange) 软件包数据交换:用于交流软件材料清单信息的开放标准,包括组件、许可证、版权和安全参考. SPDX已经成为一项国际认可的SBOM标准,将以 ISO/IEC 5962:2021 的形式发布,并被公认为软件供应链工件的开放标准,其中包括许可证合规性和安全性。

以上内容简述就是:生成一张源文件和可执行文件对应的列表,包含了所有源文件的唯一标识信息,用于对软件的准确追溯。

Zephyr SPDX

SPDX标识

Zephyr所有的源文件都通过SPDX进行标识,标识方法非常简单,打开任意一个Zephyr的源文件在其注释中可以看SPDX的标识

1
SPDX-License-Identifier: Apache-2.0

本文重点不在说明SPDX的标识,详细可以参考
https://spdx.dev/ids/
https://spdx.dev/spdx-specification-21-web-version/
https://spdx.dev/licenses/

Zephyr SPDX文档生成

Zephyr的构建系统可以从源文件中扫描SPDX标识生成SPDX文档,通过下面方法进行进行生成
生成方法:

1
2
3
west spdx --init -d build/
west build -b board_name -d build/ ./sample
west spdx --build-dir=./build/

结果生成在build/spdx/下

1
2
3
4
build/spdx/
├── app.spdx
├── build.spdx
└── zephyr.spdx

app.spdx:

加入编译的应用源代码的BOM, 有Zephyr应用者控制的应用代码的SH和License,例如

1
2
3
4
5
6
7
FileName: ./src/logging_sample.c
SPDXID: SPDXRef-File-logging-sample.c
FileChecksum: SHA1: f30c16e4c6eda834cca26b57108b37289a4ac455
FileChecksum: SHA256: 109485be31738593ffb5700d3095d024403253d92f3abd691d1d4c39ea081779
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NONE
FileCopyrightText: NOASSERTION

zephyr.spdx:

加入编译的Zephyr源代码BOM,包含了Zephyr内核,驱动,子系统,使用外部模块的源代码文件的SHA和License,例如

1
2
3
4
5
6
7
FileName: ./zephyr/kernel/msg_q.c
SPDXID: SPDXRef-File-msg-q.c
FileChecksum: SHA1: aeccc6d5daa8eceda7a23d85dd49ade6ed1260a4
FileChecksum: SHA256: 498f4fdb76b71dd74cd3d610b47d131080b2aa2a25994a6efd2a5bd32e578b8b
LicenseConcluded: Apache-2.0
LicenseInfoInFile: Apache-2.0
FileCopyrightText: NOASSERTION

build.spdx:

构建输出文件的BOM, 每个.a文件会有一个Package的描述,包含了该文件的SHA值,和生成该.a文件的源文件列表,下面是Zephyr kernel的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
##### Package: kernel

PackageName: kernel
SPDXID: SPDXRef-kernel
PackageDownloadLocation: NOASSERTION
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
PackageLicenseInfoFromFiles: NOASSERTION
FilesAnalyzed: true
PackageVerificationCode: 4b7816efd192d52c4b548959aa2d360b3b79681e

Relationship: SPDXRef-kernel HAS_PREREQUISITE SPDXRef-syscall-list-h-target
Relationship: SPDXRef-kernel HAS_PREREQUISITE SPDXRef-driver-validation-h-target
Relationship: SPDXRef-kernel HAS_PREREQUISITE SPDXRef-kobj-types-h-target
Relationship: SPDXRef-kernel HAS_PREREQUISITE SPDXRef-zephyr-generated-headers

FileName: ./zephyr/kernel/libkernel.a
SPDXID: SPDXRef-File-libkernel.a
FileChecksum: SHA1: a33dca771e80a8ffe7db2fa69db4505e4bd28a1a
FileChecksum: SHA256: 504d4ad8918e82b1b43904bf8fbf7abd92dae89b968921b5e145ff4d0e844d69
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NONE
FileCopyrightText: NOASSERTION

Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-main-weak.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-banner.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-device.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-errno.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-fatal.c-2
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-init.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-kheap.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-mem-slab.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-thread.c-2
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-version.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-idle.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-mailbox.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-msg-q.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-mutex.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-pipes.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-queue.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-sem.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-stack.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-system-work-q.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-work.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-sched.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-condvar.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-xip.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-timeout.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-timer.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-atomic-c.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-poll.c
Relationship: SPDXRef-File-libkernel.a GENERATED_FROM DocumentRef-zephyr:SPDXRef-File-mempool.c

从上面的示例可知当我们发布一个Zephyr可执行镜像时,只要同时发布spdx文档,就可以根据文档的SHA和依赖关系对Zephyr的源文件进行追溯。

west spdx的附加选项

-s
指定spdx文档输出的目录,默认生成spdx文档在build/spdx下,可以用-s指定到其它目录,例如

1
west spdx --build-dir=./build/ -s ./r1.0

--analyze-includes
默认生成spdx不扫描h文件,当我们希望追踪h文件时需要加上该选项

1
west spdx --build-dir=./build/ --analyze-includes

产生的文档中会加入h文件的信息,例如

1
2
3
4
5
6
7
FileName: ./src/log_sample/sample_instance.h
SPDXID: SPDXRef-File-sample-instance.h
FileChecksum: SHA1: cf5edf1d33a2eb43fdb4946caf86dbe4e244e5bc
FileChecksum: SHA256: 6c05c9ba7748c68703b955bcf7eaa020f7cbe9ddd8f6977b829ad21a70d90688
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NONE
FileCopyrightText: NOASSERTION

构建的结果文档中也会显示对h的依赖关系,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
##### Package: app

PackageName: app
SPDXID: SPDXRef-app
PackageDownloadLocation: NOASSERTION
PackageLicenseConcluded: NOASSERTION
PackageLicenseDeclared: NOASSERTION
PackageCopyrightText: NOASSERTION
PackageLicenseInfoFromFiles: NOASSERTION
FilesAnalyzed: true
PackageVerificationCode: a40f6b54b3340f0843e1381d833cdd4a73d2a0ba

Relationship: SPDXRef-app HAS_PREREQUISITE SPDXRef-syscall-list-h-target
Relationship: SPDXRef-app HAS_PREREQUISITE SPDXRef-driver-validation-h-target
Relationship: SPDXRef-app HAS_PREREQUISITE SPDXRef-kobj-types-h-target
Relationship: SPDXRef-app HAS_PREREQUISITE SPDXRef-zephyr-generated-headers
Relationship: SPDXRef-app HAS_PREREQUISITE SPDXRef-EspPartitionTable
Relationship: SPDXRef-app HAS_PREREQUISITE SPDXRef-EspIdfBootloader

FileName: ./app/libapp.a
SPDXID: SPDXRef-File-libapp.a
FileChecksum: SHA1: 2b05a995ea52edf14433e1bc047383afdba8f442
FileChecksum: SHA256: 95a3d25fa9650755a3b743fc4b466b7f12beae638d42b1bd63954b882df92a8c
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NONE
FileCopyrightText: NOASSERTION

Relationship: SPDXRef-File-libapp.a GENERATED_FROM DocumentRef-app:SPDXRef-File-main.c
Relationship: SPDXRef-File-libapp.a GENERATED_FROM DocumentRef-app:SPDXRef-File-logging-sample.c
Relationship: SPDXRef-File-libapp.a GENERATED_FROM DocumentRef-app:SPDXRef-File-simple.c
Relationship: SPDXRef-File-libapp.a GENERATED_FROM DocumentRef-app:SPDXRef-File-simple-co.c
Relationship: SPDXRef-File-libapp.a GENERATED_FROM DocumentRef-app:SPDXRef-File-simple-header.c
Relationship: SPDXRef-File-libapp.a GENERATED_FROM DocumentRef-app:SPDXRef-File-custom-backend.c
Relationship: SPDXRef-File-libapp.a GENERATED_FROM DocumentRef-app:SPDXRef-File-sample-instance.c
Relationship: SPDXRef-File-libapp.a GENERATED_FROM DocumentRef-app:SPDXRef-File-nvs-sample.c
Relationship: SPDXRef-File-libapp.a GENERATED_FROM DocumentRef-app:SPDXRef-File-shell-sample.c
Relationship: SPDXRef-File-libapp.a GENERATED_FROM SPDXRef-File-device-extern.h
Relationship: SPDXRef-File-libapp.a GENERATED_FROM SPDXRef-File-devicetree-fixups.h
Relationship: SPDXRef-File-libapp.a GENERATED_FROM SPDXRef-File-devicetree-unfixed.h
Relationship: SPDXRef-File-libapp.a GENERATED_FROM SPDXRef-File-kobj-types-enum.h
Relationship: SPDXRef-File-libapp.a GENERATED_FROM SPDXRef-File-syscall-list.h
Relationship: SPDXRef-File-libapp.a GENERATED_FROM SPDXRef-File-atomic-c.h

...

--analyze-sdk
该选项和--analyze-sdk搭配使用,生成SPDX文档时会多生成一个sdk.spdx,里面包含了构建使用的sdk中的h文件信息

1
west spdx --build-dir=./build/ --analyze-includes --include-sdk

生成的sdk.spdx内容摘要

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
FileName: ./riscv64-zephyr-elf/lib/gcc/riscv64-zephyr-elf/10.3.0/include/stddef.h
SPDXID: SPDXRef-File-stddef.h
FileChecksum: SHA1: b568ca33dace499eaf8da7a60f32019133a98217
FileChecksum: SHA256: ae6110360a66cb2a1e1f2141925f70a4f5818b27a7de2b62a78503c3391b7eb6
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NONE
FileCopyrightText: NOASSERTION

FileName: ./riscv64-zephyr-elf/riscv64-zephyr-elf/sys-include/_newlib_version.h
SPDXID: SPDXRef-File--newlib-version.h
FileChecksum: SHA1: 18c2341a01f6a969e04efdefc3deb52e24237ee8
FileChecksum: SHA256: 93a397574a25b9c143cee7fcb86d8fc9a0c9ba418e4710a30d2d19ba1e4120db
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NONE
FileCopyrightText: NOASSERTION

FileName: ./riscv64-zephyr-elf/riscv64-zephyr-elf/sys-include/machine/_endian.h
SPDXID: SPDXRef-File--endian.h
FileChecksum: SHA1: 437a704d6fd8bb063b7a689c32e4284d9fae07d6
FileChecksum: SHA256: 6a2878de2ce76eed443de3891e5dd49c67e3f41eea7054b47f9bd7ec27a144d0
LicenseConcluded: NOASSERTION
LicenseInfoInFile: NONE
FileCopyrightText: NOASSERTION

参考

https://docs.zephyrproject.org/latest/develop/west/zephyr-cmds.html#software-bill-of-materials-west-spdx
https://www.zephyrproject.org/generating-sboms-for-iot-at-build-time/
https://01.org/blogs/jc415/2018/open-source-hacks-one-question-interviews-open-source-experts-how-use-spdx-headers