はじめに
bitbakeではビルドするパッケージの脆弱性をCVEによってチェックを行う機能がある。
使い方
local.conf
に下記を追加する。
INHERIT += "cve-check"
すると、各パッケージのタスクにdo_cve_check
が追加される。
bitbakeを実行すると、このタスクが実行され、未対策の脆弱性があった場合には警告として表示される。
実行例
この機能を実装しているcve-check.bbclass
に記載されているコマンドの実行例を示す。
$ bitbake -c cve_check openssl $ bitbake core-image-sato $ bitbake -k -c cve_check universe
出力結果
CVEチェックの結果はログファイルとして保存される。
各パッケージに対する出力結果は${WORK_DIR}/temp/cve.log
として保存される。
イメージに対する出力結果はbuild/tmp/deploy/images/イメージ名.cve
として保存される。ラスベリーパイ4向けのcore-image-baseの場合はbuild/tmp/deploy/images/raspberrypi4/core-image-base-raspberrypi4.cve
の様になる。
出力結果の例を下記に示す。
PACKAGE NAME: libvorbis PACKAGE VERSION: 1.3.6 CVE: CVE-2020-20412 CVE STATUS: Patched CVE SUMMARY: lib/codebook.c in libvorbis before 1.3.6, as used in StepMania 5.0.12 and other products, has insufficient array bounds checki\ ng via a crafted OGG file. CVSS v2 BASE SCORE: 4.3 CVSS v3 BASE SCORE: 6.5 VECTOR: NETWORK MORE INFORMATION: https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2020-20412 PACKAGE NAME: pixman PACKAGE VERSION: 1_0.38.4 CVE: CVE-2013-0800 CVE STATUS: Unpatched CVE SUMMARY: Integer signedness error in the pixman_fill_sse2 function in pixman-sse2.c in Pixman, as distributed with Cairo and used in Mo\ zilla Firefox before 20.0, Firefox ESR 17.x before 17.0.5, Thunderbird before 17.0.5, Thunderbird ESR 17.x before 17.0.5, SeaMonkey before \ 2.17, and other products, allows remote attackers to execute arbitrary code via crafted values that trigger attempted use of a (1) negative\ box boundary or (2) negative box size, leading to an out-of-bounds write operation. CVSS v2 BASE SCORE: 6.8 CVSS v3 BASE SCORE: 0.0 VECTOR: NETWORK MORE INFORMATION: https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-0800
適用済みのものはPatched
、そうじゃないものはUnpatched
となっている。
検出の仕組み
cvecheckerがベースとなっているらしい。
これは、オンラインからCVEのデータベースを取得し、SQLite3で脆弱性情報に対してマッチするものがあるかを検索するというもの。
プロダクト名とバージョンの組み合わせによって関係ある脆弱性があるかどうかを簡易的に判定するだけなので、このチェックによって全ての脆弱性に関する危険性を排除できるわけではないとされている。
Yoctoでの実装
do_cve_check
python do_cve_check () { """ Check recipe for patched and unpatched CVEs """ if os.path.exists(d.getVar("CVE_CHECK_DB_FILE")): try: patched_cves = get_patches_cves(d) except FileNotFoundError: bb.fatal("Failure in searching patches") whitelisted, patched, unpatched = check_cves(d, patched_cves) if patched or unpatched: cve_data = get_cve_info(d, patched + unpatched) cve_write_data(d, patched, unpatched, whitelisted, cve_data) else: bb.note("No CVE database found, skipping CVE check") }
get_patches_cves(d)
とcheck_cves(d, patched_cves)
によってチェックしているようだ。
get_patches_cves
レシピに含まれるファイル名にCVE-IDが含まれているか、ファイル中の文字列にCVE-IDが含まれているものは対策済みとして扱うようにしている。 どちらも正規表現による文字列マッチとなっている。
ファイル名は下記の条件でマッチしている。CVE-1234-211432
やみたいなものが引っかかるようになっている。CVEに対する大文字/小文字の混在もOKのようだ。
cve_file_name_match = re.compile(".*([Cc][Vv][Ee]\-\d{4}\-\d+)")
ファイル中の文字列は下記の条件でマッチしている。
cve_match = re.compile("CVE:( CVE\-\d{4}\-\d+)+")
こちらはCVE: CVE-2020-13362
のようなものが引っかかるようになっている。
check_cves
こちらはホワイトリストに含まれていれば無視し、それ以外のものをCVE_CHECK_DB_FILE
で指定されているデータベースで検索する。
ホワイトリストには下記の2種類がある。
- CVE_CHECK_WHITELIST(CVE-ID)
- CVE_CHECK_PN_WHITELIST(パッケージ名)
CVE_CHECK_WHITELIST
は特定のCVEを無視したい場合にCVE-IDを指定する。
CVE_CHECK_PN_WHITELIST
は特定のパッケージに関するCVEを無視したい場合にパッケージ名を指定する。
データベースの検索条件はCVE_PRODUCT
とCVE_VERSION
の組み合わせとなっている。
CVE_PRODUCT
はデフォルトではBPN
が使用される。CVEデータベース上のプロダクト名とBPNがマッチしない場合や、1つのレシピで複数のパッケージを生成する場合などは明示的に設定する必要がある。
flacのレシピでは下記のように設定されている。
CVE_PRODUCT = "libflac flac"
CVE_VERSION
はデフォルトではPV
が使用される様になっている。こちらもCVEデータベース上のバージョン表記と一致しない場合などは明示的に設定する必要がある。
CVE_CHECK_DB_FILE
はSQLite3のデータベースとなっており、筆者が実行した環境では「"${DL_DIR}/CVE_CHECK/nvdcve_1.1.db"」が指定されている。
このファイルはcve-update-db-native
によりダウンロードされる。
CVE対策をレシピに含める場合
get_patches_cves
のロジックにより、CVE対策としてパッチを作成する場合、ファイル名を下記のようにするか、
CVE-2020-12723.patch
コメント中に下記のような文字列を含めるかすると、対策済みとして扱われるようになる。
CVE: CVE-2020-13362
まとめ
bitbakeではCVE情報によって脆弱性をチェックする機能がある。
基本的にはプロダクト名とバージョンによって、関係あるCVEが対策済みかどうかを判断する。 レシピ中のSRC_URIで指定されたファイル名やコメントなどによって、データベース上では未対策のCVEでも、対策済みと扱うことができるようになっている。
また、特定のCVEや特定のパッケージをホワイトリストに追加することによって、未対策のものであっても問題ないものに関しては明示的にチェックしないようにすることもできる。
基本的には「プロダクト名+バージョン」や、ファイル名やコメントなどによる簡易的なチェックであり、 これらのチェック機能によって全ての脆弱性を網羅できるわけではないが、これで得られた情報をもとに脆弱性に対する方針を立てることができる。