bokumin.org

RSS Sitemap Mail
ritual-clearcut

PHP2Shell対応でphp83をportsから更新した(FreeBSD)

Updating php83 from ports for PHP2Shell (FreeBSD)

事の発端

2026-10-21に、PHP本体の脆弱性が2件公開されました。通称PHP2Shellと呼ばれているみたいです。修正版も同時にリリースされています。

私の環境では、FreeBSDの公式pkg(quarterly)のphp83 8.3.35をphp-fpmで動かしていて、前段のApacheで複数のサイトを公開しています。

pkgは8.3.35のまま更新されず、いつ追いつくのかも分かりません・・・認証不要のリモートコード実行をWebに公開した状態で、pkgの更新を待つのが個人的に怖かったので、今回応急処置として、portsからソースビルドして更新することにしました。

途中でlldのエラーでビルドが失敗したりとちょっとハマったので、備忘録として残しておきます。
誰かの参考になれば幸いです。

PHP2Shellとは

  • CVE-2026-109618(OOM時の破損)とCVE-2026-109619(解放後に残るグローバル状態)の2件
  • どちらもCVSS v4.0で9.2、認証不要のリモートコード実行
  • 影響するSAPIは、PHP-FPM、Apache mod_php、php-cgi、FrankenPHP、LiteSpeedなど、Webリクエストを処理するもの
  • 修正版は 8.5.12 / 8.4.27 / 8.3.36 / 8.2.35
  • Wizの記述では、CVE-2026-109618はupload-progressのunserializer、CVE-2026-109619はOPcacheのtype confusionが関係しているとのこと
  • PHP 8.1以前は本家の通常サポート外(7.4 / 8.0 / 8.1向けにソースのバックポートが別途公開されています)

悪用状況は情報源によって差があります。今のところ、侵害の確認は報告されておらず、Cisco PSIRTは悪用を把握していないとしていました。一方でCISAは、即時の更新を強く求めているようです。

作業環境

  • FreeBSD 14.5-RELEASE-p3 amd64
  • pkgリポジトリ FreeBSD:14:amd64/quarterly
  • PHP 8.3.35
  • php-fpm(前段はApache、複数サイトを公開)
  • インストール済み拡張: curl, gd, mbstring, mysqli, opcache, pdo, pdo_mysql, session, xml, zip
  • PECLなどは入っていない
  • ビルドオプション(更新前): CGI / CLI / DTRACE / EMBED / FPM / IPV6 / LINKTHR / MYSQLND / PCRE = on、DEBUG / NOASLR / PHPDBG / ZTS = off

FreeBSDでの扱い

前提として、PHPはFreeBSDのbaseには含まれず、Ports / pkg(lang/php8x)で配布されています。そのため、FreeBSD-SAは出ません。

脆弱性情報はVuXML(pkg audit)で扱われますが、私が確認した10/22 朝8時の時点では、PHP2Shellに該当するエントリは見当たりませんでした。
pkg auditだけに頼っていると気づけないので、注意が必要です。

作業開始時点(10/22 8:30)のportsの状況は次のとおりでした。

  • php85: 修正版は8.5.12。portsは更新済み(10/21 13:40 UTC)、pkgは8.5.11
  • php84: 修正版は8.4.27。portsは8.4.26_1のまま未更新、pkgは8.4.26
  • php83: 修正版は8.3.36。portsは更新済み(10/21 13:39 UTC)、pkgは8.3.35
  • php82: 修正版は8.2.35。portsは更新済み(10/21 13:39 UTC)、pkgは8.2.34

補足です。

  • php81は2025-12-31にSunset(portsから削除)済み
  • php82はdeprecated(EOL 2026-12-31)ですが、今回の修正版は出ている
  • デフォルトのPHPは2026-09-28に8.4から8.5に変更された(UPDATING)

やったこと

  1. pkgを待たず、portsからビルドする
    • 公式pkg(quarterly)は8.3.35のままで、更新時期が不明だった
    • Webに公開していて、認証不要のRCEなので、待つリスクのほうが大きいと判断した
  2. portsはmainではなく、2026Q4ブランチを使う
    • mainはquarterlyのpkgより新しい依存を要求することがある
    • quarterlyブランチなら、今入っているパッケージと整合する(php83-8.3.36_1を確認)
  3. 拡張も同じバージョンに揃える
    • 特にopcacheとsessionは更新必須とした

実行手順

事前確認

まず、今の状態とリポジトリ側の状態を確認します。

php -v                                         # 8.3.35 を確認
pkg info -x php8
pkg update
pkg rquery '%n-%v' php83 php83-opcache         # リポジトリは 8.3.35 のまま
pkg -vv | grep -E 'FreeBSD:|url'               # quarterly を使用
pkg query -g '%o' 'php83-*'                    # 拡張の一覧
pkg query '%o %n-%v' | grep -Ei 'php|pecl'     # PECL 系はなし
Bash

portsツリーをquarterlyブランチに切り替え

git -C /usr/ports fetch --depth 1 origin 2026Q4
git -C /usr/ports checkout 2026Q4
make -C /usr/ports/lang/php83 -V PKGNAME        # php83-8.3.36_1とでたらOK
pkg info -f php83 | grep -A15 -i options        # 現行pkgのオプション
make -C /usr/ports/lang/php83 showconfig        # portsのオプション確認
Bash

make -V PKGNAME で期待したバージョンが出るかどうかは、必ず確認するようにしましょう。

ビルドと入れ替え

reinstall は先にdeinstallしてから入れ直す動きなので、ビルドに失敗するとPHP自体が消えてしまいます。そのため、先に clean build でビルドだけを済ませて、成功してからインストールしています。

make -C /usr/ports/lang/php83 install-missing-packages
make -C /usr/ports/lang/php83 config            # DTRACE のチェックを外す
make -C /usr/ports/lang/php83 clean build       # ビルド
make -C /usr/ports/lang/php83 reinstall clean   # 再インストール

# 拡張パッケージも同様に
for o in $(pkg query -g '%o' 'php83-*'); do
  make -C /usr/ports/$o clean build             
done
for o in $(pkg query -g '%o' 'php83-*'); do
  make -C /usr/ports/$o reinstall clean       
done
Bash

起動前の確認と再起動

再起動する前に、設定のテストをしておきます。

$ php -v                  
PHP 8.3.36 (cli) (built: Oct 22 2026 09:34:41) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.36, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.36, Copyright (c), by Zend Technologies
    
    
$ php -m
[PHP Modules]
Core
curl
.
.
.
xml
Zend OPcache
zip

[Zend Modules]
Zend OPcache


$ sudo php-fpm -t         
[22-Oct-2026 11:59:18] NOTICE: configuration file /usr/local/etc/php-fpm.conf test is successful

$ sudo service php_fpm restart
Bash

ハマったこと

ビルドがlldのエラーで失敗した

ld.lld: error: Zend/.libs/zend_dtrace.d.o requires an executable stack, but -z execstack is not specified
Bash

DTRACEオプションが生成するオブジェクトを、lldが拒否していると見られます。ただしこれは推測で、同一の報告は確認できていません。

make config でDTRACEを外してビルドしたところ、成功しました。

-z execstack を指定する回避策もありそうですが、スタックが実行可能になって堅牢性が下がるので、使いませんでした。

なお、ログに出ていた MAKE_JOBS_UNSAFE=yes のヒントは汎用メッセージで、今回の原因とは無関係でした。


以下作業終了後の状態です。

  • php -v(CLI): PHP 8.3.36(built: Oct 22 2026 09:34:41)、OPcache 8.3.36
  • php-fpm -v: PHP 8.3.36(fpm-fcgi)、OPcache 8.3.36
  • php-fpm -t: test is successful
  • php-fpm: 起動確認済
  • ビルドオプション: DTRACE=off

/usr/local/etc/php/ にある ext-20-filter.ini と ext-20-phar.ini は、どのパッケージにも属さない古いファイルでした。php -v に警告は出ていないので、放置で問題なさそうです。

脆弱な状態で公開していた期間は、おおよそ10/21夜の修正版公開から、10/22朝の更新完了までです。

修正後の確認事項

侵害の有無の確認

修正版の公開から更新完了までは脆弱な状態だったので、念のため確認します。

find /usr/local/www/apache24/data -name '*.php' -mtime -3 -ls
Bash

更新した覚えのない場所のファイルや、uploads配下の .php がないかを見ます。今のところは問題ないようですが、Apacheのアクセスログで、身に覚えのないPOSTの急増がないかも確認する予定です。

新しいハードメモリ上限

今回の修正で新しいハードメモリ上限が加わり、到達するとプロセスが終了して、shutdownハンドラが実行されないとのことです。memory_limit と post_max_size が、アプリの要件に合っているかを見直そうと思います。

まとめ

やったこと自体は、portsを2026Q4ブランチに切り替えて、DTRACEを外してphp83と拡張を入れ直しただけです。

また、pkg auditに出ない段階でも深刻な脆弱性が公開されることがある、というのも改めて実感しました。VuXMLを待たずに、本家の情報とportsの更新状況を直接見に行く必要があります。

make reinstallは、先にdeinstallするので、ビルドに失敗すると(今回の場合はphpが)消えてしまうので、先にclean buildでビルドを済ませてからやるのが安全かと思います。

また、ZFS環境なら作業前にsnapshotを取っておけば色々あっても安心です。
今回のようなアップグレードの場合、PHPのコアだけではなく、拡張(opcacheやsession)も同じバージョンに揃える必要があるので、環境ごとに確認をしましょう。


今後は、memory_limitまわりの見直しが残っているので、ぼちぼちやっていこうと思います。

参考にした記事

おわり