セキュリティ
Qubes OS における qvm-copy-to-vm エラー報告バックチャネル経由の任意のコード実行
Arbitrary code execution in QubesOS via copy-to-VM error reporting backchannel (qubes-os.org)
要約
Qubes OS のセキュリティアドバイザリ QSB-118 では、`qvm-copy-to-vm` コマンドに脆弱性が発見されたことが報告されています。この脆弱性を悪用されると、悪意のある仮想マシンから dom0 に対して任意のコマンドを実行され、Qubes OS の制御を奪われる可能性があります。ユーザーは通常通りアップデートを行うことで、この脆弱性に対処できます。
全文翻訳
Qubes Security Bulletin (QSB) 118: Dom0 における qvm-copy-to-vm エラー報告での任意のコード実行 を公開しました。この QSB の本文とその暗号署名を以下に示し、続いてこの発表に関する一般的な説明と認証手順を記載します。
Qubes Security Bulletin 118
---
===[ Qubes Security Bulletin 118 ]===
2026-08-28
Dom0 における qvm-copy-to-vm エラー報告での任意のコード実行
ユーザーアクション
------------
セキュリティアップデートを受け取るために、通常通りアップデートを続けてください [1]。この QSB に関して、その他のユーザーアクションは必要ありません。
概要
--------
`qvm-copy-to-vm` を使用して dom0 から悪意のある qube へファイルをコピーした場合、その qube は dom0 に任意のコマンドを注入できます。
影響
-------
攻撃者が qube を侵害し、ユーザーが dom0 から侵害された qube へ `qvm-copy-to-vm` コールを開始した場合、攻撃者はこの脆弱性を悪用して dom0 に任意のコマンドを注入し、Qubes OS の制御を奪うことが可能になります。
技術的詳細
------------------
`qvm-copy-to-vm` ツールは、dom0 から指定された qube へのファイルコピーを許可します。これは "qfile" プロトコルを使用しており、これは単純なファイルメタデータを含む、単純化されたアーカイブ形式です(`tar` や `cpio` よりもはるかに単純です)。このプロトコルには、最後に転送確認が含まれており、これはターゲットからソースに返送されます。この確認には、転送された全ファイルのチェックサム、エラーコード(もしあれば)、および最後に受信したファイル名が含まれます。
エラーコードによって報告されたエラーの場合、dom0 はエラー情報とターゲット qube から報告された影響を受けたファイル名を含む GUI メッセージを表示します。脆弱性は、そのファイル名の処理に存在します。
1. `wait_for_result()` 関数は、受信した名前に `sanitize_remote_filename()` を呼び出してエラーハンドラに渡します。
```c
linux-utils/qrexec-lib/pack.c: 55 static void sanitize_remote_filename(char *untrusted_filename)
56 {
57 for (; *untrusted_filename; ++untrusted_filename) {
58 if (*untrusted_filename < ' ' ||
59 *untrusted_filename > '~' ||
60 *untrusted_filename == '"')
61 *untrusted_filename = '_';
62 }
63 }
64
65 void wait_for_result(void)
66 {
...
98 /* sanitize the remote filename */
99 sanitize_remote_filename(last_filename);
100
101 errno = hdr.error_code;
102 if (hdr.error_code != 0) {
103 switch (hdr.error_code) {
104 case EEXIST:
105 call_error_handler("A file named \"%s\" already exists in QubesIncoming dir", last_filename);
106 break;
...
```
2. 次に、`call_error_handler()` は dom0 バリアントのエラー報告関数 -- `gui_fatal()` -> `display_error()` を呼び出します。これは `system()` を使用して実際のエラーダイアログを起動します。
```c
core-admin-linux/file-copy-vm/qfile-dom0-agent.c: 15 void display_error(const char *fmt, va_list args)
16 {
17 char *dialog_cmd;
18 char buf[1024];
19 struct stat st_buf;
20 int ret;
21
22 (void) vsnprintf(buf, sizeof(buf), fmt, args);
23 ret = stat("/usr/bin/kdialog", &st_buf);
24 #define KDIALOG_CMD "kdialog --title 'File copy/move error' --sorry "
25 #define ZENITY_CMD "zenity --title 'File copy/move error' --warning --text "
26 if (asprintf(&dialog_cmd, "%s '%s: %s (error type: %s)'",
27 ret==0 ? KDIALOG_CMD : ZENITY_CMD,
28 program_invocation_short_name, buf, strerror(errno)) < 0) {
29 fprintf(stderr, "Failed to allocate memory for error message :(\\n");
30 return;
31 }
32 #undef KDIALOG_CMD
33 #undef ZENITY_CMD
34 fprintf(stderr, "%s\\n", buf);
35 system(dialog_cmd);
36 }
37
38 _Noreturn void gui_fatal(const char *fmt, ...)
39 {
40 va_list args;
41 va_start(args, fmt);
42 display_error(fmt, args);
43 va_end(args);
44 exit(1);
45 }
```
問題は、`sanitize_remote_filename()` が非 ASCII 文字(および二重引用符)のみを削除し、シェルメタ文字をそのまま残すことです。その後、`system()` は攻撃者が制御する名前を含む構築されたコマンドをシェル経由で実行します。`qvm-copy-to-vm` の VM バリアントは影響を受けないことに注意してください。なぜなら、そのエラー報告関数のバージョンは `system()` を使用しないからです。
```c
core-agent-linux/qubes-rpc/gui-fatal.c: 16 static void produce_message(const char *type, const char *fmt, va_list args)
17 {
...
31 if (progress_type && !strcmp(progress_type, "gui"))
32 {
33 switch (fork())
34 {
35 case -1:
36 exit(1); // what else
37 case 0:
38 if (geteuid() == 0) {
39 if (setuid(getuid()) != 0) {
40 perror("setuid failed, not calling zenity/kdialog");
41 exit(1);
42 }
43 }
44 fix_display();
45 execlp("/usr/bin/zenity", "zenity", "--error", "--text", dialog_msg, NULL);
46 execlp("/usr/bin/kdialog", "kdialog", "--sorry", dialog_msg, NULL);
47 exit(1);
48 default:;
49 }
50 }
51 free(dialog_msg);
52 }
53
54 void gui_fatal(const char *fmt, ...)
55 {
56 va_list args;
57 va_start(args, fmt);
58 produce_message("Fatal error", fmt, args);
59 va_end(args);
60 exit(1);
61 }
```
影響を受けるシステム
-----------------
すべての Qubes OS リリースが影響を受けます。
パッチ適用
---------
以下のパッケージに、このアドバイザリで説明されている脆弱性に対処するセキュリティアップデートが含まれています。
Qubes 4.3 の場合、dom0 で:
- qubes-core-dom0-linux, バージョン 4.3.22
このパッケージは、コミュニティによる短期間のテストの後、security-testing リポジトリから current (stable) リポジトリに移行します。[2] 利用可能になり次第、パッケージは Qubes Update ツールまたはそのコマンドライン等価物を使用してインストールする必要があります。
[1] https://doc.qubes-os.org/en/latest/user/how-to-guides/how-to-update.html
[2] https://doc.qubes-os.org/en/latest/user/downloading-installing-upgrading/testing.html
--
The Qubes Security Team
https://www.qubes-os.org/security/
Source: qsb-118-2026.txt
Marek Marczykowski-Górecki’s PGP signature
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEELRdx/k12ftx2sIn61lWk8hgw4GoFAmqSIHAACgkQ1lWk8hgw
4GoFoQ/+PavdhVipF8/C2uLvBrYcdUmPA8FraC89p4DLzAoh2EUOerSjzPSqyTwJ
S50jPNVHYiP6GaHsHoBNuRd8S9IN1GhyHfSRabjgcV/TfhXLXk8LrPVegq2IRMY6
FzkbBdpIUNn0gILeBJXyDhF50weRvrg7SZuwmjYvKUPHb4mA6wHEw01cuj54wVYW
iL/byB7ULnvlQWnsvKSYmSM3u+b9gOz2+jinNh2qRNg3pP3MUv1gQMFKH9CN5wE1
BiPn1bIn5v9V5RcG4nB6qgtqSE1JgB5a9KYJ3gNhGKA0N3Mnf+wS3LfWeU+0xmjW
PtWjMF+d1ZppT3yEeQj1jyyAemmwkB5zl+c/6FcEX8zvWGO2aYT/xe5yTbW7kVsM
js+FiF4opVMRx3t85WfbkN6Pu0F/bNP0OsE2IJ2G7T6v9gfzb4RfuLYdb01p9Mw2
RBZVP+tcQb7gtXdysapkLsIO+ST8AcewocokiPF3st+QeB6v/3pl+aab2NojXoUk
UzoJvRRd3e/KtAV1k1EAtajG5O8HFerW9LaULOGs6nPbVDBRLhJp0nlec5ZuRbpX
jaJGgXzD/QntiNiWH1iaB7NxeZJPzKGg8O7MPUvQV4Cn02uoE5J5EY8XZrGhNPVl
D4HHrQb+dMrwImEAGovHMdqVPJIiTGRFm5umwpKK8NRVWGjpsu8=
=fHjz
-----END PGP SIGNATURE-----
Source: qsb-118-2026.txt.sig.marmarek
Simon Gaiser (aka HW42)’s PGP signature
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE6hjn8EDEHdrv6aoPSsGN4REuFJAFAmqSRk0ACgkQSsGN4REu
FJC8wQ//UOa2EdMZpIDLaYropqMHyt7cVlm3Ad4zpgqmteWOUSS2z6Y3DLA2b0Ng
xVDsmgJcoxqMt0tbzU9awSB/v41CKPQlXnevEFucwZWgeoQIhnZwr7c6zo2unngv
wc2eMMsIL/7QX2DPotoieshryTUB6kbb1hKwiXojWOJKTwVvQPRZmU6hWLAXtg7G
F4Ar/XMm2DR+KstIHFpvP+IWdS41+SWjIgjJJraUl5BE7mDF51M8vR4IvVM9Td8w
bb1ENAFO2W/ZnYnqGJpMmzWVhDzxjkikH9TT3CZmdulXa7ggK2V2EgBDJ681XtW+
jOC9f5OJjoVHc5LtPsAMZxL3sGbfOBfogK5Fwpi6lmzjcG3oCB6MMvEkveZRaSiO
H8vPl4H1dEIUKSA1LGZWEgY8RjuX0N4pnNOLzbn86tMpqYLtNBqGZ2/r8WkJSfXS
fYWyVAtF9kcy8scb4lYlsdfD7gZ8wH7dl/iUKikiS3NyFdAlYvb0OZd6c7BZwD2C
+YLHlo03he9WE1GbLoPPzqTN8VnunJ9eyyCs56SsHL5CYLfLnT95kMssAd+uJypo
7QZj3+xz7i2kaqK4osEL+5WUR47DyJEgKP8bMPeCV5ZZFC85eVKAn4BzYULx6tff
wVin+t9uZ2kwur7IyG+8Bb1PUgr+vATsVW1QcrfcRT6ujY4VDDs=
=1/K/
-----END PGP SIGNATURE-----