年内でflashのサービスが終了するのでダブルラリアットのswfデータを放流します。もうどのサイトでも見れないけど元データはこんなに綺麗なんですhttps://t.co/oxcKTeht2t
— アゴアニキ (@agoaniki) December 26, 2020
このアゴアニキさんのツイートを見て、やっぱりクリエイターと呼ばれる方々には 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 の頃のようです。
firefox3.5.5をpkgsrcから。動いたと思ったらちょっと使うと読み込みがおかしくなる。DNS lookupまわり? 別の5.0.1マシンでは動いてるから環境依存問題か……挫折 orz
— Izumi Tsutsui (@tsutsuii) November 22, 2009
過去のツイートを探すと、 2010年には NetBSD 上から YouTube に NetBSD動画の投稿もしていて pkgsrc の adobe-flash-plugin (当時) を使って動画再生もしていたようです。 Flash のバージョンは 9 もしくは 10 という時代。
NetBSD/dreamcast with IDE HDD and NE2000 http://www.youtube.com/watch?v=ctxijoP2gqo
— Izumi Tsutsui (@tsutsuii) June 4, 2010
9.x だと YouTube再生できなかった記憶があるようなないような(忘却の彼方
— Izumi Tsutsui (@tsutsuii) December 4, 2010
Suse 10.1 は Flash Player 9.x 使えということか http://www.adobe.com/products/flashplayer/systemreqs/
— Izumi Tsutsui (@tsutsuii) December 4, 2010
2011年になると adobe-flash-plugin もバージョン 11 になってそれを使っていたようです。
Firefox-6.0.2とadobe-flash-plugin-11.0.1.152のYouTube再生で音も問題なく出るぜ、といって聞いているのはGD-ROMドライブの駆動音
— Izumi Tsutsui (@tsutsuii) October 22, 2011
Firefox は前述の通りオープンソース化されていましたが、 Adobe製の Flash player は知っての通りいわゆるプロプライエタリバイナリで、利用にあたっては Adobe が配布しているバイナリをダウンロードする必要があります。かつては Solaris のようなマイナー(?) OS用のバイナリが配布されていたこともありますが、 BSD系OS については NetBSD は当然(?)として FreeBSD用についてもバイナリは一切用意されていない状態で、存在するのは Windows用、 MacOS用、そして x86 の Linux用のバイナリのみという状態でした。
その状態でどうやって 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.so
は Linuxネイティブバイナリであり、これをプラグインとしてロードできるのは ABIが共通である Linux用 Firefox のネイティブバイナリのみ、ということになります。
nspluginwrapper の原理
Linux用バイナリしか提供されていない Flash プラグインバイナリを Linux以外のブラウザでも動かすことはできないか、ということを目的として開発されたのが nspluginwrapper です。 nspluginwrapper は「多くのOSが Linuxバイナリエミュレーションレイヤーを持っており Linuxバイナリを実行可能である」というところに着目して、以下の図のような原理で Linux バイナリである libflashplayer.so
を動作させます。
- Firefox本体バイナリ用のプラグインとして nspluginwrapper が提供する仲介用プラグイン (
npwrapper.libflashplayer.so
)を用意する npwrapper.libflashplayer.so
が Firefox から起動されると、 nspluginwrapper パッケージとして用意される Linuxバイナリのnpviewer.bin
バイナリをnpviewer
スクリプト経由で起動するnpviewer.bin
バイナリは Adobe から配布されるlibflashplayer.so
バイナリを使用して Flash 再生を実行する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 を、 FreeBSD や NetBSD といった他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まわりのエラーメッセージがいろいろ出て動かないようでした。が、そのメッセージでググってみると、実はすでに関連するバグレポが出ているということが判明しました。
nspluginwrapper の新しいのってあるんかな
— Izumi Tsutsui (@tsutsuii) January 24, 2015
→ある https://t.co/TRr7IJ7oPw
動くんかなといろいろ試す
→rpcソケットでいろいろ怒られる
ググる
→すでにPRとパッチがあって動いた時の顔 https://t.co/VbP2JPwZte
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 のパッチでは以下のような対処をしていました。
- Linux の anonymous socket を処理するための専用の
bind()
関数を実装する - その
bind()
を実装したバイナリをlibnoanonsocket.so
として nspluginwrapper のパッケージに含める - libc 内の
bind(2)
を差し替えるために、プラグイン用バイナリ起動のnpviewer.sh
のスクリプトでLD_PRELOAD=${NPW_VIEWER_DIR}/libnoanonsocket.so
を指定する
結論として、
— Izumi Tsutsui (@tsutsuii) January 25, 2015
nspluginwrapper-1.4.4 では Linux 側バイナリが rpc.c 内の USE_ANONYMOUS_SOCKETS が定義された状態でビルドされているので、その差を npw-wrapper.c と bind で吸収する必要がある
ということ?
PR pkg/47208 の pkgsrc/www/nspluginwrapper 1.4.4 の変更の改修 https://t.co/UW5MgJf06d
— Izumi Tsutsui (@tsutsuii) January 25, 2015
結局「元のパッチが何をやっているか解読した」だけで本質は変わらないというオチ(´・ω・`)
確かにこの対処で Flash プラグインは動くようにはなったのですが、以下のような課題がありコミットはしづらい状態でした。
bind(2) を乗っ取って引数の外側を書き換えるというのはちょっとアレという気がするけれど、 Linux の anonymous socket を実装しない限りはどうしようもない? よーわかりません
— Izumi Tsutsui (@tsutsuii) January 25, 2015
うー。NetBSD/amd64 で nspluginwrapper-1.4.4 のパッチを適用しようとすると libnoanonsocket.so だけ 32bitで作る必要がある。理屈上は可能だろうけど configure と Makefile をいじるガッツ無し(´・ω・`)
— Izumi Tsutsui (@tsutsuii) January 25, 2015
とりあえず libnoanonsocket.so だけ i386 のバイナリに差し替えれば動く。
— Izumi Tsutsui (@tsutsuii) January 25, 2015
nspluginwrapper-1.4.4 on NetBSD/amd64 6.1.5 with firefox-34.0.5 and adobe-flash-plugin-11.2.202.438 pic.twitter.com/1cjMmHKLo2
— Izumi Tsutsui (@tsutsuii) January 25, 2015
結局、以下が正解かと思いつつ、ビルド用の Linux環境を用意するのが面倒で一時的に止まってしまいました。
オレオレで anonymous socket 使わない Linux バイナリを作るというのが正解という気もするな……
— Izumi Tsutsui (@tsutsuii) January 27, 2015
なんとなくインストール pic.twitter.com/0e093LvtnT
— Izumi Tsutsui (@tsutsuii) January 31, 2015
GNOME から YaST を起動するための、シンプルな方法です。
— Izumi Tsutsui (@tsutsuii) January 31, 2015
・メインメニューボタンをクリック
メインメニューボタンってどこすか(´・ω・`)
openSUSE 12.1 を入れたので nspluginwrapper 1.4.4 を野良ビルドしようと思ったけれど ビルドできるまでの環境構築に挫折気味である('A`)
— Izumi Tsutsui (@tsutsuii) February 1, 2015
OpenSUSE 環境整備
2周間ほど経過した後に再度トライ。
openSUSE で nspluginwrapper をビルドしてみる件をもう一度見るか、と起動したら emergency mode でしか立ち上がらない状態になっていた(´・ω・`)
— Izumi Tsutsui (@tsutsuii) February 14, 2015
ビルド環境の整備というかビルドに必要なパッケージの設定に手間取ったように記憶していますが、YaSTその他のパッケージ設定については本題でないので省略。いろいろ調べた結果として、 nspluginwrapper のビルド時の configure
のオプションで --enable-generic
を指定すれば anonymous socket ではなく従来通り generic(?) な socket を使うものがビルドでき、こうして作ったバイナリは NetBSD 上でも動作することが確認できました。
ここで結論:nspluginwrapper-1.4.4 でも USE_ANONYMOUS_SOCKETS を定義せずにビルドしたLinuxバイナリを使えば NetBSD側バイナリでは socket まわりのパッチは不要で bind(3) のフックとか必要ない
— Izumi Tsutsui (@tsutsuii) February 14, 2015
bind(3)
は間違いで bind(2)
が正解ですねx86_64 64ビット対応
ここまでいろいろ調べた結果として、前述したとおり nspluginwrapper の開発目的が「64ビット Linux の Firefox バイナリで 32ビットの libflashsupport.so
のプラグインバイナリを使用する」ためである、ということがなんとなくわかってきました。また、2015年時点ではすでに 64ビット Linux 用の libflashsupport.so
のプラグインバイナリもリリースされており、 nspluginwrapper の Linux における開発動機はほぼ失われてしまっているということもわかりました。
一方、 64ビット Linux用の libflashsupport.so
のプラグインバイナリが存在するということは、従来は COMPAT_LINUX32
の 32ビット Linuxバイナリエミュレーションを使用していた NetBSD/amd64 でも 64ビットの libflashsupport.so
が使えるのでは? ということも考えられました。
nspluginwrapper-1.4.4 の x86_64 バイナリも同じように USE_ANONYMOUS_SOCKET 無しで作れば 64bit な adobe-flash-plugin11 のプラグインも使えるのかしらん
— Izumi Tsutsui (@tsutsuii) February 14, 2015
プラグイン側アーキテクチャで npviewer を動かして、ブラウザ側アーキテクチャでは npwrapper.so や npplayer を用意する。なので、 Linuxディストリでは 32bit の npviewer と 64bit の npwrapper.so しかない。
— Izumi Tsutsui (@tsutsuii) 2015年2月16日
で、Linux 用のプラグインを *BSD で動かす場合は 32bit でも 64bitでもプラグイン側アーキテクチャの npviewer が必要だけど、 Linuxディストリには 64bit の npviewer を用意する理由がない。なので自前で作る必要がある。
— Izumi Tsutsui (@tsutsuii) 2015年2月16日
いろいろ調べた結果、 64ビットの OpenSUSE 12.1 上で以下のようにビルドすれば 32ビットの i386版同様で amd64 でも 64ビットの libflashsupport.so
を使って Flash 再生も動くことが確認できました。
nspluginwrapper-1.4.4 configure for x86_64
— Izumi Tsutsui (@tsutsuii) February 14, 2015
./configure --target-cpu=x86_64 --disable-biarch --enable-generic --enable-viewer --enable-player
この "--disable-biarch
" のオプションが分かりづらかったところで、 64ビット環境だとデフォルトで「32ビットのプラグインバイナリを動かすためのバイナリ」も同時に作られてしまう、ということのようでした。 "--disable-biarch
" を指定すれば 32ビット版同様で 64ビット版プラグインバイナリ実行に必要なバイナリのみが作成されます。
さらなる不安定問題
pkgsrc でバイナリファイルを直接使用している事例についても確認し、「64ビットバイナリでも動く」という明確なメリットがあれば自前でビルドした nspluginwrapper バイナリを使うのも許されるだろう、と思って github 作業ファイルベースでコミットの準備を進めました。しかし、 firefox 35.0 が出た頃に確認したところ 1.2.2 と比べて微妙に動作が不安定な部分があるのがわかってきました。
オレオレで作った nspluginwrapper の動きが微妙に変だな(´・ω・`)
— Izumi Tsutsui (@tsutsuii) 2015年4月11日
firefox 35 になってからか オレオレで作った nspluginwrapper 1.4.4 だとニコ動のページ表示が再生はできるけどそれ以外のコメント表示やリンクがおかしくてアレ(´・ω・`)
— Izumi Tsutsui (@tsutsuii) 2015年4月18日
従来の nspluginwrapper 1.2.2 だとこの現象は起きないようだったのですが、それはそれで従来どおり「おもむろに落ちている」という現象が復活してしまいます。
素の nspluginwrapper-1.2.2nb26 だと動くな……
— Izumi Tsutsui (@tsutsuii) 2015年4月18日
うーん。 nspluginwrapper-1.2.2nb26 だと やはりふと見ると npviewer.bin.core ができていてアレ(´・ω・`)
— Izumi Tsutsui (@tsutsuii) 2015年4月18日
解決へ
この微妙な現象の問題の原因がわからずコミットもできないままだったのですが、3か月ほど経過した後にたまたまソースを確認してふと試したところ、原因らしきものが判明しました。
nspluginwrapper 1.4.4 の動きがおかしかった件、
— Izumi Tsutsui (@tsutsuii) 2015年7月8日
NPW_NPRUNTIME_CACHE を無効にするとマトモに動くっぽい? pic.twitter.com/l0u1Nvj3Ow
NetBSD/amd64 7.0_RC1 でも 64bit adobe-flash-plugin11 で動画再生も音声もOK。やれやれ…… pic.twitter.com/srw179oAy8
— Izumi Tsutsui (@tsutsuii) 2015年7月8日
ここまでの nspluginwrapper 1.4.4 対応についてまとめたのが以下のツイート。
現状の pkgsrc の nspluginwrapper は 1.2.2 で、ここから上がらないのは 1.3.0 以降 Linux固有の ANONYMOUS_SOCKET を使うのがデフォルトになり Linux 以外のクライアントでは Linux 配布バイナリが使えないため
— Izumi Tsutsui (@tsutsuii) 2015年7月9日
1.4.4を含む 1.3.0以降の nspluginwrapper でも configure で --enable-generic を指定すれば従来同様の socket API を使うようにできるので、それでLinuxバイナリを作れば 1.4.4以降も NetBSD で使える
— Izumi Tsutsui (@tsutsuii) 2015年7月9日
が、それだと最近の firefox だと ニコ動でボタンが押せない、最大化やサイズ変更ができない、市場の商品が表示されない(一部ちゃんと動く場合もある)という症状が出ていて原因がわからなったんだけど、Linuxバイナリ側で use_cache を無効にすると動くことが昨日判明
— Izumi Tsutsui (@tsutsuii) 2015年7月9日
この辺のキャッシュは 1.2.2 → 1.3.0 の間で追加されているが、そこで同時に BUILD_GENERIC もデフォルトでなくなったので、その組み合わせでのテストがされていないという予想 https://t.co/vJmJcidkAd
— Izumi Tsutsui (@tsutsuii) 2015年7月9日
環境変数で NPW_NPRUNTIME_CACHE=no するとキャッシュを使わないようにできて従来のバイナリでも動いたけど、結局 npw-viewer.c をいじって BUILD_GENERIC だったらキャッシュ無効に修正 https://t.co/LNHGNlK6qe
— Izumi Tsutsui (@tsutsuii) 2015年7月9日
コミットまで
詳細は省略しますが、 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 のリリースの時点で、 Linux用 Firefox 向けの NPAPI プラグインのサポートについて以下のようなアナウンスが出されていました。
- Flash Player 11.2 以降は NPAPI版プラグインはサポートされない
(Chrome向けの PPAPI版プラグインのみのリリースとなる) - Flash Player 11.2 は今後 5年間 (≒2017年2月) はサポートされる
つまり、 pkgsrc に nspluginwrapper 1.4.4 をコミットした 2015年10月時点では Linux版 Firefox (つまり NetBSD版 Firefox) の 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 でもテストしてみたのですが、やはりというかなんというか素直には動いてくれませんでした。
Linux NPAPI Flash Player 23 Beta https://t.co/0oD7h9QJLq + nspluginwrapper-1.4.4 on NetBSD/i386 7.0.1 は動きませんでしたとさ(たぶん wrapper に相当手を入れる必要がある)
— Izumi Tsutsui (@tsutsuii) 2016年9月5日
nspluginwrapper + Linux libflashplayer.so 23 on NetBSD/i386 でのログ。 npviewer.bin が core 吐いて落ちてるっぽいのでログがいまいち役に立たない https://t.co/v2AwiyjfVW
— Izumi Tsutsui (@tsutsuii) 2016年9月17日
ニコ動は adobe-flash-plugin11 で特に困らないのでモチベが上がらないという問題。艦これな人たちがんばれ(怒られる) pic.twitter.com/0GlS4rEtcE
— Izumi Tsutsui (@tsutsuii) 2016年9月17日
nspluginwrapper の npplayer の使い方がやっとわかったので libflashplayer.so 23 のデバッグがちょっとはやりやすくなるかもしれない pic.twitter.com/EsXg6jYqTZ
— Izumi Tsutsui (@tsutsuii) 2016年9月23日
npplayer + libflashplayer 23 でいろいろやっていると 30回に1回くらい 5秒くらいだけ音が流れることがあって謎である
— Izumi Tsutsui (@tsutsuii) 2016年9月24日
何度も試してみると音だけじゃなくて動画も5秒くらい出てた。試行回数により動いたり動かなかったりする、というのは uninitialized ほにゃららが発動しているのだろうか
— Izumi Tsutsui (@tsutsuii) 2016年9月24日
メモ:
— Izumi Tsutsui (@tsutsuii) 2016年9月24日
npplayer の動かし方
1) libflashplayer.so を ~/.mozilla/plugins/ に置く
2) nspluginwrapper -i ~/.mozilla/plugins/libflashplayer.so する
3) /usr/pkg/lib/nspluginwrapper/i386/netbsd/npplayer src=hoge.swf
— Izumi Tsutsui (@tsutsuii) 2016年9月24日
npw-player.c の get_plugin_dirs() に /usr/pkg/lib/netscape/plugins を足すのが正解?
Linux のバイナリというか libc って SIGSEGV で落ちた時シグナルぶっ放す前に /proc/self/maps の中身確認したりするんですかね
— Izumi Tsutsui (@tsutsuii) 2016年9月24日
flash_tree.swf だと何回やっても再生開始までいかないんだけど、 /emul/linux/proc/self/maps を 7回 open して最後に SIGSEGV という ktrace が取れた。やっぱりこのあたりなんかなあ
— Izumi Tsutsui (@tsutsuii) 2016年9月24日
OpenSUSE 13.1 32bit だと Flash Player 23 Beta の libflashplayer.so で nspluginwrapper 1.4.4 の npviewer.bin + npplayer は動く pic.twitter.com/fzkqaRXi0R
— Izumi Tsutsui (@tsutsuii) 2016年10月15日
いまさら試してみたけど NPAPI な Linux版 Flash Player 23 Beta は NetBSD/amd64 でも動かないっぽい。
— Izumi Tsutsui (@tsutsuii) 2016年10月16日
ここで困ったのは「NetBSD 上で Linuxバイナリエミュレーションを使って動くバイナリをデバッグする良い方法がない」ということでした。通常バイナリがクラッシュした際に使うのは gdb ですが、 gdb は各OS別のバイナリ形式の情報がコンフィグされており、 NetBSD/i386 用にビルドされた gdb は Linux の ELFバイナリを認識してくれません。かといって Linux 用の gdb を NetBSD上でむりやり動かしてみるとこちらは NetBSD上で生成された core ファイルを認識してくれません。
唯一思いついて実行できたのは、システムコールのトレースを取る ktrace(1)
だけでした。ただ、この記事の前半で書いたように Linuxバイナリの libflashplayer.so
を呼び出す npviewer.bin
は直接コマンドラインから起動されるわけではないため、 ktrace(1)
でトレースを取るには次にような工夫が必要でした。
- 上記のツイートの中にあるように npplayer で swf 再生を起動する
- 起動してウインドウが出た直後ぐらいで suspend して停止させる
ps(1)
コマンドでnpviwer.bin
が起動していることを確認するnpviewer.bin
のプロセスに対してktrace -p [pid]
でアタッチする- suspend していた
npviwer.bin
の実行を再開させる npviewer.bin
がクラッシュしてnpplayer
がプロセス間通信のエラーメッセージが出たら停止kdump(1)
でトレースを確認
とにかくタイミングが厳しいのとウインドウマネージャーの操作が煩雑なので、意味のありそうなログを集めるために何十回も npplayer
を起動してだいぶ嫌になった記憶があります……。結局、この 2016年10月までの調査はここまでで中断していました。
Flash Player 11.2 サポート切れ問題
そうこうしているうち、 2016年12月の Flash Player 24 の正式リリースで Flash Player 11.2 はもはやリリースされていないということに気づきました。
え。 Linux の Adobe Flash Player 11 のサポート終わってしまったの https://t.co/wz30j8lxG0
— Izumi Tsutsui (@tsutsuii) 2016年12月15日
Flash Player 24 の NPAPI版プラグインが動くのであれば古い 11.2 を存続させる意味はないので当たり前なのですが、相変わらず NetBSD では動かないようなのでちょっと本腰を入れて調べるハメになりました。
Linux の adobe Flash Player 24 NPAPI は NetBSD/i386 7.0.2 ではやっぱり動かないのでかなりつらい感じである
— Izumi Tsutsui (@tsutsuii) 2016年12月15日
ニコ動も今は HTML5プレーヤーがそれなりに動くので、 ~/.asoundrc で ASLA は pulse を使うのをデフォルトにして、 adobe-flash-plugin も pulse 前提で作るようにすべきか……
— Izumi Tsutsui (@tsutsuii) 2017年1月1日
どうにも煮詰まって Flash はもうあきらめるべきか、とも考えていたところ、 FreeBSD の Ports にはすでに Flash Player 24 が入っていることに気が付きました。
FreeBSD ports だと adobe flashplayer 24 で動いているということなのだろうか…… https://t.co/hTT4PHdfxi
— Izumi Tsutsui (@tsutsuii) 2017年2月5日
FreeBSD で動いているのであれば、システムコールの新規実装といった難しい修正は要らないはずです。とりあえず両者の COMPAT_LINUX
関連のソースを見比べてみたのですが、さすがに NetBSD と FreeBSD とでは差分が大きすぎてよくわかりません。そもそもどこで落ちているのかも定かではないので、問題の有りそうな箇所を見つけることはできませんでした。
ただ、これだけ材料がそろってきたので、一度 pkgsrc-users@ のメーリングリストに相談メールを投げてみることにしました。するとすぐに NetBSDの VM開発の第一人者でもある 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 に対して offset を指定した読み出しを可能にする
- 機種共通部 (MI部) の Linux エミュレーションレイヤーの es_arglen (argv のサイズ関連定義) の変更に対し、 amd64 以外で使われる関連マクロの修正が漏れていた
つまり、 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 が進んできてそろそろ惰性でのメンテになってきていました。
pkgsrc の adobe-flash-player のプラグインもニコ動用にメンテしていたという側面があったけれど、今は HTML5版でもあまり困らないので 2020年にはフェードアウトということになりそうである(ニコ生はまだ FLASHのみ?)
— Izumi Tsutsui (@tsutsuii) 2017年8月19日
と、油断したところで 2017年 9月12日の Flash Player 27 への更新で問題が発生しました。
Adobe Flash Player 27.0.0.130 https://t.co/UaolTmZ69a
— Izumi Tsutsui (@tsutsuii) 2017年9月13日
う。 adobe-flash-player 27.0.0.130 だと NetBSD/i386 上で音の再生できなくなっている?
— Izumi Tsutsui (@tsutsuii) 2017年9月14日
libudev: udev_has_devtmpfs: name_to_handle_at on /dev: Function not implemented
— Izumi Tsutsui (@tsutsuii) 2017年9月14日
めんどくさそうな予感(´・ω・`)
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
に関連した何らかの新仕様が入ったようでした。
adobe-flash-player はとりあえず 26.0.0.151 に戻した。どのみちモチベというか必要性が失われてきているので 2020年を待たずにそのうち消滅か……
— Izumi Tsutsui (@tsutsuii) 2017年9月16日
とりあえず、やれることはやるか、といろいろ調査。
落ちるログ https://t.co/340CMRQ4Zu
— Izumi Tsutsui (@tsutsuii) 2017年9月16日
OpenSUSE 1.31 で firefox + adobe flash player 27.0.0.130 を試すとちゃんと動いて音も鳴る。NetBSD/i386 7.1 で動かないのはやはり udev まわりの問題なのか…… pic.twitter.com/Z8pqBW3Zdx
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
flash バイナリの ktrace を取ろうとすると firefox もしくは npplayer から呼び出される npviewer.bin の ktrace を取る必要があるのだけれど、どのタイミングで起動するのかよくわからない上にすぐ落ちるのでどう引っ掛けるのがよいのか
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
前述の通り udev
なるブツのサポートが追加されたことに起因している様子。
あー。NetBSD/i386 7.1 + adobe flash player 27 でもデフォルトの libflashsupport を使って OSS で鳴らせば udev で文句を言われつつも音は鳴る。 pulseaudio で udev を見るようになったということか……
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
OpenSUSE で /dev/shm を見ると
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
/dev/pulse-shm-174546789
等がある。NetBSD上だと pulseaudio はネイティブアプリとして走るので /dev/shm 以下には何も作らない。そもそもデーモンも手動で起動する必要があったりする
これを何とかするには libflashsupport の pulseaudio 用のを復活させるということをすれば行けそうな気はするが、そこまでのモチベが出ないという問題。 NetBSD 8.0 が出たら OSS で困らないしな……
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
思いつくまま、過去に libflushsupport
のビルドでいろいろ調べた内容を思い出しながら各種バイナリを作ってみてテスト。
OSS用に作った libflashsupport.so だと鳴るけれど、 ALSA や PULSEAUDIO で作ると
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
npviewer.bin: pcm.c:2265: snd_pcm_open: Assertion `pcmp && name' failed.
になる。うーん
`pcmp && name' の assert は usr/lib/libasound.so.2 の中のような気がするけれど、ALSA用に作った libflashsupport はともかく PULSEAUDIO 設定で作った libflashsupport でも呼ばれるのだろうか
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
PULSEAUDIOサポートのある libflashsupport はここにある https://t.co/dX768yQeV4
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
OpenSUSE 13.1 では #include <pthread.h> だけ足せばビルドは通る
define OSS で libflashsupport.so を作ると FPX_Init() が呼ばれるけれど define ALSA や define PULSEAUDIO で作った libflashsupport.so だとそもそも FPX_Init() が呼ばれてない?
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
これは単に libflashsupport.so を作る時に -lasound もしくは -lpulse を付けておらず動的リンクに失敗していただけっぽい。 -lpulse つけたら PULSEAUDIO 版でもなんか音は出たけど動きが変なような……
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
ALSA 有効の libflashsupport.so だと結局 snd_pcm_open() の Assert で落ちる。 PULSEAUDIO 有効のだと npplayer は動くときもあるけど firefox はダメ pic.twitter.com/jNrSEo3Wem
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
そもそも Linux でのサウンド再生のしくみは何が標準なのかという話はある。 ALSA が udev 使うようになって pulseaudio もそれに紐付いているとかいう話なら COMPAT_LINUX をそっちの方向で頑張れということになるのか?
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
今回作った PULSEAUDIO版 libflashsupport.so をぶち込んだ OpenSUSE 13.1 では firefox + flash player 27 で普通に音は再生されるっぽい。 pic.twitter.com/7ajOqlznMp
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
なので、結局 NetBSD の COMPAT_LINUX での pulseaudio 再生の問題という感じか。そもそも今までも
— Izumi Tsutsui (@tsutsuii) 2017年9月23日
setsockopt(SOL_SOCKET, SO_PASSCRED): 無効な引数です
とか怒られてたわけだけれど
週末作業でいろいろやってみたもののこれといった手がかりはなく、他からの依頼で別マシンのテストをしてたりするとあっという間に 10月になってしまい、手がかりを得られないまま次の 27.0.0.159 が出てしまいました。
Adobe flash player 27.0.0.159 https://t.co/TipP9Bx6jZ
— Izumi Tsutsui (@tsutsuii) 2017年10月11日
セキュリティ修正がない Security Bulletin とは
が、あれだけ散々調べたのにも関わらず、 27.0.0.159 はあっさり NetBSD/i386 で動作する、という結果に。ま、こういうこともあります。
Adobe flash player 27.0.0.159 だと NetBSD/i386 7.1 + pulseaudio 設定でもちゃんと動くようになっているっぽい。やったね! pic.twitter.com/XAyUqwk1R2
— Izumi Tsutsui (@tsutsuii) 2017年10月11日
adobe flash player 27 の初版 27.0.0.130 は NetBSD に限らずいろいろとおかしかったらしい https://t.co/MEscx79Aqr
— Izumi Tsutsui (@tsutsuii) 2017年10月11日
後からわかったのですが、 Flash Player 27 の初版の 27.0.0.139 は Linux でもディストリビューションによっては問題があったらしいということで、 udev サポート追加に伴うトラブルらしいというオチだったのでした。
NetBSD/amd64 バイナリの pulseaudio 対応問題
前述の Flash Player 27 での udev の問題は一応解決したのですが、これに関連して NetBSD/amd64 で Flash Player の音が鳴らないという問題が発生しました。これはこのエントリの前半で書いた「NetBSD/amd64 で Linux の pulseaudio バイナリが正常に動かない」という問題に関連します。
NetBSD/amd64 7.1 上で COMPAT_LINUX の機能で Linuxバイナリを動かして pulseaudio を使ったサウンド再生すると coredump する問題。これをどうやったらデバッグできるのかという2年以上前からの課題
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
上記のツイートの通り、この問題を調べたのは 2015年の12月頃。その時のツイートをふたたびオレオレ Togetter するとこんな感じ。
NetBSD/i386 7.0 の場合、/usr/pkg/emul/linux/usr/lib/libflashsupport.so を消して ~/.asoundrc で出力先を pulse にすれば pulseaudio で flash 再生の音は普通に鳴る。
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
NetBSD/amd64 7.0 の場合、 /usr/pkg/emul/linux/usr/lib64/libflashsupport.so を消して ~/.asoundrc で pulse 指定すると https://t.co/PiXXT3JbOz のエラーで音が鳴らない
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
NetBSD/amd64 7.0 で alsa-plugin-pulse を入れて .asoundrc で pulse を指定して aplay で再生するとちゃんと pulseaudio 経由で音が鳴る
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
NetBSD/amd64 7.0 で firefox 43.0.2 の YouTube の HTML5 player の音声も pulseaudio 出力で正常に鳴る
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
https://t.co/GDtsPvu0tq から alsa-utils-1.0.27.2-4.5.1.x86_64.rpm を取ってきてその中の usr/bin/aplay を実行すると https://t.co/36QZ8oE0Zp のエラーが再現。これですか
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
https://t.co/fzbflLHCYj の alsa-utils-1.0.27.2-4.5.1.i586.rpm の usr/bin/aplay を NetBSD/i386 7.0 上で実行すると音は鳴る
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
しかし
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
setsockopt(SOL_SOCKET, SO_PASSCRED): Invalid argument
と文句を言われている。これは flash 再生時に出ていたのと同じメッセージ
NetBSD/i386は
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
linux/socket
linux/setsockopt
linux/connect
linux/sockaddr
が呼ばれてて
NetBSD/amd64は
socket
setsockopt
connect
linux/sockaddr
が呼ばれてる
そういうものなのだろうか pic.twitter.com/aYCwnwbhM3
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
NetBSD/i386では futex 成功しているが NetBSD/amd64 では失敗している pic.twitter.com/EeaGEbTGuh
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
再現手順まとめてPR投げるか(´・ω・`)
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
pulseaudio は root では実行できんとか再現手順書く難易度高いよ(´・ω・`)
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
% paplay /usr/pkg/emul/linux/usr/share/sounds/alsa/test.wav
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
思ったより重厚なテストサウンドだった
PR投棄
— Izumi Tsutsui (@tsutsuii) 2015年12月31日
というわけで投げたのが PR/50603 のバグレポート。
そして、1年半後のツイートを改めて整理したオレオレ Togetter はこんな感じ。
NetBSD/i386 7.1 だと Linuxバイナリでの pulseaudio 再生は一応動く(いろいろ警告は出る)ので、問題があるとすれば COMPAT_LINUX のシステムコールエミュレーション部分だとは思うのだけれど、それを検証するのが難しい
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
gdb は Linux のバイナリを解釈しないので使えない。Linux の gdb は NetBSD の core を理解しないのでこれまたデバッグできない。 ktrace だと linux/socket もしくは futex が怪しい感じがするけれど気がするだけ
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
で、aplay(1) で pulseaudio させると Abort で落ちるのだけれど、落ちるところが微妙に変わったりする。システムコールの実装が不完全で一部ゴミを返している、とかあるのだろうか
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
Assertion 'c->defer_event == e' failed at pulsecore/socket-client.c:172, function connect_defer_cb(). Aborting.
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
落ち方その1
Assertion 'pthread_mutex_unlock(&m->mutex) == 0' failed at pulsecore/mutex-posix.c:110, function pa_mutex_unlock(). Aborting
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
落ち方その2
Assertion 'c->callback' failed at pulsecore/socket-client.c:128, function do_call(). Aborting.
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
落ち方その3
ktrace その1 https://t.co/WRydnCv8sO https://t.co/0w8AcrlNqW
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
ktrace その2 https://t.co/qSMGQELMQe https://t.co/PoB2HDFY2t
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
ktrace その3 https://t.co/xlLkWssLa4 https://t.co/u9TjUto27s
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
Assertion 'pthread_mutex_unlock(&m->mutex) == 0' で落ちてる時はほかと比べて進んでいるというか、この怒涛の futex(2) は正常なのか みたいな https://t.co/1Za9mPPnz5
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
(ふと思いついて実行した調査結果を適当につぶやいておいて気が向いたらブログにまとめるかもしれない という手法)
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
で、native バイナリなら NetBSD/amd64 7.1 上で作った alsa 設定の firefox 56.0 で HTML5動画の音はちゃんと鳴る。 pic.twitter.com/3C5HhEtxo0
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
adobe-flash-player だと Linux バイナリなので pulseaudio 経由再生は落ちる。 OSS経由だと鳴るけど
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
オレオレ Togetter もいい加減にしなさいという状態ですが、ついにブログにまとめるときが来たということで……。で、問題はここからで、従来 NetBSD/amd64 で一応鳴っていた OSS 設定でも音が鳴らなくなった、というところ。
あれ? NetBSD/amd64 7.1 + pkgsrc-2017Q3 だと libflashsupport 入れても OSS 使うようにならない? なんでだ
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
半年くらい前に試した時は OSS で鳴ってたはずだけど
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
うーん。aplay は oss で鳴るようになったけど adobe-flash-player は ALSA で pulseaudio 再生しようとする。 libflashsupport.so が無視されてるのだろうか。 i386 だと libflashsupport 呼んでたけど
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
64bit adobe-flash-player 26.0.0.151 だと libflashsupport.so で OSS で鳴る。 27 から挙動が変わっているのか……
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
改めて試してみると、 NetBSD/i386 7.1 だと firefox + adobe-flash-player 27.0.0.170 + libflashsupport で OSS 経由でサウンド再生できる。64ビット版と32ビット版で仕様変わったとかあるのだろうか
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
64bit 版 adobe-flash-player 27.0.0.170 の libflashplayer.so のバイナリの中には
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
libflashsupport.so
FPX_Init
の文字列があるので仕様として呼ばなくなったわけではない?
udev まわりで変わっているので呼び出し条件が変わってるとかあるのだろうか……(amd64 を普段遣いしていないのでいまいちガッツが足りない)
— Izumi Tsutsui (@tsutsuii) 2017年10月24日
この問題、openSUSE 13.1 上だと 64bit環境でも libflashsupport の FPX_Init() は呼ばれている。NetBSD/amd64 7.1 だと FPX_Init() は呼ばれない。これまた難しいことを言う…… https://t.co/dPgFSMdYpy
— Izumi Tsutsui (@tsutsuii) 2017年10月25日
NetBSD/amd64 8.0_BETA の GENERIC カーネルでも Linuxバイナリで pulseaudio 再生できない問題は変わらず(userland は 7.1 のまま)
— Izumi Tsutsui (@tsutsuii) 2017年10月26日
いろいろとツイートしていたものの、結局このときも詳細はわからず、 amd64 を普段遣いしていないのもあっていったん保留にしてしまっていました。そして、新たな事実がわかったのは年の変わった 2019年 2月。
Something wrong in COMPAT_LINUX futex(2) emulation on NetBSD/amd64?
— Izumi Tsutsui (@tsutsuii) 2019年2月16日
(ktrace(1) says it returns "futex -1 errno -38 Too many processes" before the pthread_mutex asssertion in Linux pulseaudio lib, while it works on NetBSD/i386) pic.twitter.com/uFrbOyUtM7
いろいろ適当なことをつぶやいていたところ、カーネルオプションとして options DEBUG_LINUX_FUTEX
というものがあることがわかったので早速トライ。
ok, I'll try a debug kernel with DEBUG_LINUX_FUTEX (I'm not sure why it works on i386)
— Izumi Tsutsui (@tsutsuii) February 16, 2019
Feb 17 05:55:17 optiplex760 /netbsd: linux_do_futex: unknown op 6
— Izumi Tsutsui (@tsutsuii) 2019年2月16日
Feb 17 05:55:17 optiplex760 /netbsd: linux_do_futex: unknown op 7
Unimplemented LINUX_FUTEX_LOCK_PI and LINUX_FUTEX_UNLOCK_PI ...
というわけで、わかってみれば簡単で、 x86_64 の COMPAT_LINUX
のシステムコールの futex(2)
のうち、 LINUX_FUTEX_LOCK_PI
と LINUX_FUTEX_UNLOCK_PI
が実装されていないため、それを使用する Linux の pulseaudio が assert() で落ちている、ということでした。
こうして 2015年12月から 3年以上経過した 2019年 3月になってようやくバグレポートに LINUX_FUTEX_LOCK_PI
と LINUX_FUTEX_UNLOCK_PI
の件を追記したところ、早速 NetBSD の主要開発者である Jason Thorpe 氏の手が挙がりました。
ただ、残念ながらというかなんというか、 Jason Thorpe 氏による futex(2)
実装の見直しは現在も thorpej-futex ブランチで作業中で、 Flash の終了に間に合わせることはできませんでした。
NetBSD/amd64 で Flash Player 以外を含む pulseaudio のバイナリを動かす場合、 OpenSUSE 13.1 の pulseaudio パッケージを assert を無効にした状態で作ってそれを使うようにすればエラーメッセージは出るものの音は鳴ってとりあえず動くようです。
adobe-flash-player 32.0.0.142 (64-bit) on NetBSD/amd64 8.0 (with patched suse131_pulse binary rpm to disable pthread_mutex assertion failures due to possible COMPAT_LINUX bug) pic.twitter.com/iqC7caE5gO
— Izumi Tsutsui (@tsutsuii) 2019年2月14日
メモ:
— Izumi Tsutsui (@tsutsuii) 2019年2月16日
pkgsrc/emulators/suse131_* で必要な openSUSE 13.1 のバイナリ rpm はこのへんhttps://t.co/u96dkpQ0DRhttps://t.co/jSU5QNAxSmhttps://t.co/hkpdMog00Xhttps://t.co/v4zIf1gacw
オレオレパッチ rpm を作る時のソース rpm はこのへんhttps://t.co/ahPjRkJs9Rhttps://t.co/Xwkw9VUFke
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.bin
の Linuxバイナリではなく、 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
動作しているっぽい?
※2021/12/12追記
nspluginwrapper 付属の npplayer を使う場合は 32.0.0.371 でも動作するようです。
追記ここまで
今回 Flash は終わりを迎えますが、自分自身が数年間やってきた作業について将来懐かしむことがあるとすれば、このブログエントリとともに古いバイナリを引っ張り出してきて再度感慨に耽りたいと思います。
最後に
このような長文駄文を最後まで読んでいただきありがとうございました!