LinuxのLinux KernelにおけるNULL ポインタデリファレンスに関する脆弱性
タイトル LinuxのLinux KernelにおけるNULL ポインタデリファレンスに関する脆弱性
概要

Linuxカーネルにおいて、以下の脆弱性が修正されました。btrfsのサブボリューム作成時にBTRFS_ROOT_ORPHAN_CLEANUPが設定されていない問題です。最近、破損したdentryを持つサブボリュームが多数観測されています。親ディレクトリのls出力は次のようになります。drwxrwxrwt 1 root root 16 Jan 23 16:49 . drwxr-xr-x 1 root root 24 Jan 23 16:48 .. d????????? ? ? ? ? ? broken_subvol。また、statコマンドも失敗します。この状態では、サブボリュームの削除がENOENTエラーで失敗し、新しいファイルやサブボリュームの上書きを試みるとEEXISTエラーで失敗し、さらにファイルシステムが強制終了してしまいます。dmesgには次のエラーメッセージが記録されています: "could not do orphan cleanup -2"。エラーコード2はENOENTであり、このエラーはbtrfs_orphan_cleanup()の失敗処理経路から発生し、呼び出しスタックはbtrfs_lookup()まで遡ります。詳細な調査により以下のことが明らかになりました。サブボリュームに孤立アイテムは存在しません。サブボリュームは健全であり、半分削除された状態やドロップの進行中ではありません。サブボリュームはかなり前に作成されており、BTRFS_ROOT_ORPHAN_CLEANUPを設定する最初のbtrfs_orphan_cleanup()呼び出しは遅れて行われます。btrfs_orphan_cleanup()失敗後、btrfs_lookup_dentry()が-ENOENTを返し、このためd_splice_alias(NULL, dentry)により負のdentryが生成され、観察された動作が起きています。この問題はdentryキャッシュを破棄することで緩和でき、その後はサブボリュームの削除が正常に可能となります。具体的には、btrfs_lookup()はbtrfs_lookup_dentry()を呼び出し、その中でbtrfs_orphan_cleanup()が実行されてビットBTRFS_ROOT_ORPHAN_CLEANUPを設定しようとしますが、孤立アイテムの検索が失敗し"could not do orphan cleanup -2"を表示します。その結果、inodeはERR_PTR(-ENOENT)となりNULLに変換され、d_splice_alias(NULL, dentry)が負のdentryを返します。btrfs_orphan_cleanup()は一度実行されるとビットを設定するため同じルートで複数回実行されませんが、同時に実行される別の処理の存在が考えられます。孤立ノード削除の典型的なルートはサブボリューム内のルックアップが必要であり、それによりbtrfs_orphan_cleanup()が実行される構造です。重要な観察点として、create_subvol()はd_instantiate_new()を呼び出しますが、BTRFS_ROOT_ORPHAN_CLEANUPビットを設定しません。そのためdentryキャッシュが破棄されると、次のサブボリュームのルックアップ時に初めてbtrfs_orphan_cleanup()が呼ばれ、孤立ノード削除と競合する可能性があります。通常のevict()パスでは親dentryへの参照があるため親のdentryキャッシュの削除は抑制されますが、遅延iputの場合は例外です。ordered extentの作成はinodeにigrab()を呼び出し、ファイルがunlinkされクローズされるとこの参照が残ったままでiput()によりi_countが減少してもイジェクションは発生せず、子dentryが解放されてサブボリュームdentryのd_lockref.countが0となりイジェクト可能になります。これにより書き戻しとunlinkの競合、ルックアップと遅延iputの競合という二つのレースコンディションが発生し、複雑な動作を引き起こします。以上の問題は複数段階のプロセスにより発生し、詳細なダイアグラムで完全な状況が示されています。

想定される影響 当該ソフトウェアが扱う情報について、外部への漏えいは発生しません。 また、当該ソフトウェアが扱う情報について、書き換えは発生しません。 さらに、当該ソフトウェアが完全に停止する可能性があります。 そして、この脆弱性を悪用した攻撃の影響は、他のソフトウェアには及びません。 
対策

リリース情報、またはパッチ情報が公開されています。参考情報を参照して適切な対策を実施してください。

公表日 2026年4月22日0:00
登録日 2026年4月30日11:06
最終更新日 2026年4月30日11:06
CVSS3.0 : 警告
スコア 5.5
ベクター CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H
影響を受けるシステム
Linux
Linux Kernel 2.6.32.19 以上 2.6.33 未満
Linux Kernel 2.6.33 以上 6.1.168 未満
Linux Kernel 6.13 以上 6.18.21 未満
Linux Kernel 6.19 以上 6.19.11 未満
Linux Kernel 6.2 以上 6.6.131 未満
Linux Kernel 6.7 以上 6.12.80 未満
Linux Kernel 7.0
CVE (情報セキュリティ 共通脆弱性識別子)
CWE (共通脆弱性タイプ一覧)
その他
変更履歴
No 変更内容 変更日
1 [2026年04月30日]
  掲載
2026年4月30日11:06

NVD脆弱性情報
CVE-2026-31519
概要

In the Linux kernel, the following vulnerability has been resolved:

btrfs: set BTRFS_ROOT_ORPHAN_CLEANUP during subvol create

We have recently observed a number of subvolumes with broken dentries.
ls-ing the parent dir looks like:

drwxrwxrwt 1 root root 16 Jan 23 16:49 .
drwxr-xr-x 1 root root 24 Jan 23 16:48 ..
d????????? ? ? ? ? ? broken_subvol

and similarly stat-ing the file fails.

In this state, deleting the subvol fails with ENOENT, but attempting to
create a new file or subvol over it errors out with EEXIST and even
aborts the fs. Which leaves us a bit stuck.

dmesg contains a single notable error message reading:
"could not do orphan cleanup -2"

2 is ENOENT and the error comes from the failure handling path of
btrfs_orphan_cleanup(), with the stack leading back up to
btrfs_lookup().

btrfs_lookup
btrfs_lookup_dentry
btrfs_orphan_cleanup // prints that message and returns -ENOENT

After some detailed inspection of the internal state, it became clear
that:
- there are no orphan items for the subvol
- the subvol is otherwise healthy looking, it is not half-deleted or
anything, there is no drop progress, etc.
- the subvol was created a while ago and does the meaningful first
btrfs_orphan_cleanup() call that sets BTRFS_ROOT_ORPHAN_CLEANUP much
later.
- after btrfs_orphan_cleanup() fails, btrfs_lookup_dentry() returns -ENOENT,
which results in a negative dentry for the subvolume via
d_splice_alias(NULL, dentry), leading to the observed behavior. The
bug can be mitigated by dropping the dentry cache, at which point we
can successfully delete the subvolume if we want.

i.e.,
btrfs_lookup()
btrfs_lookup_dentry()
if (!sb_rdonly(inode->vfs_inode)->vfs_inode)
btrfs_orphan_cleanup(sub_root)
test_and_set_bit(BTRFS_ROOT_ORPHAN_CLEANUP)
btrfs_search_slot() // finds orphan item for inode N
...
prints "could not do orphan cleanup -2"
if (inode == ERR_PTR(-ENOENT))
inode = NULL;
return d_splice_alias(NULL, dentry) // NEGATIVE DENTRY for valid subvolume

btrfs_orphan_cleanup() does test_and_set_bit(BTRFS_ROOT_ORPHAN_CLEANUP)
on the root when it runs, so it cannot run more than once on a given
root, so something else must run concurrently. However, the obvious
routes to deleting an orphan when nlinks goes to 0 should not be able to
run without first doing a lookup into the subvolume, which should run
btrfs_orphan_cleanup() and set the bit.

The final important observation is that create_subvol() calls
d_instantiate_new() but does not set BTRFS_ROOT_ORPHAN_CLEANUP, so if
the dentry cache gets dropped, the next lookup into the subvolume will
make a real call into btrfs_orphan_cleanup() for the first time. This
opens up the possibility of concurrently deleting the inode/orphan items
but most typical evict() paths will be holding a reference on the parent
dentry (child dentry holds parent->d_lockref.count via dget in
d_alloc(), released in __dentry_kill()) and prevent the parent from
being removed from the dentry cache.

The one exception is delayed iputs. Ordered extent creation calls
igrab() on the inode. If the file is unlinked and closed while those
refs are held, iput() in __dentry_kill() decrements i_count but does
not trigger eviction (i_count > 0). The child dentry is freed and the
subvol dentry's d_lockref.count drops to 0, making it evictable while
the inode is still alive.

Since there are two races (the race between writeback and unlink and
the race between lookup and delayed iputs), and there are too many moving
parts, the following three diagrams show the complete picture.
(Only the second and third are races)

Phase 1:
Create Subvol in dentry cache without BTRFS_ROOT_ORPHAN_CLEANUP set

btrfs_mksubvol()
lookup_one_len()
__lookup_slow()
d_alloc_parallel()
__d_alloc() // d_lockref.count = 1
create_subvol(dentry)
// doesn't touch the bit..
d_instantiate_new(dentry, inode) // dentry in cache with d_lockref.c
---truncated---

公表日 2026年4月22日23:16
登録日 2026年4月25日4:05
最終更新日 2026年4月29日3:54
影響を受けるソフトウェアの構成
構成1 以上 以下 より上 未満
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 2.6.32.19 2.6.33
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 2.6.33 6.1.168
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.2 6.6.131
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.7 6.12.80
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.13 6.18.21
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 6.19 6.19.11
cpe:2.3:o:linux:linux_kernel:7.0:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:7.0:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:7.0:rc3:*:*:*:*:*:*
関連情報、対策とツール
共通脆弱性一覧