Ubuntu Weekly Recipe

第734回UbuntuでSBOM(ソフトウェア部品表)作る方法

SBOM(Software Bill Of Materials:ソフトウェア部品表)という概念があります。これはあるソフトウェアを構築する上で利用しているライブラリの一覧をまとめたものです。また、システムにインストールされているソフトウェア一覧を示す場合もあります。今回は手元のUbuntuにインストールされているソフトウェア一覧を簡易的にまとめる方法を紹介しましょう。

SBOMの必要性

昨今のソフトウェアは多種多様なライブラリに依存しながら構築されています。太古のC言語のプログラムなら、シンプルなものならlibcだけ、そこそこ複雑なものでも2、3個のライブラリに依存するだけで済むことが大半でした。それが今風のプログラミング言語になると、特定の便利そうなライブラリに依存するだけで、⁠だったら俺も僕も私もミーも」といくつものライブラリがバンドルされてしまうのです。

結果的に広く使われているライブラリで脆弱性が発生すると、入れ子的に依存しているけれどもあまり関係のないソフトウェアにまで影響を及ぼしてしまいます。最近だとJavaプログラムで広く使われているApache Log4jに脆弱性が見つかり、その影響範囲の広さから大きな問題となりました。結果的にさまざまなソフトウェアコミュニティにおいて、いろんな人から「この問題影響ないか?」⁠このライブラリは使ってないか?」との絨毯爆撃される様子を目にした人も多いのではないでしょうか。今後も人気のライブラリに大きな問題が見つかる度に、似たような事態が繰り返されることになるでしょう。

問題の本質は、あるソフトウェアがどんなライブラリを使っているのかわかりにくい点です。各プログラミング言語のビルド環境が充実した結果、ビルド時にライブラリの依存関係等も自動的に解決してくれるようになりました。結果的にソフトウェア上で何が使われていて、何が使われるかわかりにくくなっているのです。

そこで出てくるのがSBOM(Software Bill Of Materials:ソフトウェア部品表)です。ソフトウェアを構築するソフトウェア一式を部品表の形で常にリストアップしておくことで、サプライチェーン上の部品の一部に問題が発覚したときに影響範囲を追跡しやすくなります。製造業では一般的に行われていた文化で、身近なものだと食品表示ラベルの原材料名もBOMの一種です。ソフトウェアの分野でも組み込み関係だと、特に構成ソフトウェアのライセンス管理の観点からすでにSBOMを作っているところも多いでしょう[1]

ただしソフトウェアの場合、開発周期やメンテナンス性を考えると、プロセスやツールをできるだけ自動化することが肝要です。そこで現在は様々な自動化ツールが登場しています。たとえばMicrosoftはUbuntuでも動くSBOM構築ツールであるSBOM Toolを公開しています。これはソースツリーの中身を精査して、利用しているソフトウェアのメタデータ情報をJSONファイルにまとめるものです。おそらく今後ソフトウェア開発を行うメーカーも、このようなツールを用いてSBOMを作成・維持する文化がより広まっていくことでしょう。

これによりSBOMを定期的に作成しておくことで、特定のソフトウェアの特定のバージョンに問題が発生したとき、それに影響を受けるのがどのバージョンなのかをすぐに把握できるようになります。結果的に必要な対応・アナウンスも素早く行えるようになります。ただし残念ながら、Log4jと同様の問題が起きたときは、影響度をやたらと高圧的に問い合わせる人が減ることは期待できません[2]

Ubuntuにインストールされているソフトウェアを調べる

今回は「Ubuntuにインストールされているソフトウェア一式」をSBOMとして構築してみましょう。通常のソフトウェアにおいてSBOMは、ソースコードツリーやそこに含まれるビルド用のメタデータを用いてSBOMを作成します。しかしながらUbuntuの場合は、⁠インストール済みの環境」を用いて構築することになります。どのソフトウェアのどのバージョンがインストールされているかをストアップしていくわけです。個々のソフトウェアごとのSBOMは今回は対象外とします。これはソフトウェアごとに調べる必要があるためです。

インストール済みの環境を使用する場合、⁠そのソフトウェアを使用する際に必要するソフトウェア」の依存関係を検討する必要はありません。依存するソフトウェアはすべてインストール済みであるためです。つまり単にインストール済みのソフトウェアをリストアップするだけで完了です。インストール済みパッケージリストを表示するかんたんな方法はdpkg -lコマンドです。

$ dpkg -l
要望=(U)不明/(I)インストール/(R)削除/(P)完全削除/(H)保持
| 状態=(N)無/(I)インストール済/(C)設定/(U)展開/(F)設定失敗/(H)半インストール/(W)トリガ待ち/(T)トリガ保留
|/ エラー?=(空欄)無/(R)要再インストール (状態,エラーの大文字=異常)
||/ 名前                                       バージョン                                 アーキテクチ 説明
+++-==========================================-==========================================-============-================================================================================
ii  accountsservice                            22.07.5-2ubuntu1.3                         amd64        query and manipulate user account information
ii  acl                                        2.3.1-1                                    amd64        access control list - utilities
ii  acpi-support                               0.144                                      amd64        scripts for handling many ACPI events
ii  acpid                                      1:2.0.33-1ubuntu1                          amd64        Advanced Configuration and Power Interface event daemon
(後略)

このdpkg -ldpkg-query --listのエイリアスとなっています。しかしながらこの表示は人間が読む用途で作られており、出力フォーマットの変更はできないようになっています。SBOMとして管理するには若干不便です。より機械向けに出力を調整できるのがdpkg-query --showコマンドとなります。

$ dpkg-query --show
accountsservice 22.07.5-2ubuntu1.3
acl     2.3.1-1
acpi-support    0.144
acpid   1:2.0.33-1ubuntu1
(後略)

このように何も指定しなければパッケージ名とバージョンをタブ連結で表示してくれます。dpkg-queryのmanページにもあるように、--showformat='フォーマットリスト'で出力を調整できます。たとえばHomepageフィールドがあるパッケージはURLも合わせて表示してみましょう。

$ dpkg-query --show --showformat='${Package}\t${Version}\t${Homepage}\n'
accountsservice 22.07.5-2ubuntu1.3      https://www.freedesktop.org/wiki/Software/AccountsService/
acl     2.3.1-1 https://savannah.nongnu.org/projects/acl/
acpi-support    0.144
acpid   1:2.0.33-1ubuntu1       http://sourceforge.net/projects/acpid2/
(後略)

これでTSV(Tab Separated Values)フォーマットでのファイルを生成できますし、sedやtrなどでタブ文字をカンマに変換すればCSVにもできます。

$ dpkg-query --show --showformat='${Package}\t${Version}\t${Homepage}\n' | sed 's/\t/,/g'
accountsservice,22.07.5-2ubuntu1.3,https://www.freedesktop.org/wiki/Software/AccountsService/
acl,2.3.1-1,https://savannah.nongnu.org/projects/acl/
acpi-support,0.144,
acpid,1:2.0.33-1ubuntu1,http://sourceforge.net/projects/acpid2/

Debianパッケージのパッケージ名やバージョン名にタブ文字やカンマが含まれることはありませんので、エスケープの検討は不要なはずです。

ただしdpkg-queryは必ずしも現在インストールされているパッケージだけを表示するわけではありません。⁠過去にインストールされていたけれどもその後削除されて、設定ファイルはまだ残っている」というタイプのパッケージdpkg -lでいうところのrcと表示されるパッケージなど)も表示されます。⁠現在インストールされているパッケージだけ」を表示したい場合は、${Status}も出力して、⁠install ok installed」になっているものだけをリストアップすると良いでしょう。

次の例では「現在インストールされているパッケージだけ」を表示しつつ、jqコマンドを用いてJSON化しています。

$ sudo apt install jq
$ jq -Rsn '{ "packages": [ inputs | . / "\n" |  (.[] | select(length > 0) | . / "\t") as $input |
  {"name": $input[0], "version": $input[1], "site": $input[2] } ] }' \
  <(dpkg-query --show --showformat='${Package}\t${Version}\t${Homepage}\t${Status}\n' | grep "install ok installed")
 {
  "packages": [
    {
      "name": "accountsservice",
      "version": "22.07.5-2ubuntu1.3",
      "site": "https://www.freedesktop.org/wiki/Software/AccountsService/"
    },
    {
      "name": "acl",
      "version": "2.3.1-1",
      "site": "https://savannah.nongnu.org/projects/acl/"
    },
    {
      "name": "acpi-support",
      "version": "0.144",
      "site": ""
    },
    {
      "name": "acpid",
      "version": "1:2.0.33-1ubuntu1",
      "site": "http://sourceforge.net/projects/acpid2/"
    },
(後略)

ここからさきはこの結果を「sbom.json」として保存した上で、内容を更新していきましょう。

ちなみにaptコマンドでもインストール済みのパッケージをリストアップできます。

$ apt list --installed
一覧表示...
accountsservice/jammy-updates,jammy-security,now 22.07.5-2ubuntu1.3 amd64 [インストール済み、自動]
acl/jammy,now 2.3.1-1 amd64 [インストール済み、自動]
acpi-support/jammy,now 0.144 amd64 [インストール済み、自動]
acpid/jammy,now 1:2.0.33-1ubuntu1 amd64 [インストール済み、自動]
(後略)

こちらは完全に人間が読む目的で作られているため、スクリプトで操作することはあまり想定していません。

インストールされていないパッケージのメタデータについては、grep-dctrlコマンドなどが使えます。grep-dcrtrlの使い方については第312回のパッケージとより良いお付き合いをするための情報収集を参照してください。

ソフトウェアごとのファイルリストを調べる

インストールされているパッケージの名前やバージョンについては簡単に取得できましたが、ストレージの内容のファイルをすべて網羅しているかはこれだけではわかりません。パッケージが提供するファイルやディレクトリのリストはdpkg -L パッケージ名で表示できます。

$ dpkg -L acpi-support
/.
/etc
/etc/acpi
/etc/acpi/asus-keyboard-backlight.sh
/etc/acpi/asus-wireless.sh
/etc/acpi/events
/etc/acpi/events/asus-keyboard-backlight-down
(後略)

上記の結果を見るとわかるように、ファイルの上位ディレクトリもリストに含まれます。また、インストール時や実行時に自動生成されるファイルは含まれません。前者の例としてはパッケージのインストールスクリプトで必要に応じて作られるファイルなどsystemd enableした結果など⁠⁠、後者の例としては起動時にユーザーのホームディレクトリに作られる設定ファイルなどが該当します。これらの自動生成ファイルの元を機械的に調べるのはそこそこ難しいことだけ念頭に置いておくと良いでしょう。

実はこのファイルリストはストレージの中にファイルとして保存されています。それが/var/lib/dpkg/info/パッケージ名.listです。これをcatすると、dpkg -Lと同じ結果が得られます。

$ cat /var/lib/dpkg/info/acpi-support.list
/.
/etc
/etc/acpi
/etc/acpi/asus-keyboard-backlight.sh
/etc/acpi/asus-wireless.sh
/etc/acpi/events
/etc/acpi/events/asus-keyboard-backlight-down
(後略)

ただし注意点としてここで使われる「パッケージ名」はアーキテクチャーの修飾子がついたものになります。たとえば上記の例だとacpi-supportで問題ありませんが、zlib1gだとパッケージ名は「zlib1g」ではなく「zlib1g:amd64」となります。

$ file /var/lib/dpkg/info/zlib1g.list
/var/lib/dpkg/info/zlib1g.list: cannot open `/var/lib/dpkg/info/zlib1g.list' (No such file or directory)
$ file /var/lib/dpkg/info/zlib1g:amd64.list
/var/lib/dpkg/info/zlib1g:amd64.list: ASCII text

dpkg-queryの場合このパッケージ名は${binary:Package}で参照できます。

ちなみにDebianパッケージでは、⁠設定ファイル(conffiles⁠⁠」という概念も存在します。これはインストールされるファイルのうち、ユーザーが編集可能なファイルを「設定ファイル」として定義し、パッケージのアップグレード時などにファイルを置き換える場合、設定ファイルが変更されていたら特別な処理を行うというものです。この設定ファイルは/var/lib/dpkg/info/パッケージ名.conffilesとして保存されています。

$ cat /var/lib/dpkg/info/acpi-support.conffiles
/etc/acpi/asus-keyboard-backlight.sh
/etc/acpi/asus-wireless.sh
/etc/acpi/events/asus-keyboard-backlight-down
(後略)

一般的に設定ファイルは/etc/以下に配置されます。可変なファイルを特別扱いしたい場合は、このファイルを参考にリストアップを行うと良いでしょう。

前項で作成したsbom.jsonに、jqを用いてファイル一覧を追加してみましょう。

$ for p in $(dpkg-query --show --showformat='${binary:Package}\t${status}\n' | grep "install ok installed" | awk '{ print $1 }'); do
    cat /var/lib/dpkg/info/$p.list | jq -R . > files.json
    jq --arg name "$p" --slurpfile files files.json '(.packages[] | select(.name == $name) | .files) |= $files' sbom.json > sbom.json.tmp;
    mv sbom.json.tmp sbom.json;
  done

$ jq '.packages[0]' sbom.json
{
  "name": "accountsservice",
  "version": "22.07.5-2ubuntu1.3",
  "site": "https://www.freedesktop.org/wiki/Software/AccountsService/",
  "files": [
    "/.",
    "/lib",
    "/lib/systemd",
    "/lib/systemd/system",
    "/lib/systemd/system/accounts-daemon.service",
    "/usr",
    "/usr/libexec",
    "/usr/libexec/accounts-daemon",
    "/usr/share",
    "/usr/share/accountsservice",
    "/usr/share/accountsservice/user-templates",
    "/usr/share/accountsservice/user-templates/administrator",
    "/usr/share/accountsservice/user-templates/standard",
    "/usr/share/dbus-1",
    "/usr/share/dbus-1/interfaces",
    "/usr/share/dbus-1/interfaces/org.freedesktop.Accounts.User.xml",
    "/usr/share/dbus-1/interfaces/org.freedesktop.Accounts.xml",
    "/usr/share/dbus-1/system-services",
    "/usr/share/dbus-1/system-services/org.freedesktop.Accounts.service",
    "/usr/share/dbus-1/system.d",
    "/usr/share/dbus-1/system.d/org.freedesktop.Accounts.conf",
    "/usr/share/doc",
    "/usr/share/doc/accountsservice",
    "/usr/share/doc/accountsservice/README.md",
    "/usr/share/doc/accountsservice/TODO",
    "/usr/share/doc/accountsservice/copyright",
    "/usr/share/doc/accountsservice/spec",
    "/usr/share/doc/accountsservice/spec/AccountsService.html",
    "/usr/share/language-tools",
    "/usr/share/language-tools/language-options",
    "/usr/share/language-tools/language-validate",
    "/usr/share/language-tools/language2locale",
    "/usr/share/language-tools/locale2papersize",
    "/usr/share/language-tools/main-countries",
    "/usr/share/language-tools/save-to-pam-env",
    "/usr/share/language-tools/set-language-helper",
    "/usr/share/language-tools/update-langlist",
    "/usr/share/polkit-1",
    "/usr/share/polkit-1/actions",
    "/usr/share/polkit-1/actions/org.freedesktop.accounts.policy",
    "/var",
    "/var/lib",
    "/var/lib/AccountsService",
    "/var/lib/AccountsService/icons",
    "/var/lib/AccountsService/users",
    "/usr/share/doc/accountsservice/changelog.Debian.gz"
  ]
}

愚直にひとつずつ処理しているため、実行環境によってはそれなりに時間がかかりますし、sbom.jsonのファイルサイズも数十メガバイト程度となることでしょう。もしかするとファイルリストはjsonに含まずに別ファイルでアーカイブする形でも良いかもしれません。

もしかするとjqにもsedのinplaceのようなオプションがあるのかもしれませんが、見つけられなかったのでここではファイルをコピーしています。このあたり無理やりjqだけでやろうとしているから非効率なのであって、Python等を用いてスクリプト化すれば、もっとスマートで効率よく実施できるはずです。

ソフトウェアの個々のライセンスを調べる

ソフトウェアにはライセンスが存在します。UbuntuやDebianに含まれるソフトウェアは原則としてDebianフリーソフトウェアガイドライン(DFSG)に準拠したフリーソフトウェアといくつかのプロプライエタリなバイナリデータから構築されています。また設定やインストール内容によっては、プロプライエタリなソフトウェアも含まれているかもしれません。システムにインストールされたソフトウェアのライセンスも一覧表示したいところです。

ソフトウェアのライセンススキャナーとしてはFOSSologyなどが有名です。FOSSologyは原則としてソースツリー(やソースパッケージ)の中身を精査して、ライセンス情報をまとめてくれるツールになります。しかしながらDebianパッケージにはもともと「copyright」ファイルの作成が義務付けられています。これはDebianパッケージが提供するソフトウェアの個々のファイルのライセンスをリストアップしたものです。今回はこれを参考にしてみましょう。

ただしcopyrightの内容にはいくつかの懸念点があります。まず最初に、このファイルは基本的にパッケージメンテナーが手動で更新しています。よって抜け漏れは起こりえますし、最新の状態に追随できていない可能性もあります。

もうひとつは「機械読み取り可能」ではないことです。従来のcopyrightファイルはある程度のフォーマットは決まっていたものの、メンテナーに依存した書式になっていました。最近はDEP 5: Machine-readable debian/copyrightを元に、機械読み取り可能なcopyrightフォーマットに更新しているパッケージが増えてはいますが、すべてがそうなっているわけではないのです。具体的に手元のマシンにインストールされた約2700個のバイナリパッケージのうち、新しいフォーマットになっているのは2000個程度でした[3]

copyrightファイルは/usr/share/doc/パッケージ名/copyrightとして保存されます。このパッケージ名はアーキテクチャー修飾子がついていないものです。つまり前述のzlib1gパッケージの例だと、copyrightファイルの位置は/usr/share/doc/zlib1g/copyrightとなります。

そこで${Package}でパッケージ名をリストアップしつつ、copyrightがdep5に対応していたらライセンスのリストを、そうでないなら「no dep5」を、sbom.jsonのパッケージ情報に埋め込んでみましょう。

$ for p in $(dpkg-query --show --showformat='${Package}\t${status}\n' | grep "install ok installed" | awk '{ print $1 }'); do
    if [ -f /usr/share/doc/$p/copyright ]; then
      if grep -q '^Format: ' /usr/share/doc/$p/copyright; then
        cat /usr/share/doc/$p/copyright | grep '^License: ' | sort -u | cut -d' ' -f 2- | jq -R . > licenses.json;
      else
        echo '"no dep5"' > licenses.json;
      fi
      jq --arg name "$p" --slurpfile licenses licenses.json '(.packages[] | select(.name | startswith($name)) | .licenses) |= $licenses' sbom.json > sbom.json.tmp;
      mv sbom.json.tmp sbom.json;
    fi
  done

$ jq '.packages[0:3] | .[] | .name, .licenses' sbom.json
"accountsservice"
[
  "GPL-2+",
  "GPL-3+"
]
"acl"
[
  "GPL-2+",
  "LGPL-2+"
]
"acpi-support"
[
  "GPL-2+"
]

これでdep5に対応しているパッケージについてはライセンス情報を記録できました。ただしファイルリストと同じくこちらもあまり効率的な方法ではありません。特にライセンス情報は本来コンポーネントごとにわかれているはずなので、ただライセンスを列挙するだけでなく、コンポーネントも合わせて書くほうが正しい対応となります。このあたりも、Pythonスクリプト等を使ってより柔軟に作成できるようにすると良いでしょう。

Ubuntuのソフトウェアのバージョンと脆弱性情報

理想的には「対応している脆弱性リスト」もSBOMに入れられると嬉しいのですが、これは一筋縄ではいきません。それよりはパッケージのバージョンから都度引くほうが良さそうです。

ちなみに世の中には上記に対応した「脆弱性スキャナ」がいくつか存在しますが、Ubuntuの場合その利用には注意が必要です。一般的にソフトウェアに脆弱性が見つかると、その脆弱性に対応したバージョンがリリースされます。たとえばあるパッケージがバージョン2系とバージョン3系の、2系統をメンテナンスしているとき、⁠2.0.3」「3.0.1」に同様の脆弱性が見つかった場合は、⁠2.0.4」「3.0.2」で対応されるといった具合です。

しかしながらUbuntuの場合、上記の脆弱性の修正を次のような流れで取り込みます。たとえばUbuntu 22.04 LTSに3.0.1(パッケージバージョン:3.0.1-1ubuntu1)が、Ubuntu 20.04 LTSに2.0.3(パッケージバージョン:2.0.3-1ubuntu2)が存在し、開発中のUbuntu 22.10に3.0.1(パッケージバージョン:3.0.1-1ubuntu1)が存在したとしましょう。

Ubuntuにおいて、個々のリリースの対応は次のようになります。

  • 22.10のパッケージのバージョンを3.0.2(パッケージバージョン:3.0.2-1ubuntu-1)にあげる
  • 3.0.2のうち脆弱性修正部分をパッチとして22.04の3.0.1に取り込み、パッケージバージョンを3.0.1-1ubuntu1.1とする
  • 2.0.4のうち脆弱性修正部分をパッチとして20.04の2.0.3に取り込み、パッケージバージョンを2.0.3-1ubuntu2.1とする

これによりそのソフトウェアの表面上のバージョンはそれぞれ「3.0.1」⁠2.0.3」のままとなります。もし脆弱性スキャナがこのルールを無視して、⁠ソフトウェアのバージョン表記だけ」を見るタイプのものであれば、Ubuntuのパッケージは「脆弱性あり」として判断されてしまいます。よって脆弱性スキャナーを使う場合は、Ubuntu(を含むLinuxディストリビューションのパッケージ管理システム)に対応したものを使うことが重要です。

このあたりの事情については、Ubuntu Weekly Topicsの2019年6月14日号でも詳しく説明されていますのでそちらも参照してください。

さて、Ubuntuの特定のパッケージが、ある脆弱性に対応しているかどうかを確認する方法はいくつか存在します。

UbuntuのCVEレポートは、Ubuntuのセキュリティチームがメンテナンスしている個々のCVEに対するUbuntuリリースごとの対応状況のまとめです。確認したいCVE番号が明らかな場合はまずはここを見ると良いでしょう。

ちなみにセキュリティ対応が行われてリリースされたパッケージは、Ubuntu Security Noticesとして通知されます。メーリングリストやRSSもあるので、定期的に情報が欲しい場合は登録しておきましょう。本連載の姉妹連載であるUbuntu Weekly Topicsでは、1週間ごとのUbuntu Security Noticesの内容をまとめていますので、日本語の情報が欲しい場合はそちらも参考になるでしょう。

Ubuntuのパッケージによっては、対応したCVE番号をパッケージのchangelogファイルに記載します。ただしこれはパッケージメンテナー次第です。パッケージによってはソフトウェアの開発元(upstream)の最新バージョンに更新することでセキュリティ対応を済ませてしまうこともあり、その場合はCVE番号が掲載されません。とりあえず確認してみるなら、⁠apt changelog パッケージ名」を実行すると良いでしょう。たとえばkittyパッケージだと、2022年10月に行われた脆弱性対応がchangelogに残っています。

$ apt changelog kitty
kitty (0.21.2-1ubuntu0.22.04.1) jammy-security; urgency=medium

  * SECURITY UPDATE: an attacker controlled desktop notification escape
    sequence allows execution of arbitrary commands
    - debian/patches/CVE-2022-41322.patch: sanitizes desktop notification
      escape sequence
    - CVE-2022-41322

 -- Mark Esler <[email protected]>  Tue, 04 Oct 2022 18:46:33 -0500

最後のua/proコマンドは、Ubuntu Advantage Tools(Ubuntu Pro)のツールです。このコマンドはインストール環境において特定のCVE番号の脆弱性が対応済みかどうかを確認する機能も有しています[4]

たとえば先程のkittyの脆弱性CVE-2022-41322だと次のように確認できます。

$ pro fix CVE-2022-41322
CVE-2022-41322: kitty vulnerabilities
https://ubuntu.com/security/CVE-2022-41322
No affected source packages are installed.
✔ CVE-2022-41322 does not affect your system.

そもそもkitty関連のパッケージをインストールしていない環境(No affected source packages are installed.)だったため、結果は「CVE-2022-41322 does not affect your system.」でした。それではどの環境にもインストールされているであろ、isc-dhcpパッケージの脆弱性CVE-2022-2929を見てみましょう。

$ pro fix CVE-2022-2929
CVE-2022-2929: DHCP vulnerabilities
https://ubuntu.com/security/CVE-2022-2929
1 affected source package is installed: isc-dhcp
(1/1) isc-dhcp:
A fix is available in Ubuntu standard updates.
The update is already installed.
✔ CVE-2022-2929 is resolved.

こちらはインストール済みの関連パッケージがリストアップされ(1 affected source package is installed: isc-dhcp⁠⁠、すでに修正パッケージがインストール済みであることが提示されています。

2022年10月9日時点で修正パッケージがまだ作られていないCVE-2022-42010の場合は、次のような結果になります。

$ pro fix CVE-2022-42010
CVE-2022-42010:
[Unknown description]
https://ubuntu.com/security/CVE-2022-42010
1 affected source package is installed: dbus
(1/1) dbus:
Ubuntu security engineers are investigating this issue.
1 package is still affected: dbus
✘ CVE-2022-42010 is not resolved.

バツマークとともに「is not resolved」と表示されました。SBOMの作成から話がずれましたが、上記のように手元の環境で特定のCVEが対応済みかどうか確認したいだけなら、proコマンドを使うと便利です。

Debianパッケージ以外や出力フォーマット

ここまでの流れでインストール済みのDebianパッケージの一覧およびそのファイルリストやライセンスを取得できるようになりました。実はUbuntuシステムの場合、Debianパッケージ以外にもsnapパッケージがインストールされています。snapパッケージはsnap listコマンドでパッケージの一覧を取得可能ではありますが、Debianパッケージほど柔軟なメタデータの取得はできません。ただし提供されるファイルはすべて/snap/パッケージ名/current/以下にmountしているので、この下をいくつかのツールを使ってパースすることになるでしょう。

またDebianパッケージ自体も、インストール済みのファイルやバイナリは取得できるものの、この方法では「構築時に利用したソフトウェア」は不明なままです。こちらについてはソースパッケージのリポジトリを有効化した上で、ソースパッケージのメタデータをパースすることになります。他にもapt source パッケージ名でソースパッケージをダウンロード・展開した上で、SBOM作成ツール等を利用する手もあります。

出力フォーマットも、今回はJSONベースでオリジナルのフォーマットを利用しましたが、SBOMが広く作られるようになるとフォーマットも共通化されていくことになるでしょう。標準化済みのオープンなフォーマットで目下の有力候補はSPDX(Software Package Data Exchange)です。これはLinux Foundation参加で開発しているフォーマットで、どちらかと言うとソフトウェアのソースファイルごとのライセンス・著作権情報をまとめるためのフォーマットでしたが、実質やっていることはSBOMの作成そのものですし、SPDX自身SBOM情報のやりとりを行うためのオープスタンダードの構築を目指すと明記しています。

Linxuカーネルのソースコードや、Debianのcopyrightファイルのdep5においても、ライセンスの名前としてSPDXの識別子をしていできることからもわかるとおり、今後ソースコードやメタデータ内のライセンス情報の記述方法としてSPDXフォーマットが増えていくことは確実でしょう。

おすすめ記事

記事・ニュース一覧