io_uringが本番環境でセキュリティ問題になる理由
io_uringは Linux 5.1(2019年)で導入された非同期I/Oインタフェースです。従来の epoll や aio と比べてシステムコール回数を大幅に削減でき、高スループットのネットワークサーバやデータベースエンジンで積極的に採用されています。一方、カーネルとユーザ空間が共有リングバッファを介して直接やり取りする設計は攻撃面が広く、2022年以降、特権昇格・use-after-free・ヒープ破壊に関わるCVEが継続的に報告されています。
代表的な例として CVE-2022-1786(use-after-free、CVSS 7.8)、CVE-2022-2078(ヒープオーバーフロー)、CVE-2024-0582(UAF、CVSS 7.8)が挙げられます。いずれも「非特権ユーザがio_uringの操作を通じてカーネルメモリを破壊し、root権限を取得できる」パターンです。Google ChromeOS・Android・Cloudflareのサンドボックス環境が相次いでio_uringを無効化または制限したのはこうした背景があるためです。
本番環境への対策として、「完全に無効化する」「アプリケーション単位でseccompで制御する」「cgroupで使用を制限する」という3つの選択肢があります。本記事ではこれらを組み合わせた運用シナリオを、段階的検証・切り戻し手順とあわせて解説します。
cgroup v2によるio_uring使用量の制御
Linux 5.5以降、cgroup v2には io.uring サブシステムが実装されています(より正確には misc コントローラ配下の io_uring リソース制限)。ただし、2026年時点でディストリビューションによって対応状況に差があるため、後述の「現行環境差分」も参照してください。
systemdサービス単位でio_uringを制限する
systemdのサービスユニットに RestrictAddressFamilies や SystemCallFilter を加えることで、io_uringに関連するシステムコール(io_uring_setup・io_uring_enter・io_uring_register)をブロックできます。
# /etc/systemd/system/myapp.service.d/security.conf
[Service]
SystemCallFilter=~io_uring_setup io_uring_enter io_uring_register
SystemCallErrorNumber=EPERM
SystemCallFilter=~ はブラックリスト指定です。指定したシステムコールを呼び出した場合、EPERM を返してプロセスを継続させます(SIGSYS で終了させたい場合は SystemCallErrorNumber を省略)。設定後は systemctl daemon-reload && systemctl restart myapp で反映します。
cgroup misc コントローラでリング数を上限設定する
cgroup v2の misc コントローラが有効な環境では、特定のcgroupに対してio_uringインスタンス数(リング数)を制限できます。これにより「使わせない」ではなく「使いすぎを防ぐ」制御が可能になります。
# misc コントローラが有効か確認
cat /sys/fs/cgroup/cgroup.controllers
# 出力例: cpuset cpu io memory hugetlb pids rdma misc
# 対象cgroupのio_uring上限を設定(例: 8インスタンスまで)
echo "io_uring 8" > /sys/fs/cgroup/system.slice/myapp.service/misc.max
現在の使用状況は misc.current で確認できます。io_uring max と出力されていれば制限なし、数値が表示されていれば上限が設定されています。
seccompフィルタによるプロセスレベルの制御
cgroupが「グループ単位の制御」であるのに対し、seccompは「プロセス単位のシステムコールフィルタ」です。コンテナランタイム(containerd・podman)やアプリケーション組み込みのサンドボックスでは、seccompプロファイルで直接io_uring呼び出しを遮断するほうが管理がシンプルです。
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"names": ["io_uring_setup", "io_uring_enter", "io_uring_register"],
"action": "SCMP_ACT_ERRNO",
"errnoRet": 1
}
]
}
Dockerの場合は --security-opt seccomp=/path/to/profile.json で指定します。Kubernetesでは Pod の spec.securityContext.seccompProfile に Localhost タイプで参照します。
seccompフィルタは SCMP_ACT_TRACE でauditd・strace連携のログ収集にも使えます。本番適用前にまず SCMP_ACT_LOG(カーネル 4.14以降)で呼び出し頻度を記録し、アプリケーションが実際にio_uringを使っているかを確認するのが安全です。
段階的な検証手順
制限を一気に適用すると、io_uringに依存したライブラリ(liburing・TokioのLinuxバックエンド・io_uring対応のglibcなど)が EPERM でフォールバックするか、クラッシュするかの判断ができません。以下は想定例として示す段階的な検証フローです。
ステージ1:ログのみで依存状況を把握する
まず SystemCallLog=io_uring_setup io_uring_enter io_uring_register(systemd 246以降)または SCMP_ACT_LOG のseccompプロファイルをステージング環境に適用します。本番同等の負荷をかけて、io_uring呼び出しが発生しているかをsyslogまたはaudit.logで確認します。
# auditdでio_uring_setup呼び出しをトレース
auditctl -a always,exit -F arch=b64 -S io_uring_setup -k iouring_audit
ausearch -k iouring_audit --start today
ステージ2:非特権ユーザへの制限をまず適用する
カーネルパラメータ kernel.io_uring_disabled(Linux 6.2以降に追加)は3段階の値を持ちます。
- 0:制限なし(デフォルト)
- 1:
CAP_SYS_ADMINを持たないプロセスはio_uringを使用不可 - 2:システム全体でio_uringを無効化
# まず値1で非特権ユーザのみ制限(ランタイム適用)
sysctl -w kernel.io_uring_disabled=1
# 確認
sysctl kernel.io_uring_disabled
値1ではデーモンが root または CAP_SYS_ADMIN を持つサービスアカウントで動作している場合は影響を受けません。多くの本番サービスがこのケースに該当するため、値1だけで完全な保護にはなりませんが、「非特権プロセスからのエクスプロイト」に対しては有効な緩和策です。
ステージ3:サービス単位のsystemdフィルタを本番適用する
ステージ1のログでio_uring呼び出しがないことを確認したサービスから順に、SystemCallFilter を drop-in 設定として追加します。/etc/systemd/system/サービス名.service.d/ 以下に設置することで、パッケージアップデートで上書きされるリスクを避けられます。適用後は journalctl -u サービス名 -n 100 でエラーがないかを確認します。
無効化とロールバックの手順
制限適用後にアプリケーションの異常(接続拒否・パフォーマンス劣化・クラッシュ)が確認された場合、次の順で切り戻します。
systemd drop-in の即時無効化
# drop-in ファイルを削除して再読み込み
rm /etc/systemd/system/myapp.service.d/security.conf
systemctl daemon-reload
systemctl restart myapp
削除せず一時的に無効化したい場合は、SystemCallFilter=(空値)を同ファイルに書けばリセットされます。
sysctl パラメータのロールバック
# ランタイムを元に戻す
sysctl -w kernel.io_uring_disabled=0
# /etc/sysctl.d/ に設定を追加していた場合は削除
rm /etc/sysctl.d/99-iouring-disable.conf
sysctl --system
kernel.io_uring_disabled=2(完全無効)は再起動なしにランタイムで0に戻せます。ただし一部カーネルバージョンでは値2から1・0への変更が再起動を必要とするケースが報告されているため、ロールバックをテストしてから本番適用することを推奨します。
カーネルブートオプションによる永続的な無効化
アプリケーションが完全にio_uringに依存していないことが確認できた環境では、カーネルブートオプション io_uring.disabled=1 を追加する方法もあります。GRUBの場合は /etc/default/grub の GRUB_CMDLINE_LINUX に追記し、update-grub(Debian系)または grub2-mkconfig -o /boot/grub2/grub.cfg(RHEL系)で反映します。ブートオプションによる無効化はsysctlより確実ですが、再起動が必要です。
2026年時点のディストリビューション対応差分
io_uringのセキュリティ対応はディストリビューションごとに差があります。運用環境に合わせて確認が必要なポイントをまとめます。
Ubuntu 24.04 LTS / 25.04以降
Ubuntu 24.04 LTS(Noble)はカーネル 6.8 系を搭載し、kernel.io_uring_disabled sysctl が標準で利用可能です。AppArmor プロファイルにio_uring関連の制御が追加されており、Snap コンテナは原則としてio_uringを制限しています。Ubuntu側のセキュリティチームはLandlock LSMとio_uringの統合について継続的に取り組んでいます。
RHEL 9 / AlmaLinux 9 / Rocky Linux 9
RHEL 9 系はカーネル 5.14 ベース(バックポートあり)で、kernel.io_uring_disabled は RHEL 9.2 以降のカーネルアップデートで利用可能です。SELinuxポリシーでio_uringの sqpoll スレッド機能を制限するboolean(allow_io_uring_sqpoll)が提供されています。getsebool -a | grep uring で現在の状態を確認できます。
Debian 12 / 13
Debian 12(Bookworm)はカーネル 6.1 LTSを採用しており、misc cgroupコントローラが標準で有効化されています。Debian 13(Trixie)ではカーネル 6.12 LTSに移行予定で、io_uringの Landlock 連携がより扱いやすくなる見込みです。
コンテナ環境(Kubernetes / containerd)
containerd 1.7以降はデフォルトseccompプロファイル(RuntimeDefault)にio_uring関連syscallのブロックが含まれています。Kubernetes 1.30以降では PodSecurityAdmission の restricted プロファイルが RuntimeDefault seccomp を要求するため、Restricted ポリシーを適用しているNamespaceのPodはio_uringが暗黙的に制限されます。既存クラスタで Baseline ポリシーを使用している場合は、RuntimeDefault seccompを明示的に設定するか、カスタムプロファイルで補完する必要があります。
io_uringのセキュリティ制御は「有効化するか・しないか」の二択ではなく、ワークロードの性質・権限モデル・ディストリビューションの組み合わせで最適な制限レベルが変わります。まずログ収集で依存状況を把握し、段階的に制限を強化していく進め方が、本番環境での影響を最小化するうえで有効です。
「コマンドは打てる。次は”現場で通用する型”を最短で身につけたい」——そんなあなたへ。
ネットの断片的なTipsをコピペするだけでは、体系的な運用スキルはなかなか積み上がりません。リナックスマスター.JPの無料メルマガ「リナマガ」では、現場で実際に使うLinuxサーバー運用の考え方を、順を追って実務目線でお届けしています。いま登録された方には、安全なサーバー構築の「型」をまとめた『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼント中です。
>> 図解60P『Linux入門マニュアル』を無料で受け取る
(メルマガ登録は10秒・いつでも解除OK)
※ 「独学の時間がもったいない」「プロから現場の技術を最短で学びたい」という本気の方には、2日で実務レベルが身につく初心者向けハンズオンセミナーもご用意しています。
PR・広告
ポート・ファイアウォール・権限などサーバ防御の基本をオープンソースで学べる実務書。
※ Amazonのアソシエイトとして、当サイトは適格販売により収入を得ています。
