tsutsuiの作業記録置き場

NetBSDとかPC-6001とかの作業記録のうち、Twitterの140字では収まらない内容や記事としてまとめるべき内容をとりあえず置いてみる予定

NetBSD と Adobe Flash Player の思い出

このアゴアニキさんのツイートを見て、やっぱりクリエイターと呼ばれる方々には Flash そのものに思い入れがある方も多いのだろうなあ、と感慨深く思ってしまったのを機会に、 NetBSD と pkgsrc で 5年以上 adobe-flash-player のプラグインパッケージをメンテしてきた思い出(?)についてつらつら書いてみようと思います。

Adobe Flash Player について

記事の導入で困ったときには Wikipedia、ということで Adobe Flash のページから引用すると

Adobe Flash(アドビ・フラッシュ)は、かつてアドビが開発していた動画ゲームなどを扱うための規格、およびそれを作成・動作させるアプリケーション群。

とサラッと書いてあります。

かつては、先頭に貼った「ダブルラリアット」の動画のように Flash ならではの機能を使って「止めても動く」といったギミックを組み込んだ作品やゲームも多数ありました。ただ、 HTML5 による動画再生が当たり前となった今とは違い、 2010年頃の時代を振り返るとYouTube を始めとする動画サイトでの動画視聴をするだけでも Flash が必須」という状況だったかと思います。

NetBSD における Adobe Flash プラグインバイナリ

前身の Netscape から Firefoxオープンソース化されて NetBSD などというマイナーOS上でもネイティブアプリとしてビルドできるようになったのはいつなのかをログで漁ってみると、 2004年 3月に firefox-0.8 がインポートされたのが最初のようです。その後も順調にアップデートされていたようですが、私自身が pkgsrc の firefox を使うようになったのは 2009年頃、 firefox のバージョンでいえば 3.5.x の頃のようです。

過去のツイートを探すと、 2010年には NetBSD 上から YouTubeNetBSD動画の投稿もしていて pkgsrc の adobe-flash-plugin (当時) を使って動画再生もしていたようです。 Flash のバージョンは 9 もしくは 10 という時代。

2011年になると adobe-flash-plugin もバージョン 11 になってそれを使っていたようです。

GD-ROMドライブの駆動音動画はこちら

Firefox は前述の通りオープンソース化されていましたが、 Adobe製の Flash player は知っての通りいわゆるプロプライエタリバイナリで、利用にあたっては Adobe が配布しているバイナリをダウンロードする必要があります。かつては Solaris のようなマイナー(?) OS用のバイナリが配布されていたこともありますが、 BSD系OS については NetBSD は当然(?)として FreeBSD用についてもバイナリは一切用意されていない状態で、存在するのは Windows用、 MacOS用、そして x86Linux用のバイナリのみという状態でした。

その状態でどうやって NetBSD上で flash player を動かしていたのか、というのがこの記事の本題の nspluginwrapper (リンクは archive.orgアーカイブ) というツールです。

Adobe Flash プラグインnspluginwrapper

Adobe から提供される Flash Player のバイナリは libflashpler.so というダイナミックリンクライブラリと同様の shared object 形式になっています。

% file libflashplayer.so
libflashplayer.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, BuildID[sha1]=(略), stripped

つまり、 libflashpler.soLinuxネイティブバイナリであり、これをプラグインとしてロードできるのは ABIが共通である LinuxFirefox のネイティブバイナリのみ、ということになります。

nspluginwrapper の原理

Linux用バイナリしか提供されていない Flash プラグインバイナリを Linux以外のブラウザでも動かすことはできないか、ということを目的として開発されたのが nspluginwrapper です。 nspluginwrapper は「多くのOSが Linuxバイナリエミュレーションレイヤーを持っており Linuxバイナリを実行可能である」というところに着目して、以下の図のような原理で Linux バイナリである libflashplayer.so を動作させます。

  1. Firefox本体バイナリ用のプラグインとして nspluginwrapper が提供する仲介用プラグイン (npwrapper.libflashplayer.so)を用意する
  2. npwrapper.libflashplayer.soFirefox から起動されると、 nspluginwrapper パッケージとして用意される Linuxバイナリの npviewer.bin バイナリを npviewer スクリプト経由で起動する
  3. npviewer.bin バイナリは Adobe から配布される libflashplayer.so バイナリを使用して Flash 再生を実行する
  4. npviewer.bin バイナリと Firefox プラグインとして動作している npwrapper.libflashplayer.so がプロセス間通信を使用して再生結果をブラウザに伝達する

ネイティブ実行と比較すると途中にプロセス間通信が入るため描画速度といった性能面では不利ですが、とりあえず当時の動画サイズであれば視聴に支障のない程度の速度は出ていました。

nspluginwrapper の開発経緯

nspluginwrapper のもともとの開発動機は BSD系OSで Flash Player を動かすことではなく、開発元のページにあるように「64ビットの x86_64 Linux用ブラウザで 32ビットの x86 Linux用の libflashplayer.so バイナリを使用する」ためでした。前述の図で「NetBSDバイナリ」の部分を「64ビット Linuxバイナリ」に、「Linuxバイナリ」の部分を「32ビット Linuxバイナリ」に置き換えて、64ビット Linuxが 32ビットバイナリを実行できることを含めればコンセプトはほぼ同じであることがわかるかと思います。

この 64ビット Linuxのために開発された nspluginwrapper を、 FreeBSDNetBSD といった他OSでのユーザーが応用して自分たちの OSでも Flash 再生を可能にするために利用した、というのが正確なところです。

余談ですが、BSD系OSのカーネルの持つ Linuxバイナリエミュレーションに限らず、何らかの手段で「Linux用の libflashplayer.so を実行する」ことさえできれば、どんなOSでも同様のしくみで Flash 再生が可能であるといえます。 nspluginwrapper のドキュメントには「QEMUのユーザーバイナリ実行機能を使って Flash を動かす方法」についても言及されていましたが、実際には実行速度の問題でかなりキツいのではないかと思います。

私と Adobe Flash Player

ここまでは単に「一ユーザーとして pkgsrc の firefox, nspluginwrapper, adobe-flash-plugin を使っていた」というだけでした。YouTube の視聴についても、当時は Flash Player 互換プロジェクトとして作成されていた gnash でもある程度動いていたこともあり、2012年のオープンソースカンファレンス北海道で発表した NetBSD用 Live Image でも gnash を組み込んでいたくらいで、 Flash Player についてはたまに使う程度でした。それが 2015年頃から一転して pkgsrc の adobe-flash-plugin および nspluginwrapper のメンテをするようになったのはなぜなのか、というところから書いてみようと思います。

ニコニコ動画Flash Player

Flash を多用するようになったきっかけといっても大したことではなく、単に 2014年の夏頃からニコニコ動画をよく見るようになった、というところからです。ちょうどこの頃に個人的な環境変化もあり精神的にキツい状況に置かれていたのですが、ニコ動にアップされている「UP主のエネルギーがこれでもか投入された動画」「人間の可能性を知らしめる動画」を見て精神の安寧を保つ、という時期が続いていました。その頃に元気をもらった動画のうち、今でも印象に残っているものを挙げると以下の 2つでしょうか。

まあ、特定の動画が問題だったというわけではなく、単に再生する回数が増えたせいで nspluginwrapper もしくは Flash プラグインバイナリが落ちることが多くなり、それが日に日に気になってどうにかしたいと思うようになった、というのが実際のところです。

nspluginwrapper のバージョンアップ問題

本家の nspluginwrapper のリリースは 2011年6月に出た 1.4.4 が最後で、 github のコミットも 2011年12月29日を最後に行われていません。

一方、 pkgsrc の nspluginwrapper は 2015年1月時点でも 1.2.2 という 2009年1月リリースのものが使われており 1.4.4 どころか 1.3.0 へのバージョンアップも行われていない状態でした。これは単にメンテナ不在で更新が止まっていたわけではなく、 1.3.0以降のバイナリがうまく動いていないということのようでした。

とりあえず適当に pkgsrc/www/nspluginwrapper の中身を 1.4.4 に更新してみたところ、確かに RPCまわりのエラーメッセージがいろいろ出て動かないようでした。が、そのメッセージでググってみると、実はすでに関連するバグレポが出ているということが判明しました。

Linux anonymous socket

上述の PR/47208 の Probrem Report に
a hack to work around the usage of anonymous sockets in the linux npviewer.bin binary
とあるとおり、 nspluginwrapper 1.3.0 以降では Linux バイナリの npviewer.bin 側が Linux 固有の anonymous socket というものを使うように変更されており、通信相手の NetBSDプラグインバイナリもそれに対応する必要がある、ということのようでした。この問題に対し、 PR/47208 のパッチでは以下のような対処をしていました。

  1. Linux の anonymous socket を処理するための専用の bind() 関数を実装する
  2. その bind() を実装したバイナリを libnoanonsocket.so として nspluginwrapper のパッケージに含める
  3. libc 内の bind(2) を差し替えるために、プラグイン用バイナリ起動の npviewer.sh のスクリプトで LD_PRELOAD=${NPW_VIEWER_DIR}/libnoanonsocket.so を指定する
具体的な説明差分はこちら

確かにこの対処で Flash プラグインは動くようにはなったのですが、以下のような課題がありコミットはしづらい状態でした。

結局、以下が正解かと思いつつ、ビルド用の Linux環境を用意するのが面倒で一時的に止まってしまいました。

OpenSUSE 環境整備

2周間ほど経過した後に再度トライ。

ビルド環境の整備というかビルドに必要なパッケージの設定に手間取ったように記憶していますが、YaSTその他のパッケージ設定については本題でないので省略。いろいろ調べた結果として、 nspluginwrapper のビルド時の configure のオプションで --enable-generic を指定すれば anonymous socket ではなく従来通り generic(?) な socket を使うものがビルドでき、こうして作ったバイナリは NetBSD 上でも動作することが確認できました。

bind(3) は間違いで bind(2) が正解ですね

x86_64 64ビット対応

ここまでいろいろ調べた結果として、前述したとおり nspluginwrapper の開発目的が「64ビット LinuxFirefox バイナリで 32ビットの libflashsupport.soプラグインバイナリを使用する」ためである、ということがなんとなくわかってきました。また、2015年時点ではすでに 64ビット Linux 用の libflashsupport.soプラグインバイナリもリリースされており、 nspluginwrapper の Linux における開発動機はほぼ失われてしまっているということもわかりました。

一方、 64ビット Linux用の libflashsupport.soプラグインバイナリが存在するということは、従来は COMPAT_LINUX32 の 32ビット Linuxバイナリエミュレーションを使用していた NetBSD/amd64 でも 64ビットの libflashsupport.so が使えるのでは? ということも考えられました。

いろいろ調べた結果、 64ビットの OpenSUSE 12.1 上で以下のようにビルドすれば 32ビットの i386版同様で amd64 でも 64ビットの libflashsupport.so を使って Flash 再生も動くことが確認できました。

この "--disable-biarch" のオプションが分かりづらかったところで、 64ビット環境だとデフォルトで「32ビットのプラグインバイナリを動かすためのバイナリ」も同時に作られてしまう、ということのようでした。 "--disable-biarch" を指定すれば 32ビット版同様で 64ビット版プラグインバイナリ実行に必要なバイナリのみが作成されます。

さらなる不安定問題

pkgsrc でバイナリファイルを直接使用している事例についても確認し、「64ビットバイナリでも動く」という明確なメリットがあれば自前でビルドした nspluginwrapper バイナリを使うのも許されるだろう、と思って github 作業ファイルベースでコミットの準備を進めました。しかし、 firefox 35.0 が出た頃に確認したところ 1.2.2 と比べて微妙に動作が不安定な部分があるのがわかってきました。

従来の nspluginwrapper 1.2.2 だとこの現象は起きないようだったのですが、それはそれで従来どおり「おもむろに落ちている」という現象が復活してしまいます。

解決へ

この微妙な現象の問題の原因がわからずコミットもできないままだったのですが、3か月ほど経過した後にたまたまソースを確認してふと試したところ、原因らしきものが判明しました。

ここまでの nspluginwrapper 1.4.4 対応についてまとめたのが以下のツイート。

コミットまで

詳細は省略しますが、 Flash 再生において pulseaudio ではなく oss を使用するための libflashsupport パッケージについても 64ビット版バイナリを作成してようやくコミットできる動作になりつつありました。しかし、この libflushsupport バイナリのバージョン番号をどう扱うか、および、自前ビルドの Linuxバイナリを使用することの是非の相談を pkgsrc-bugs のメーリングリストに投げたところ誰からも返事をもらえず、自分自身も忙しかったのもあってさらに時間がかかることになってしまいました。バイナリにサインしろとか言われたらやる気なくしそうだった

64ビット版バイナリでは pulseaudio を使う設定では動作せず libflashsupport バイナリを使った oss 設定でしか動作しないという問題が残ったままという懸念もあり、結局コミットしたのは pkgsrc-2015Q3 が出た後の 2015年10月も終わりに近づいた頃でした。事前の pkgsrc-bugs のメールでは賛成意見も反対意見も出なかったので、バイク小屋議論を避けるためと未来の自分のためにやたらくどく書いたコミットログがこちら

Log Message:
Update nspluginwrapper-1.4.4.

pkgsrc changes:
- use private Linux npviewer.bin binaries built by me (tsutsui@) on
openSUSE 12.1 on 32 bit (i386) and 64 bit (x86_64) on VirtualBox
- enable EMUL_PLATFORMS=linux-x86_64 using the native 64 bit Linux
npviewer.bin binary, which allows using 64 bit native adobe-flash-plugin
on NetBSD/amd64 hosts
- also explicitly set EMUL_REQD= suse>=12.1 (NetBSD 6.x can use it anyway)
- tweak some pkgsrc ${PREFIX}
- update HOMEPAGE
- take maintainership

Note:
- major Linux distributions provided nspluginwrapper binaries to use
the 32 bit plugin binaries without sources on their 64 bit systems,
so there is no 64 bit wrapper binary (npviewer.bin) to use native 64 bit
plugin binaries on other systems (like NetBSD) via binary emulation
- nowadays adobe provides 64 bit native adobe-flash-plugin11 binaries
and NPAPI plugins are being deprecated by vendors, so I guess there is
very few motivation to update nspluginwrapper project for Linux people
http://nspluginwrapper.org/why.html
- Linux binaries in distfiles are built with following changes to
make npviewer.bin works on non-Linux hosts:
- configure with the following options, to enable "generic" RPC calls
(The default Linux native binaries use their specific "anonymous socket")
- for i386:
% ./configure --enable-generic
- for x86_64:
% ./configure --target-cpu=x86_64 --disable-biarch --enable-generic --enable-viewer --enable-player
- disable USE_NPIDENTIFIER_CACHE in npviewer (as patch-src_npw-viewer.c),
which doesn't seems tested with the "generic" RPC interfaces

OK from abs@, and no particular objection to PR pkg/49705 and pkgsrc-users@.
Also thanks to Onno van der Linden for his first analysis about
newer nspluginwrapper APIs in PR pkg/47208.

このスピード感の無さが NetBSD の悪いところというか、ユーザーの需要関係なく開発者側が思う存分考えて納得できるところまでやるというのは良くも悪くも伝統かな、などと思ったりはします。結局、 Flash のサポートが終了する今日までこのときのバイナリが使われ続けることになりました。
実際に使っていた人がどれくらいいたのかは定かではありません

pkgsrc と Adobe Flash Player その後

ここまでで書いたように「プロプライエタリLinuxバイナリとネイティブバイナリを組み合わせて使う」という目的の実現のために多くの知恵と技術が詰まっていることに感銘を受けたこと、そして実際にそうして作られたソフトを日常生活でも毎日のように使って満足している、というところが 2020年になっても pkgsrc の adobe-flash-player の更新とメンテを続けてきた理由だったりします。

ここからは、 2015年以降 Flash Player の NetBSD対応で発生した技術的な問題と対処について思いつくまま書いていきたいと思います。

Adobe Flash Player 11.2 と NPAPI プラグインサポート

私が adobe-flash-player に積極的に関わるようになる前の 2012年 2月の Flash Player 11.2 のリリースの時点で、 LinuxFirefox 向けの NPAPI プラグインのサポートについて以下のようなアナウンスが出されていました。

  • Flash Player 11.2 以降は NPAPI版プラグインはサポートされない
    (Chrome向けの PPAPI版プラグインのみのリリースとなる)
  • Flash Player 11.2 は今後 5年間 (≒2017年2月) はサポートされる

つまり、 pkgsrc に nspluginwrapper 1.4.4 をコミットした 2015年10月時点では LinuxFirefox (つまり NetBSDFirefox) の Flash サポートは残り 1年ちょっと、という状況でした。

NPAPI版サポート終了に伴う Linux界隈の対応の一つとしては「サポートの続いている PPAPI版プラグインに NPAPIの wrapper を被せる」という freshplayer というプロジェクトが存在しました (一応 2020年にもコミットは行われているようです)。原理としては nspluginwrapper でやっていることと同様ですが、 Linux用の freshplayer を NetBSD (およびそれ以外のOS) に対応させるには、自分の能力ではちょっと難しいかなという感じで、考えるだけで何もしないまま年月が経過していく状態でした。

NPAPI サポート延長と Flash Player 23 動作確認

そんな中、2016年9月になって「Adobe が Linux向け NPAPI版 Flash Player の開発を継続する」というニュースが飛び込んできました (zdnetの関連日本語記事)Flash Player 23 のページには実際に NPAPI版の Linux用ベータ版バイナリがリリースされていました。早速 NetBSD + nspluginwrapper でもテストしてみたのですが、やはりというかなんというか素直には動いてくれませんでした。

ここで困ったのは「NetBSD 上で Linuxバイナリエミュレーションを使って動くバイナリをデバッグする良い方法がない」ということでした。通常バイナリがクラッシュした際に使うのは gdb ですが、 gdb は各OS別のバイナリ形式の情報がコンフィグされており、 NetBSD/i386 用にビルドされた gdbLinux の ELFバイナリを認識してくれません。かといって Linux 用の gdbNetBSD上でむりやり動かしてみるとこちらは NetBSD上で生成された core ファイルを認識してくれません。

唯一思いついて実行できたのは、システムコールのトレースを取る ktrace(1) だけでした。ただ、この記事の前半で書いたように Linuxバイナリの libflashplayer.so を呼び出す npviewer.bin は直接コマンドラインから起動されるわけではないため、 ktrace(1) でトレースを取るには次にような工夫が必要でした。

  1. 上記のツイートの中にあるように npplayer で swf 再生を起動する
  2. 起動してウインドウが出た直後ぐらいで suspend して停止させる
  3. ps(1) コマンドで npviwer.bin が起動していることを確認する
  4. npviewer.bin のプロセスに対して ktrace -p [pid] であタッチする
  5. suspend していた npviwer.bin の実行を再開させる
  6. npviewer.bin がクラッシュして npplayer がプロセス間通信のエラーメッセージが出たら停止
  7. kdump(1) でトレースを確認

とにかくタイミングが厳しいのとウインドウマネージャーの操作が煩雑なので、意味のありそうなログを集めるために何十回も npplayer を起動してだいぶ嫌になった記憶があります……。結局、この 2016年10月までの調査はここまでで中断していました。

Flash Player 11.2 サポート切れ問題

そうこうしているうち、 2016年12月の Flash Player 24 の正式リリースで Flash Player 11.2 はもはやリリースされていないということに気づきました。

Flash Player 24 の NPAPI版プラグインが動くのであれば古い 11.2 を存続させる意味はないので当たり前なのですが、相変わらず NetBSD では動かないようなのでちょっと本腰を入れて調べるハメになりました。

どうにも煮詰まって Flash はもうあきらめるべきか、とも考えていたところ、 FreeBSD の Ports にはすでに Flash Player 24 が入っていることに気が付きました。

FreeBSD で動いているのであれば、システムコールの新規実装といった難しい修正は要らないはずです。とりあえず両者の COMPAT_LINUX 関連のソースを見比べてみたのですが、さすがに NetBSDFreeBSD とでは差分が大きすぎてよくわかりません。そもそもどこで落ちているのかも定かではないので、問題の有りそうな箇所を見つけることはできませんでした。

ただ、これだけ材料がそろってきたので、一度 pkgsrc-users@ のメーリングリスト相談メールを投げてみることにしました。するとすぐに NetBSDVM開発の第一人者でもある Chuck Silvers氏から返信をもらえました。しかし、私からの
"Is there any good way to debug Linux binary using compat_linux on NetBSD?"
という質問に対する回答は
"I think the short answer is "no". :-("
となかなか厳しいものでした。

Chuck Silvers 氏は Flash Player 11 のサポートでもカーネルを調べたことがあるとのことだったので、事前に作っていた adobe-flash-player 24 用の pkgsrc ファイル一式や npplayer を使ったデバッグ手順等々を連絡し、さらに取得していた ktrace のログも送付したところ、別途以下のような連絡を直接もらいました。

  • 実は NetBSD/amd64 -current のカーネルでは Flash Player 24 はそのまま動作する
  • i386 では Linux エミュレーションレイヤのどこかが根本的におかしい
  • /emul/linux/proc/self/maps を参照した後の SIGSEGV ではユーザーアドレス空間の末尾を参照しているが、これはスタック直後にあるカーネルだけが参照できるページテーブルであり、 linux エミュレーションレイヤーのどこかが argv や環境変数の後ろに他何かが存在すると誤って認識している可能性がある
  • スタックの設定を含め変なことになっていないか確認してみる

この返信に対して「何か必要な情報があれば取得するので連絡してくれ」と返したのですが、それを待つまでもなく 1日も経たないうちに「修正をコミットしたので NetBSD/i386 -current でも Flash Player 24 が動くようになった」との返信が。

これにはさすがに驚いて「うひょー!」と声が出てしまいましたが、このときこそがいろいろと調べてきたことが皆の協力で実を結んだ瞬間で、やっててよかったという満足感で頭がいっぱいになった記憶があります。

結局、 Flash Player 24 の動作のために修正が必要だったのはカーネル側の以下の2項目でした。

つまり、 procfs も argv も事前調査から導き出された内容と関連しており、地道な調査でデータを集めることの重要性を改めて実感したときでもありました。こうして 2017年2月末に pkgsrc/multimedia/adobe-flash-player24 のパッケージとしてコミットすることができました。

Flash Player 25 バージョン番号問題

前項の通り pkgsrc/multimedia/adobe-flash-player24 という名前でパッケージをコミットした直後の 2017年3月の Flash Player 月例リリースでちょっとした問題がありました。 11.2 同様に同じバージョン番号が続くだろうという予想に反して「同一 major version で 4か月(4回)リリースしたら major bump する」という従来慣例通りのバージョン更新が行われ、 Flash Player 25 としてリリースされてしまったのです。

リリースノートや実際の動作を見る限りでは major version を挙げるべきような変更は無く、 NetBSD上の動作も特に問題ありませんでした。今後も同様に major version が上がり続けるであろう一方で、 NPAPIサポートの延長が決まったときの経緯からして中身はそれほど変わらないであろうことが予想されたので、 pkgsrc については有識者と相談の上で pkgsrc/multimedia/adobe-flash-player としてバージョン番号を含まない名前でコミットし直すことになりました。

Flash Player 27 における "new feature" 問題

前項の Flash Player 25 の更新の後、 Flash Player 26 の更新では何事もなく、ニコニコ動画HTML5 が進んできてそろそろ惰性でのメンテになってきていました。

と、油断したところで 2017年 9月12日の Flash Player 27 への更新で問題が発生しました。

Security Bulletin の critical 表記に惑わされていたのですが、リリースノートの方を見るとしれっと
In today's scheduled release, we've updated Flash Player and AIR with important bug fixes, security updates, and new features.
などと書かれていて、この udev_has_devtmpfs に関連した何らかの新仕様が入ったようでした。

とりあえず、やれることはやるか、といろいろ調査。

前述の通り udev なるブツのサポートが追加されたことに起因している様子。

思いつくまま、過去に libflushsupport のビルドでいろいろ調べた内容を思い出しながら各種バイナリを作ってみてテスト。

このときの知見がすでにほぼ忘却の彼方という問題

週末作業でいろいろやってみたもののこれといった手がかりはなく、他からの依頼で別マシンのテストをしてたりするとあっという間に 10月になってしまい、手がかりを得られないまま次の 27.0.0.159 が出てしまいました。

が、あれだけ散々調べたのにも関わらず、 27.0.0.159 はあっさり NetBSD/i386 で動作する、という結果に。ま、こういうこともあります。

後からわかったのですが、 Flash Player 27 の初版の 27.0.0.139 は Linux でもディストリビューションによっては問題があったらしいということで、 udev サポート追加に伴うトラブルらしいというオチだったのでした。

NetBSD/amd64 バイナリの pulseaudio 対応問題

前述の Flash Player 27 での udev の問題は一応解決したのですが、これに関連して NetBSD/amd64Flash Player の音が鳴らないという問題が発生しました。これはこのエントリの前半で書いた「NetBSD/amd64Linux の pulseaudio バイナリが正常に動かない」という問題に関連します。

上記のツイートの通り、この問題を調べたのは 2015年の12月頃。その時のツイートをふたたびオレオレ Togetter するとこんな感じ。

ここでの PR は git の Pull Request ではなく Gnats の Problem Report です
再現手順では音源も指定する必要がある

というわけで投げたのが PR/50603 のバグレポート。

そして、1年半後のツイートを改めて整理したオレオレ Togetter はこんな感じ。

オレオレ Togetter もいい加減にしなさいという状態ですが、ついにブログにまとめるときが来たということで……。で、問題はここからで、従来 NetBSD/amd64 で一応鳴っていた OSS 設定でも音が鳴らなくなった、というところ。

いろいろとツイートしていたものの、結局このときも詳細はわからず、 amd64 を普段遣いしていないのもあっていったん保留にしてしまっていました。そして、新たな事実がわかったのは年の変わった 2019年 2月。

いろいろ適当なことをつぶやいていたところ、カーネルオプションとして options DEBUG_LINUX_FUTEX というものがあることがわかったので早速トライ。

というわけで、わかってみれば簡単で、 x86_64 の COMPAT_LINUXシステムコールfutex(2) のうち、 LINUX_FUTEX_LOCK_PILINUX_FUTEX_UNLOCK_PI が実装されていないため、それを使用する Linux の pulseaudio が assert() で落ちている、ということでした。

こうして 2015年12月から 3年以上経過した 2019年 3月になってようやくバグレポートに LINUX_FUTEX_LOCK_PILINUX_FUTEX_UNLOCK_PI の件を追記したところ、早速 NetBSD の主要開発者である Jason Thorpe 氏の手が挙がりました。

ただ、残念ながらというかなんというか、 Jason Thorpe 氏による futex(2) 実装の見直しは現在も thorpej-futex ブランチで作業中で、 Flash の終了に間に合わせることはできませんでした。

2021/1/4 11:34 追記

NetBSD/amd64Flash Player 以外を含む pulseaudio のバイナリを動かす場合、 OpenSUSE 13.1 の pulseaudio パッケージを assert を無効にした状態で作ってそれを使うようにすればエラーメッセージは出るものの音は鳴ってとりあえず動くようです。

rpm パッケージの再作成の詳細については OpenSUSE rpm 等で検索すると出てくるので省略しますが、とりあえずで -DNDEBUG を追加して rpm パッケージを作り直して、それを pkgsrc の pkgsrc/emulators/suse131_pulse のパッケージで使うようにすれば OKだったと思います。ただ、これを pkgsrc 公式に入れるには他の suse パッケージとの整合が取れないこと、 i386 用には公式の rpm で問題ないことから小手先で入れる方法が思いつかず、非公式オレオレ版バイナリのみとしています。

追記ここまで

Fireox 71.0 以降でプラグインが動作しない問題

長々と書いてきましたが、最後がこれ。Firefox 70.0 までは Flash Player バイナリがなんとか動作していたのですが、 71.0 に更新すると動作しなくなってしまいました。

この現象は Flash Player 側の問題では無さそうで、落ちているのは npviewer.binLinuxバイナリではなく、 NetBSDバイナリである firefox 付属のプラグイン関連の plugin-container のバイナリが core を吐いていました。

ただ、 gdb でトレースを取得してみたところで firefox の plugin 実装の詳細がわかっていないとても足も出ないという感じでした。firefox 69 あたりからの plugin 仕様の変更に関係していそうではありましたが、 バグレポートも出したものの結局今日に至るまで他の開発者からの助言を得ることもできず、これ以降の adobe-flash-player パッケージのテストは firefox68 の ESR版を使って行うことになりました。

雑多なおまけ

セキュリティ更新小ネタ

pkgsrc の adobe-flash-player パッケージを毎月のように更新してきたわけですが、 pkgsrc のルールとして「アップストリームのリリースアナウンスをコミットログに転記する」というものがあります。これがまた面倒なのですが、毎月第2火曜もしくは水曜にこれらをチェックするのがほぼ習慣になっていたので、いくつか印象に残っているものをピックアップしてみました。

2017年 6月13日
この Flash Player 26 から Security Bulletin 上での CVE番号表記がサマリからなくなり別表形式になり、 pkgsrc のログに転記しづらくなる
2017年 7月25日
Flash Player の更新と提供が 2020年末で終了することが発表される
2017年10月10日
月例更新で恐らく初めてとなる "This monthly update addresses functionality bugs." と書かれた「月例だけどセキュリティ更新じゃない Security Bulletin」が出る
(この更新はなぜか Security updates 一覧のページに載っていない)
2017年10月16日
セキュリティ更新が無いと思ったら1週間後にゼロデイ (CVE-2017-11292) に対する修正が緊急リリースされる
2017年10月25日
セキュリティ更新でない機能修正に対応する月例外更新
2017年12月12日
Security Bulletin だが "regression that could lead to the unintended reset of the global settings preference file" という「vulnerability じゃない regression だけど CVE番号つけられちゃった」みたいな微妙な修正
2018年 2月 1日
2月の月例更新前に CVE-2018-4878 のゼロデイ攻撃が発表される
(2月の月例リリースも 2月6日に前倒し
2018年10月 9日
月例更新で恐らく2回目となる "not include security fix" と書かれた「月例だけどセキュリティ更新じゃない Security Bulletin」が出る
2018年11月20日
最後(?)の定例外セキュリティ修正となるゼロデイ (CVE-2018-15981) 対応緊急リリース
2018年12月 5日
CVE-2018-15982 のゼロデイ対応による月例予定からの前倒しリリース。
なお、この Flash Player 32 への更新以降 major version が上がらなくなる
2019月 1月 8日
月例更新で恐らく最後の "not include security fix" と書かれた「月例だけどセキュリティ更新じゃない Security Bulletin」が出る
2019年 3月
月例更新でセキュリティ修正が無い場合は Security Bulletin が出ずにリリースノート記載だけになる
2019年 7月・8月
2か月連続のセキュリティ修正無し (初めて?)
2019年10月〜5月
恐らく過去最長のセキュリティ修正無し期間
2020年10月13日
最後のセキュリティ修正となる更新 (Edge, IE 版最終バージョン)
2020年12月 8日
最後の月例更新。
フェードアウトということなのか、11月と12月はリリースノートページの更新がバイナリ公開より半日ほど遅く、コミットログは暫定で記載した

2019年になるとセキュリティ更新のない月が増えてきました。これについては、いよいよ出尽くしてきたということなのか、Flashの終焉が現実的にも見えてきたのでセキュリティ研究者あるいは Bounty Hunter たちのターゲットから外れたということなのか、どちらなのかはわかりません。ただ、20年を超える歴史を持つソフトであるにも関わらず毎月のようにセキュリティホールが見つかるというのは、複雑なソフトウェアにおいて基本設計が如何に重要であるかということを考えさせられる事例ではあります。

libflashplayer.so のバイナリの中身

Adobe が提供している libflashplayer.so のバイナリですが、様々なカーネルバージョンが存在する各種の Linux ディストリビューションに対して単一のバイナリで対応しているというのは一体どうやってビルドしているのだろうか、という疑問を持ったことがあります。

というわけで libflashplayer.so のバイナリの中身を適当に見てみると
GCC: (GNU) 4.3.2 20081105 (Red Hat 4.3.2-7)
という文字列があり、 Red Hat 6 あたりの相当古い環境でビルドされているようです。(Linux は詳しくないので見当外れでも笑ってスルーしてください)

libflashsupport.so のバイナリはライブラリなので関数や変数のシンボル名もそのまま残っているため、 strings(1) コマンドで見るだけでもそこそこ情報を得られたりはします。たとえば、問題解決の中で挙げた Flash Player 26 と 27 の strings(1) の出力の差分を見るとこんな感じです。








ざっと斜め読みしただけでも、 udev の追加、意図したものかどうかよくわからない pulseaudio 関連の追加、さらにはアップデート確認の各国語メッセージが入っていたりして、そこそこ大きな変更である一方、雑に diff リストを見比べられるくらいには変更が少ない、とも言えます。

まあ、これらは情報というかヒントに過ぎず、 NetBSD での Linuxエミュレーションの問題で役に立つかというと、そんなに簡単な話ではないのですけれど。

Flash Player の今後

いくつかのページでも言及されていますが、公式ページにも記載があるとおり、 2021年 1月12日以降は Flash Player のセキュリティ更新がされないだけではなく、 Flash Player 自体の実行がブロックされるようになってしまいます。

ただ、2020年末での Flash Player サポート終了が決定したのは先に書いたとおり 2017年 7月です。では、いつ頃のバイナリから 2021年 1月以降の実行がブロックされるのだろうかとちょっと見てみたところ、2020年2月リリースの 32.0.0.330 であれば 2021年以降も実行可能なようでした。

  • 32.0.0.433 (最後のセキュリティ更新版)
    サポート終了案内ページへのリンク画像表示になる
  • 32.0.0.387
    これもサポート終了案内ページへのリンク画像表示になる
  • 32.0.0.344
    無言で実行されないっぽい?
  • 32.0.0.330
    動作しているっぽい?

今回 Flash は終わりを迎えますが、自分自身が数年間やってきた作業について将来懐かしむことがあるとすれば、このブログエントリとともに古いバイナリを引っ張り出してきて再度感慨に耽りたいと思います。

最後に

このような長文駄文を最後まで読んでいただきありがとうございました!