以下の内容はhttps://mickey-happygolucky.hatenablog.com/entry/2025/01/25/133627より取得しました。


Yocto ProjectのSBOM生成機能をためす

はじめに

Yocto ProjectではSBOM(Software Bill Of Materials)を出力する機能がある。SBOMはcreate-spdx.bbclassの機能によって出力される。 また、Nanbield(4.3)からこの機能がデフォルトで有効化されている。

今回はScarthgap(5.0)でこの機能を試してみた。

SBOMが何かは日本語の情報だと下記が詳しい。

create-spdx.bbclassesの機能で出力されるSBOMの形式はSPDXとなっている。 SPDXはYocto Projectと同じLinux Foundation参加のプロジェクトで策定されている。

SPDXについては下記が詳しい。

環境構築

まずは環境を構築する。

作業環境

$ mkdir -p ~/yocto/scarthgap
$ cd ~/yocto/scarthgap

pokyの取得

$ git clone git://git.yoctoproject.org/poky.git -b scarthgap 

環境変数の設定

$ source poky/oe-init-build-env

local.confを編集

local.confに下記を追加する。

MACHINE ?= "qemuarm64"
INIT_MANAGER ?= "systemd"

QB_OPT_APPEND:append = " -echr 0x14"
SPDX_PRETTY = "1"

ビルド

今回はターゲットの機能は使わないのでcore-image-minimalをビルドする。

$ bitbake core-image-minimal -k

これでSBOMが出力されているはず。

Yocto ProjectのSBOMの機能

37 Creating a Software Bill of Materialsに機能の詳細が記述されている。

まず、SBOMは下記の場所に生成されているとのこと。

  • SPDX output in JSON format as an IMAGE-MACHINE.spdx.json file in tmp/deploy/images/MACHINE/ inside the Build Directory.

今回の環境では「build/tmp/deploy/images/qemuarm64」になるので確認する。

$ cd tmp/deploy/images/qemuarm64
$ ls -lha *.spdx.json
ls: '*.spdx.json' にアクセスできません: そのようなファイルやディレクトリはありません

見つからない。

わかりにくいが実はこのような修正が行われている。

  • create-spdx: remove the top-level image SPDX file and the JSON index file from DEPLOYDIR to avoid confusion

DEPLOYDIRは https://docs.yoctoproject.org/singleindex.html#term-DEPLOYDIR によると、「DEPLOYDIR = "${WORKDIR}/deploy-${PN}"」となるらしいが、さらに下記のような記述がある。

Recipes inheriting the deploy class should copy files to be deployed into DEPLOYDIR, and the class will take care of copying them into DEPLOY_DIR_IMAGE afterwards.

DEPLOY_DIR_IMAGEは「${DEPLOY_DIR}/images/${MACHINE}/」となっており、DEPLOY_DIRは「${TMPDIR}/deploy.」となっているため、最終的には「build/tmp/deploy/images/qemuarm64」と一致する。

つまりは「build/tmp/deploy/images/qemuarm64」には「IMAGE-MACHINE.spdx.json」は作成されないということが正しい動作であるらしいということになる。

では実際のSBOMはどこにあるかというと、「core-image-minimal-qemuarm64.rootfs.spdx.tar.zst」となる。正確にはこれはシンボリックリンクなのでその指し先がSBOM本体。

tar.zstは下記のコマンドで伸長できる。

$ tar -I zstd -xf HOGE.tar.zst

次のようにして実際に伸張してみる。

$ cd ~/yocto/scarthgap/build/tmp/deploy/images/qemuarm64
$ mkdir sbom
$ cd sbom
$ tar -I zstd -v -xf ../core-image-minimal-qemuarm64.rootfs.spdx.tar.zst

SBOMの内容

SPDX_PRETTY

local.confでSPDX_PRETTY = "1"を設定している。これを設定しないと下記のような感じになる。

{"SPDXID": "SPDXRef-DOCUMENT", "creationInfo": {"comment": "This document was created by analyzing packages created during the build.", "created": "2025-01-25T00:35:11Z", "creators": ["Tool: OpenEmbedded Core create-spdx.bbclass", "Organization: OpenEmbedded ()", "Person: N/A ()"], "licenseListVersion": "3.14"}, "dataLicense": "CC0-1.0", "documentNamespace": "http://spdx.org/spdxdocs/base-files-dev-a752bc7c-388a-5a14-984a-72e888717fd3", "externalDocumentRefs": [{"checksum": {"algorithm": "SHA1", "checksumValue": "6dd33163fd47c2258769c8c955fe324cc3293273"}, "externalDocumentId": "DocumentRef-recipe-base-files", "spdxDocument": "http://spdx.org/spdxdocs/recipe-base-files-c146050a-959a-5836-966f-98e79d6e765f"}], "name": "base-files-dev", "packages": [{"SPDXID": "SPDXRef-Package-base-files-dev", "copyrightText": "NOASSERTION", "downloadLocation": "NOASSERTION", "licenseConcluded": "NOASSERTION", "licenseDeclared": "GPL-2.0-only", "licenseInfoFromFiles": ["NOASSERTION"], "name": "base-files-dev", "packageVerificationCode": {"packageVerificationCodeValue": "da39a3ee5e6b4b0d3255bfef95601890afd80709"}, "supplier": "Organization: OpenEmbedded ()", "versionInfo": "3.0.14"}], "relationships": [{"relatedSpdxElement": "DocumentRef-recipe-base-files:SPDXRef-Recipe-base-files", "relationshipType": "GENERATED_FROM", "spdxElementId": "SPDXRef-Package-base-files-dev"}, {"relatedSpdxElement": "SPDXRef-Package-base-files-dev", "relationshipType": "DESCRIBES", "spdxElementId": "SPDXRef-DOCUMENT"}], "spdxVersion": "SPDX-2.2"}

設定すると下記のように改行とインデントが挿入され、人間が読みやすく(Human-readable)なる。

{
  "SPDXID": "SPDXRef-DOCUMENT",
  "creationInfo": {
    "comment": "This document was created by analyzing packages created during the build.",
    "created": "2025-01-25T00:48:46Z",
    "creators": [
      "Tool: OpenEmbedded Core create-spdx.bbclass",
      "Organization: OpenEmbedded ()",
      "Person: N/A ()"
    ],
    "licenseListVersion": "3.14"
  },
... (snip) ...
  "spdxVersion": "SPDX-2.2"
}

出力されるデータの内容はこの設定によって変化することはない。

データの分類

core-image-minimal-qemuarm64.rootfs.spdx.tar.zstに含まれているSBOMについては下記のように分類することができる

分類 ファイル名 概要
イメージ <イメージ名>.spdx.json イメージ及び含まれているすべてのパッケージの情報
インデックス index.json 出力されたすべてのspdxファイルの一覧
レシピ recipe-<レシピ名>.spdx.json ソース及びビルド時依存関係の情報
パッケージ <パッケージ名>.spdx.json パッケージ及び含まれているファイルの情報
ランタイム runtime-<パッケージ名>.spdx.json 実行時依存関係の情報

イメージ

今回はcore-image-minimal-qemuarm64.rootfs-20250124123426.spdx.jsonが生成された。

{
  "SPDXID": "SPDXRef-DOCUMENT",
  "creationInfo": {
    "comment": "This document was created by analyzing the source of the Yocto recipe during the build.",
    "created": "2025-01-24T12:42:53Z",
    "creators": [
      "Tool: OpenEmbedded Core create-spdx.bbclass",
      "Organization: OpenEmbedded ()",
      "Person: N/A ()"
    ],
    "licenseListVersion": "3.14"
  },
  "dataLicense": "CC0-1.0",
  "documentNamespace": "http://spdx.org/spdxdocs/core-image-minimal-qemuarm64.rootfs-20250124123426-65884203-16cb-5c76-b945-338caac15f74",
  "externalDocumentRefs": [
    {
      "checksum": {
        "algorithm": "SHA1",
        "checksumValue": "441afea16d04b80a127fcaad0ce335c3608a97b7"
      },
      "externalDocumentId": "DocumentRef-base-files",
      "spdxDocument": "http://spdx.org/spdxdocs/base-files-ee9424e3-1d7e-5739-b9cd-237a1a6f843f"
    },
...(snip)...
  ],
  "packages": [
    {
      "SPDXID": "SPDXRef-Image-core-image-minimal-qemuarm64.rootfs-20250124123426",
      "copyrightText": "NOASSERTION",
      "downloadLocation": "NOASSERTION",
      "licenseConcluded": "NOASSERTION",
      "licenseDeclared": "NOASSERTION",
      "licenseInfoFromFiles": [
        "NOASSERTION"
      ],
      "name": "core-image-minimal",
      "supplier": "Organization: OpenEmbedded ()",
      "versionInfo": "1.0"
    }
  ],
  "relationships": [
    {
      "relatedSpdxElement": "DocumentRef-base-files:SPDXRef-Package-base-files",
      "relationshipType": "CONTAINS",
      "spdxElementId": "SPDXRef-Image-core-image-minimal-qemuarm64.rootfs-20250124123426"
    },
... (snip) ...
  ],
  "spdxVersion": "SPDX-2.2"
}

大きく下記のブロックに分けることができる。

  • creationInfo: SPDXファイル自体の情報
  • externalDocumentRefs: 外部のSPDXファイルへの参照
    • イメージに含まれるパッケージ
  • packages: イメージの情報
  • relationship: 各エレメントとの関係(CONTAINS,OTHER...)

インデックス

index.jsonが生成された。アーカイブに含まれているすべてのSPDXファイルの情報が記述されている。

{
  "documents": [
    {
      "documentNamespace": "http://spdx.org/spdxdocs/base-files-ee9424e3-1d7e-5739-b9cd-237a1a6f843f",
      "filename": "base-files.spdx.json",
      "sha1": "441afea16d04b80a127fcaad0ce335c3608a97b7"
    },
    {
      "documentNamespace": "http://spdx.org/spdxdocs/base-passwd-78e3ab0a-4686-572d-a886-5105dd9b12de",
      "filename": "base-passwd.spdx.json",
      "sha1": "ff03da0613185fc706748144ea96acb018765fc8"
    },
    {
      "documentNamespace": "http://spdx.org/spdxdocs/busybox-syslog-9c50eff5-a9f9-5765-b33a-312c76b55eb2",
      "filename": "busybox-syslog.spdx.json",
      "sha1": "c6c338cafce778f362a45b1c6af31e4f4bcb93a8"
    },
... (snip) ...

レシピ

recipe-update-rc.d.spdx.jsonを例示する。

{
  "SPDXID": "SPDXRef-DOCUMENT",
  "creationInfo": {
    "comment": "This document was created by analyzing recipe files during the build.",
    "created": "2025-01-24T12:34:48Z",
    "creators": [
      "Tool: OpenEmbedded Core create-spdx.bbclass",
      "Organization: OpenEmbedded ()",
      "Person: N/A ()"
    ],
    "licenseListVersion": "3.14"
  },
  "dataLicense": "CC0-1.0",
  "documentNamespace": "http://spdx.org/spdxdocs/recipe-update-rc.d-87cf57af-6fc6-500b-8aa5-8b53c9c11554",
  "name": "recipe-update-rc.d",
  "packages": [
    {
      "SPDXID": "SPDXRef-Recipe-update-rc.d",
      "copyrightText": "NOASSERTION",
      "description": "update-rc.d is a utility that allows the management of symlinks to the initscripts in the /etc/rcN.d directory structure.",
      "downloadLocation": "NOASSERTION",
      "externalRefs": [
        {
          "referenceCategory": "SECURITY",
          "referenceLocator": "cpe:2.3:*:*:update-rc.d:0.8:*:*:*:*:*:*:*",
          "referenceType": "http://spdx.org/rdf/references/cpe23Type"
        }
      ],
      "homepage": "http://github.com/philb/update-rc.d/",
      "licenseConcluded": "NOASSERTION",
      "licenseDeclared": "GPL-2.0-or-later",
      "licenseInfoFromFiles": [
        "NOASSERTION"
      ],
      "name": "update-rc.d",
      "summary": "manage symlinks in /etc/rcN.d",
      "supplier": "Organization: OpenEmbedded ()",
      "versionInfo": "0.8+git"
    },
    {
      "SPDXID": "SPDXRef-Download-update-rc.d-1",
      "copyrightText": "NOASSERTION",
      "downloadLocation": "git+https://git.yoctoproject.org/update-rc.d@b8f950105010270a768aa12245d6abf166346015",
      "licenseConcluded": "NOASSERTION",
      "licenseDeclared": "NOASSERTION",
      "licenseInfoFromFiles": [
        "NOASSERTION"
      ],
      "name": "update-rc.d-source-1",
      "supplier": "NOASSERTION"
    }
  ],
  "relationships": [
    {
      "relatedSpdxElement": "SPDXRef-Recipe-update-rc.d",
      "relationshipType": "DESCRIBES",
      "spdxElementId": "SPDXRef-DOCUMENT"
    },
    {
      "relatedSpdxElement": "SPDXRef-Download-update-rc.d-1",
      "relationshipType": "DESCRIBES",
      "spdxElementId": "SPDXRef-DOCUMENT"
    },
    {
      "relatedSpdxElement": "SPDXRef-Recipe-update-rc.d",
      "relationshipType": "BUILD_DEPENDENCY_OF",
      "spdxElementId": "SPDXRef-Download-update-rc.d-1"
    }
  ],
  "spdxVersion": "SPDX-2.2"
}

大きく下記のブロックに分けることができる。

  • creationInfo: SPDXファイル自体の情報
  • externalDocumentRefs: 外部のSBOMへの参照
    • ビルド時依存関係のあるレシピ
  • packages: レシピの情報(ソースコードの場所やライセンス、セキュリティFixの情報など)
  • relationship: 各エレメントとの関係(BUILD_DEPENDENCY_OF, DESCRIBES...)

CVE対応状況などはここに含まれる。下記はrecipes-openssl.spdx.jsonの例

  "packages": [
    {
... (snip) ...
      "name": "openssl",
      "sourceInfo": "CVEs fixed: CVE-2024-9143",//★これ
      "summary": "Secure Socket Layer",
      "supplier": "Organization: OpenEmbedded ()",
      "versionInfo": "3.2.3"
    },

パッケージ

update-rc.d.spdx.jsonを例示する。

{
  "SPDXID": "SPDXRef-DOCUMENT",
  "creationInfo": {
    "comment": "This document was created by analyzing packages created during the build.",
    "created": "2025-01-24T12:34:48Z",
    "creators": [
      "Tool: OpenEmbedded Core create-spdx.bbclass",
      "Organization: OpenEmbedded ()",
      "Person: N/A ()"
    ],
    "licenseListVersion": "3.14"
  },
  "dataLicense": "CC0-1.0",
  "documentNamespace": "http://spdx.org/spdxdocs/update-rc.d-fde24237-98eb-54c2-b3e8-cc69971dd42c",
  "externalDocumentRefs": [
    {
      "checksum": {
        "algorithm": "SHA1",
        "checksumValue": "9732cb1d663117e9acd729bbd9bd453141ef3c14"
      },
      "externalDocumentId": "DocumentRef-recipe-update-rc.d",
      "spdxDocument": "http://spdx.org/spdxdocs/recipe-update-rc.d-87cf57af-6fc6-500b-8aa5-8b53c9c11554"
    }
  ],
  "files": [
    {
      "SPDXID": "SPDXRef-PackagedFile-update-rc.d-1",
      "checksums": [
        {
          "algorithm": "SHA1",
          "checksumValue": "8cabd995976443050be511510920ca5ecfc057c9"
        },
        {
          "algorithm": "SHA256",
          "checksumValue": "5426fe8d447719957b51bdce842fb857816a6d5cd5053f7586ffbf66b48111d2"
        }
      ],
      "copyrightText": "NOASSERTION",
      "fileName": "usr/sbin/update-rc.d",
      "fileTypes": [
        "BINARY"
      ],
      "licenseConcluded": "NOASSERTION",
      "licenseInfoInFiles": [
        "NOASSERTION"
      ]
    }
  ],
  "name": "update-rc.d",
  "packages": [
    {
      "SPDXID": "SPDXRef-Package-update-rc.d",
      "copyrightText": "NOASSERTION",
      "downloadLocation": "NOASSERTION",
      "hasFiles": [
        "SPDXRef-PackagedFile-update-rc.d-1"
      ],
      "licenseConcluded": "NOASSERTION",
      "licenseDeclared": "GPL-2.0-or-later",
      "licenseInfoFromFiles": [
        "NOASSERTION"
      ],
      "name": "update-rc.d",
      "packageVerificationCode": {
        "packageVerificationCodeValue": "35e8e3f99d23c8b20ea0ccfc4a21222fdc8eff34"
      },
      "supplier": "Organization: OpenEmbedded ()",
      "versionInfo": "0.8+git"
    }
  ],
  "relationships": [
    {
      "relatedSpdxElement": "DocumentRef-recipe-update-rc.d:SPDXRef-Recipe-update-rc.d",
      "relationshipType": "GENERATED_FROM",
      "spdxElementId": "SPDXRef-Package-update-rc.d"
    },
    {
      "relatedSpdxElement": "SPDXRef-Package-update-rc.d",
      "relationshipType": "DESCRIBES",
      "spdxElementId": "SPDXRef-DOCUMENT"
    },
    {
      "relatedSpdxElement": "SPDXRef-PackagedFile-update-rc.d-1",
      "relationshipType": "CONTAINS",
      "spdxElementId": "SPDXRef-Package-update-rc.d"
    }
  ],
  "spdxVersion": "SPDX-2.2"
}

大きく下記のブロックに分けることができる。

  • creationInfo: SPDXファイル自体の情報
  • externalDocumentRefs: 外部のSPDXファイルへの参照
    • 元になったレシピ
  • files: パッケージに含まれるファイルの情報
  • packages: パッケージの情報(バージョン、ライセンス、提供者など)
  • relationship: 各エレメントとの関係(GENERATED_FROM,DESCRIBES,CONTAINS...)

依存関係はここに含まれない。

ランタイム

runtime-update-rc.d.spdx.jsonを例示する。

{
  "SPDXID": "SPDXRef-DOCUMENT",
  "creationInfo": {
    "comment": "This document was created by analyzing package runtime dependencies.",
    "created": "2025-01-24T12:34:49Z",
    "creators": [
      "Tool: OpenEmbedded Core create-spdx.bbclass",
      "Organization: OpenEmbedded ()",
      "Person: N/A ()"
    ],
    "licenseListVersion": "3.14"
  },
  "dataLicense": "CC0-1.0",
  "documentNamespace": "http://spdx.org/spdxdocs/runtime-update-rc.d-91536303-d4bc-55bf-bad5-db561c40958c",
  "externalDocumentRefs": [
    {
      "checksum": {
        "algorithm": "SHA1",
        "checksumValue": "d2d90dd2cf17edb835512a92866156918cc23e18"
      },
      "externalDocumentId": "DocumentRef-package-update-rc.d",
      "spdxDocument": "http://spdx.org/spdxdocs/update-rc.d-fde24237-98eb-54c2-b3e8-cc69971dd42c"
    }
  ],
  "name": "runtime-update-rc.d",
  "relationships": [
    {
      "relatedSpdxElement": "DocumentRef-package-update-rc.d:SPDXRef-DOCUMENT",
      "relationshipType": "AMENDS",
      "spdxElementId": "SPDXRef-DOCUMENT"
    }
  ],
  "spdxVersion": "SPDX-2.2"
}

大きく下記のブロックに分けることができる。

  • creationInfo: SPDXファイル自体の情報
  • externalDocumentRefs: 外部のSPDXファイルへの参照
    • 対象のパッケージ
    • 依存関係のあるパッケージのランタイム
  • relationship: 各エレメントとの関係(AMENDS、RUNTIME_DEPENDENCY_OF...)

まとめ

  • Yocto ProjectではデフォルトでSBOMが出力される
  • マニュアルが実装に追いついていない部分がある
    • IMAGE-MACHINE.spdx.jsonはtmp/deploy/images/MACHINEには存在しない
  • IMAGE-MACHINE.rootfs.spdx.tar.zstが本体
  • レシピ、パッケージ、ランタイムのSPDXファイル組み合わせることで、パッケージ情報や依存関係などが表現されている



以上の内容はhttps://mickey-happygolucky.hatenablog.com/entry/2025/01/25/133627より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14