** 概要 このリポジトリは、CodeQLを使用してpolkit pkexecバグを調査します。 以下が含まれます:
完了済み:
未完了:
** バグ Polkit pkexecバグ [[https://blog.qualys.com/vulnerabilities-threat-research/2022/01/25/pwnkit-local-privilege-escalation-vulnerability-discovered-in-polkits-pkexec-cve-2021-4034][(CVE-2021-4034)]] は、argvに関する配列境界エラーから始まり、 それを基に構築されています。 この問題の範囲外部分は、 codeqlレンジ分析ライブラリで調べることができます。
polkit/src/programs/pkexec.c 内の pkexec の main() 関数は、次の構造を持ちます: #+begin_src text 435 main (int argc, char *argv[]) 436 { ... 534 for (n = 1; n < (guint) argc; n++) 535 { ... 568 } ... 610 path = g_strdup (argv[n]); ... #+end_src
主なアイデア:
確認するバージョン:
2009年以降のすべてのPolkitバージョンが脆弱です。最初のバージョンは2009年5月 (コミット c8c3d83, "Add a pkexec(1) command") です。
[[https://lgtm.com/projects/g/freedesktop/polkit/ci/#ql][lgtmから]] /a/ データベースを取得できます。現在のもの <2022-02-11 Fri> は =...srcVersion_a6bedfd...= ですが、これはすでにpolkitパッチを通過しています: #+BEGIN_SRC text commit a6bedfd09b7bba753de7a107dc471da0db801858 (origin/master, origin/HEAD, master) Author: Xi Ruoyao [email protected] Date: Thu Jan 27 10:16:32 2022 +0000
jsauthority: port to mozjs-91
commit a2bf5c9c83b6ae46cbd5c779d3055bff81ded683 Author: Jan Rybar [email protected] Date: Tue Jan 25 17:21:46 2022 +0000
pkexec: local privilege escalation (CVE-2021-4034)
#+END_SRC そして、問題が修正されていることがわかります: #+BEGIN_SRC text commit a2bf5c9c83b6ae46cbd5c779d3055bff81ded683 Author: Jan Rybar [email protected] Date: Tue Jan 25 17:21:46 2022 +0000
pkexec: local privilege escalation (CVE-2021-4034)
diff --git a/src/programs/pkcheck.c b/src/programs/pkcheck.c index f1bb4e1..768525c 100644 --- a/src/programs/pkcheck.c +++ b/src/programs/pkcheck.c @@ -363,6 +363,11 @@ main (int argc, char *argv[]) local_agent_handle = NULL; ret = 126;
exit(126);
したがって、[[https://gitlab.freedesktop.org/polkit/polkit.git][ソースコード]] を取得し、パッチ適用前とパッチ適用後の 独自のデータベースを構築する必要があります。
次のセクションでは、Dockerコンテナを使用した構築手順を説明します。
** polkitとCodeQL DBの構築 codeqlデータベースを取得する前に、polkitのビルド環境が必要です。
ビルド用のオペレーティングシステムのオプション:
macOSも試す価値はありますが、すぐに複雑になります。 =brew= を使用して 依存関係を取得することはある程度機能しますが、=mozjs-78= 依存関係は spidermonkeyの特定のバージョンであり、/それを/ ビルドすることは現実的ではありません。 #+BEGIN_SRC sh # autoconf... macでは少し厄介です brew install autoconf automake libtool gtk-doc export PATH="/usr/local/opt/libtool/libexec/gnubin:$PATH" ./autogen.sh
# mesonを使用しますか?
brew install meson ninja intltool glib gobject-introspection
#+END_SRC
Linuxはpolkitのネイティブ環境ですが、どれでしょうか? mozjs-78 依存関係はspidermonkeyの特定のバージョンです。また、polkitはすべての ディストリビューションで使用されているわけではありません:
Ubuntu 22.04は、ハードウェア、VM (vmware、virtualbox、multipassなど)、または別のホスト上のdocker コンテナなど、さまざまな方法で実行できます。 この問題では、Dockerコンテナを使用し、 codeqlコマンドラインツールも含めることができます。
コンテナの定義は ./Dockerfiles にあり、ビルドシーケンスは次のとおりです: #+BEGIN_SRC shell # qlbuildコンテナをセットアップするためのベースイメージ docker pull ubuntu:jammy docker images docker run --cpus 4 -m 8GB -ti ubuntu:jammy
# カスタマイズするイメージ
docker build -t qlbuild .
#+END_SRC 注: Windowsとmacでdocker desktopを使用する場合、メモリとCPUの制限を そこで引き上げる必要があります。 設定後、コンテナの実行シーケンスは単純です: #+BEGIN_SRC sh # デーモンとして実行し、切断しても存続させます。 docker run -d -p 127.0.0.1:2020:22 --cpus 8 -m 16GB qlbuild
# そして接続
ssh -p 2020 test@localhost
#+END_SRC
Ubuntu 22.04でのビルド
#+BEGIN_SRC sh
# ---------------------------------
# システムセットアップ/インストール (rootとして):
echo "deb-src http://archive.ubuntu.com/ubuntu/ jammy main restricted" >> /etc/apt/sources.list
apt-get update
apt-get install -y zile build-essential git cmake
meson ninja-build
libmozjs-78-0 libmozjs-78-dev
libdbus-1-3 libdbus-1-dev
apt-get build-dep -y policykit-1
apt install unzip
# polkitバージョンa2bf5c9cにはいくつかの追加パッケージも必要です
apt install duktape duktape-dev
# 古いmesonを /usr/local/bin に
pip3 install meson==0.60.3
# またはソースを取得して使用します:
# wget https://github.com/mesonbuild/meson/archive/refs/tags/0.60.3.tar.gz
# tar zxf 0.60.3.tar.gz
# etc.
# ---------------------------------
# codeqlセットアップ -- まだroot
# 取得 -- codeql cliとライブラリを取得して展開します
# 使用法: grab version url prefix
grab() {
version=$1; shift
platform=$1; shift
prefix=$1; shift
mkdir -p $prefix/codeql-$version &&
cd $prefix/codeql-$version || return
# cliを取得
wget "https://github.com/github/codeql-cli-binaries/releases/download/$version/codeql-$platform.zip"
# ライブラリを取得
wget "https://github.com/github/codeql/archive/refs/tags/codeql-cli/$version.zip"
# 属性を修正
if [ `uname` = Darwin ] ; then
xattr -c *.zip
fi
# 展開
unzip -q codeql-$platform.zip
unzip -q $version.zip
# VS Code用にライブラリディレクトリ名を変更
mv codeql-codeql-cli-$version/ ql
# アーカイブを削除
rm codeql-$platform.zip
rm $version.zip
}
grab v2.7.6 linux64 /opt
grab v2.6.3 linux64 /opt
# ---------------------------------
# ユーザーtestとして:
# polkitソースを取得
cd /tmp && git clone https://gitlab.freedesktop.org/polkit/polkit.git
# バージョン0.119をビルド
cd /tmp/polkit
git checkout 0.119
git clean -fxd
meson setup builddir
meson compile -C builddir
find builddir -name pkexec -ls
: 139269 76 -rwxr-xr-x 1 test root 76696 Feb 12 03:06 builddir/src/programs/pkexec
# ---------------------------------
# バージョン0.119のcodeqlデータベースをビルド
cd /tmp/polkit
git checkout 0.119
git clean -fxd
# codeqlなしで通常どおり設定ステップを実行
cd /tmp/polkit && rm -fR builddir
meson setup builddir
# codeqlでビルドステップを実行
export CODEQL=/opt/codeql-v2.7.6/codeql/codeql
$CODEQL --version
$CODEQL database create --language=cpp -s . -j 8 -v \
polkit-0.119.db \
--command='meson compile -C builddir'
# 次を待ちます
# TRAP import complete (10.2s).
# Successfully created database at /tmp/polkit/polkit-0.119.db.
# pkexecが認識されたことを確認する簡単なチェック:
unzip -v polkit-0.119.db/src.zip |grep pkexec
: 29713 Defl:N 8477 72% 2022-02-14 20:12 bb39f235 tmp/polkit/src/programs/pkexec.c
# ---------------------------------
# パッチ適用済みバージョン (そして引き続きmozjs-78を使用) である
# バージョンa2bf5c9cのcodeqlデータベースをビルド
cd /tmp/polkit
git checkout a2bf5c9c
git clean -fxd
# codeqlなしで通常どおり設定ステップを実行
cd /tmp/polkit && rm -fR builddir
/usr/local/bin/meson setup builddir
# meson 0.61では、設定は次のエラーで停止します
# actions/meson.build:3:5: ERROR: Function does not take positional arguments.
# 簡単な検索で次にたどり着きます
# https://lore.kernel.org/all/20220111222135.693a88f2@windsurf/T/
# そしてそこから
# [1/1] package/gobject-introspection: bump to version 1.70.0
# codeqlでビルドステップを実行
export CODEQL=/opt/codeql-v2.7.6/codeql/codeql
$CODEQL --version
$CODEQL database create --language=cpp -s . -j 8 -v \
polkit-a2bf5c9c.db \
--command='/usr/local/bin/meson compile -C builddir'
# 次を待ちます
# TRAP import complete (7.2s).
# Successfully created database at /tmp/polkit/polkit-a2bf5c9c.db.
# pkexecが認識されたことを確認する簡単なチェック:
unzip -v polkit-a2bf5c9c.db/src.zip |grep pkexec
: 30136 Defl:N 8647 71% 2022-02-14 21:27 6af18604 tmp/polkit/src/programs/pkexec.c
#+END_SRC
dbをホスト上の恒久的な場所にコピーします #+BEGIN_SRC sh # コンテナからコピー mkdir -p ~/local/polkit && cd ~/local/polkit scp -rq -P 2020 test@localhost:/tmp/polkit/polkit-0.119.db . scp -rq -P 2020 test@localhost:/tmp/polkit/polkit-a2bf5c9c.db .
# オリジナルを保持
zip -rq polkit-0.119.zip polkit-0.119.db
zip -rq polkit-a2bf5c9c.zip polkit-a2bf5c9c.db
#+END_SRC
次は、クエリ開発のセットアップです。
** クエリ開発のセットアップ クエリは、codeql cli単独、またはcodeql cli + VS Codeプラグインを使用して 調査できます。 どちらの場合も、cliをインストールし (上記の =grab()= 関数を参照)、 [[./db]] からデータベースを展開するか、[[*Build polkit and codeql db][Build polkit and codeql db]] で 行ったようにビルドします。
以下では、データベースに次のディレクトリ構造を想定しています: #+BEGIN_SRC text . ├── polkit-0.119.db │ ├── codeql-database.yml │ ├── db-cpp │ ├── log │ └── src.zip ├── polkit-0.119.zip ├── polkit-a2bf5c9c.db │ ├── codeql-database.yml │ ├── db-cpp │ ├── log │ └── src.zip └── polkit-a2bf5c9c.zip #+END_SRC
** クエリ クエリは [[./argv-out-of-bounds-*.ql]] で段階的に開発されます。
[[./argv-out-of-bounds-0.ql]] の最初のステップでは、ASTと変数参照を使用して、 結果を問題の既知の部分に絞り込みます。次のとおりです。
#+BEGIN_SRC text declaration | 435 main (int argc, char *argv[]) | 436 { | ... init other var; | 534 for (n = 1; compare to argc | n < (guint) argc; update other var | n++) | 535 { | ... | 568 } | ... indexed read | 610 path = g_strdup (argv[n]); | ... | 629 if (path[0] != '/') | 630 { | ... | 632 s = g_find_program_in_path (path); | ... indexed write | 639 argv[n] = path = s; | 640 } #+END_SRC
値の調査は [[./argv-out-of-bounds-1.ql]] で始まり、=SimpleRangeAnalysis= ライブラリを 使用して次のように試みます: #+begin_src javascript lowerBound(cmp.getLeftOperand().getFullyConverted()), "left lower bound", lowerBound(cmp.getRightOperand().getFullyConverted()), "right lower bound" #+end_src 境界は型に対して正しいですが、あまりにも一般的です -- 反復の可能な結果も含みます。 私たちは、反復が発生する前の、静的に決定される初期境界のみに関心があります。
言い換えると、これは一般的なデータフローの問題ではありません。特定の実行パスに沿った 初期値の伝播のみをチェックしたいのです。 =for= ループは、その中の操作と同様に、 これを複雑にします。
私たちが本当に見たいのは、ループを完全にバイパスする実行パスです。 これは [[./argv-out-of-bounds-1.ql]] の後半部分で、=SsaDefinition= を使用して行われます。
クエリ [[./argv-out-of-bounds-2.ql]] は、[[./argv-out-of-bounds-1.ql]] の調査をクリーンアップし、 既知のインデックス値 =n > 0= を持つ =n= を使用するすべての場所を正しく識別します。
このクエリは、脆弱なバージョンのコード =polkit-0.119.db= で結果を報告します。 次に、パッチ適用済みバージョン =polkit-a2bf5c9c.db= で何も報告しないように、 チェックして拡張する必要があります。