SElinuxはミリしらだけどアクセス許可を追加してみた

Posted on

 SELinuxってたまに聞くけど中身は全然知らなかったのですが、今回Fedora 17のChromeでNativeClientが動かなかったので設定することにしました。

SELinuxって何じゃらホイ

 SELinuxって名前は聞いたことあって、セキュリティ系の機能らしいというのは知っているのですが、それ以上のことはよく知りませんでした…。

 というわけで、調べてみました。第1回 セキュアOS機能「SELinux」の基本的な仕組み。ちょっと古い記事ですが、まあ問題ないでしょう。

私の理解したところによると。

 今までの普通のLinuxには、chmodで設定するような、ユーザーやグループを用いたアクセス制御がありますが、この場合は万が一root権限で動くプロセスを奪取されるとすべてにアクセスし放題になってしまってよろしくありません。というわけで、SELinuxではそれとは別にプログラム単位で色々な制限を、ファイルへのアクセス制限だけでなく、もっと色々な行動への制限が掛けられるようになっている…ということみたいです。

 …間違ってたらゴメンネ。例えばhttpdにはネットワーク接続の権限が必要だけど、passwdへのアクセスは要らないから、これを制限しよう、という発想だと理解しました。これをTE(Type-Enforcement)と言うそうです。

 RABCっていう別の仕組みもあるそうですが、今回引っかかったのはTEなのでこちらに話を絞ります

Fedora 17でGoogle ChromeのNative Clientが動かない

 さて。今回引っかかったのはGoogle ChromeのNative Clientです。SDKに入っているexampleを試しに動かしてみましたが…こんな感じで動いてくれません。

 20120825_01.png

 うまく行くとこうなるはずなんですけどー!

20120825_02.png

 で、まずはGoogleで検索してみたのですが、どうやら今回のSELinuxが問題で動かないようになっているようだ、という事が分かりました。

まずは全体を無効にしてみる

 まずは、SELinux全体を無効にしてみました。

% sudo setenforce Permissive

こうすると全体のSELinuxが無効になります。で、この状態でさっきのExampleが綺麗に表示されたので、SELinuxが問題だと分かります。

あとで有効に戻すには次のコマンドを使って下さい。無効にしたままは流石にどうかと思うので…

% sudo setenforce Enforcing

さらに細かい粒度で有効か無効かを調べる

 とりあえずSELinuxの問題であることがわかったので、Chromeのどういうモジュールなのかなあというのを調べるために、プロセスのドメインごとに有効無効を切り替えられるツールを使います

% sudo yum install policycoreutils-gui

20120825_03.png

どうやらChromeにはsandboxとsandbox_naclという2つのドメインが割り当てられているようです(この割り当て自体はFedoraの中の人がやってるようです)。どう考えても後者が怪しいので、Permissiveボタンを押してnaclの方をPermissiveモード(SELinux無効)にしてみると…やっぱり動作しました。これが問題みたいです。

AuditのログからSELinux用のモジュールを作る

 SELinuxを一時的に解除して動くようにしましたが、SELinuxはアクセス制御は行なっていませんが、ログを、Auditdというデーモンのログに記録しています。Fedoraの場合は/var/log/audit/audit.logに入っております。

 このAuditというデーモン、syslogdみたいな感じらしいです。でもSyslogdよりリッチなシステムらしいです。詳しくはLinux Audit 〜OSレベルの監査ログ徹底活用〜が参考になります。

 このログの中で、chrome nacl…といったキーワードを調べていくと、chrome_sandbox_nacl_tというのがnacl関連だと思われるので、それでgrepします。

%sudo grep ":chrome_sandbox_nacl_t:" /var/log/audit/audit.log

 さらにこれでログを抽出した上で、audit2allowというプログラムを用いて、SELinuxでの設定ファイル、モジュールを作る事ができます。

%sudo grep ":chrome_sandbox_nacl_t:" /var/log/audit/audit.log | audit2allow -a -l r
require {
type chrome_sandbox_nacl_t;
type chrome_sandbox_t;
class unix_dgram_socket { read write };
}
#============= chrome_sandbox_nacl_t ==============
allow chrome_sandbox_nacl_t chrome_sandbox_t:unix_dgram_socket { read write };

さらに、-M module名とすると、モジュールのコンパイルもしてくれます。

% sudo grep ":chrome_sandbox_nacl_t:" /var/log/audit/audit.log | audit2allow -a -l -r -M chrome_sandbox_nacl

 で、最後にsemodule -iを使ってインストールします。

% sudo module -i chrome_sandbox_nacl.pp

 以上です。さっきのGUIでnaclだけPermissiveにしていたのを元に戻してEnforcingにしても、ちゃんとnaclが動作するようになるはずです!

モジュールを作らなくても大丈夫な場合もある

 今回はモジュールを作りましたが、正直言って結構大工事でしたね。それ以外にも、getsebool/setseboolで設定できるフラグや、ファイルのタイプを変更する方法でもSELinuxの制限を何とか出来たりもするようです。が、今回は駄目でした。

SELinuxは分かりづらい。

 SELinuxは他のLinuxのデーモンなどと違い、設定ファイルがバイナリにコンパイルされた状態で保存されています。(/etc/selinuc/targetd/以下)。速度が重要な所ですから、多分そのためだとは思うのですが、いまいち分かりづらいです。

 上記で使ったaudit2allowの代わりに、audit2whyというのを使うと制限された理由を教えてくれたりもするようです。

type=AVC msg=audit(1345883976.560:36379): avc:  denied  { read write } for  pid=15643 comm="nacl_helper_boo" path="socket:[667837]" dev="sockfs" ino=667837 scontext=unconfined_u:unconfined_r:chrome_sandbox_nacl_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:chrome_sandbox_t:s0-s0:c0.c1023 tclass=unix_dgram_socket
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.

Missingって…。Fedoraの中の人のミスじゃないかなあ、これ…。

参考にしたところ

差分アップデートを実装したさきゅばす2.0b3を公開しました

Posted on

リリースノート

 コメントの表示時間に関するバグの修正と、前回言っていた差分による自動アップデータを搭載したバージョンを公開します。

 自動アップデートを搭載したので、今後のアップデート作業は大分楽になると思います。とはいえ、最初のバイナリのサイズがまた増えてしまったのですが…。

変更履歴

  • コメントの表示時間がue/shitaと通常コメントで逆になっていた問題を修正しました。
  • 自動アップデータを搭載しました(bazaarを利用しています)
  • FFmpegのバイナリを最新のものに更新しました
  • libxml2とx264を更新しました。

ダウンロード

 いつも通りSourceforgeからどうぞ

 なお、zipと7zは内容は同じです。7zのほうがファイルサイズが小さいので7zが解凍できる人はどうぞ。

自動アップデータの使い方

 Wikiに書いておきました

20120824_01.png

 Bazaarの軽量チェックアウトを使っています。従来のSubversionより容量を使わなかったので急遽乗り換えました。

Chromeではメソッドをオブジェクトに直接入れてはいけない!?

Posted on

 短く言うと:アセンブラっぽく書く オブジェクト指向つかったら負け

 前の記事で書いたJavaScriptのファミコンエミュレータ「CycloaJS」を実装する際に使った最適化の手法について紹介します。

関数呼び出し、避けましょう

 まずはこんな関数から〜。

"use strict";
var TIMES = 100000000;
function Klass(){
	this.val = 0;
	this.add = function(val){
		this.val += val;
	};
}
function doBench() {
	var memory = new Uint8Array(1024*1024);
	log("calling func: "+cycloa.probe.measure(function(){
		var obj = new Klass();
		var i = TIMES;
		while(--i){
			obj.add(i&0xfff);
		}
	}));
	log("not calling func: "+cycloa.probe.measure(function(){
		var obj = new Klass();
		var i = TIMES;
		while(--i){
			obj.val += (i&0xfff);
		}
	}));
}

 cycloa.probe.measureっていうのは、実行時間を測ってミリ秒単位で返してくれるだけのユーティリティ関数です。最初のベンチマークでは変数に足し算する処理をクラスメソッドに移譲していますが、次のベンチマークでは移譲せずに直接書いてます。こんな例だと馬鹿馬鹿しいですが、規模が大きくなると前者みたいな方式の方が見通しがよくなったりするんですよね…。

 これを、Chrome21とFirefox14.0.1を用いてログを取ってみました。

Firefox14.0.01

calling func: 657
not calling func: 289
calling func: 772
not calling func: 284
calling func: 768
not calling func: 293

 関数呼び出しを加えただけでかなり遅くなります。C/C++やJavaのような感覚でgetter/setterなどを作ると一気に遅くなってしまいます。

 今回エミュレータでは、CPUのエミュレーション部分がメモリの読み書きを行う際のメソッドを、すべてコードジェネレータを用いてインライン展開しています。

 

  同様に、その他の通常ならば別のメソッドに分けるような処理も、すべて一つの関数内で行うようにしました。erbを用いて埋め込むなどしてできる限り可読性を下げないようにはしているものの、正直見難くなっているのが実情です…。

Chrome21

calling func: 592
not calling func: 592
calling func: 1327
not calling func: 590
calling func: 1035
not calling func: 587
calling func: 1037
not calling func: 585

 Chromeだと、最初の一回目だと差が出ない(インライン展開でも行なっているのでしょうか?)のですが、二回目以降関数呼び出しバージョンが極端に遅くなります。なぜだろと思ってプロファイラを有効にすると、なぜか差がでなくなってしまいます…。なぜなのかはよく分かりません。試しに、

var obj = new Klass();
function doBench() {
var memory = new Uint8Array(1024*1024);
log("calling func: "+cycloa.probe.measure(function(){
	var _obj = obj;
	var i = TIMES;
	while(--i){
		_obj.add(i&0xfff);
	}
}));
log("not calling func: "+cycloa.probe.measure(function(){
	var _obj = obj;
	var i = TIMES;
	while(--i){
		_obj.val += (i&0xfff);
	}
}));
}

 として、オブジェクトの生成を一度だけにしたとしても…

calling func: 575
not calling func: 565
calling func: 890
not calling func: 577
calling func: 881
not calling func: 572

 として、二度目以降やっぱり関数呼び出しバージョンが遅くなってしまいます。なぜでしょう…。

 

ローカル変数、使いましょう

 お次はこのコードです。

  • グローバル変数
  • ローカル変数(var variable = 0;)
  • thisオブジェクトのメンバ変数(this.variable)
  • ローカルオブジェクトのメンバ変数(var obj = 略;obj.variable)
  • thisオブジェクトのメンバオブジェクトのメンバ変数(this.obj.variable)

時間[ms] Chrome21 Firefox14
グローバル変数 302 622
ローカル変数 132 255
this.variable 586 280
var obj;obj.variable 580 280
this.obj.variable 655 292

 ChromeとFirefoxで随分特性が違いますが、できる限りローカル変数を使うのが一番なのは間違いありません。

 定数などはよくグローバル変数としてこのように、擬似名前空間を作った上で保持しておくのが割と綺麗な設計だと思いますが…

var namespace = {}; //ソフトウェア用の擬似名前空間
namespace.INT_MAX=0xffffffff; //32bitIntegerの最大値
namespace.Klass = function(){
	this.method = function(){
		var variable = namespace.INT_MAX; //定数を参照
		for(***){
			variable = (variable+1) & namespace.INT_MAX; //32ビットカウンターとして使う
		}
	};
};

 以上のように複数回定数を使う場合は、

var namespace = {}; //ソフトウェア用の擬似名前空間
namespace.INT_MAX=0xffffffff; //32bitIntegerの最大値
namespace.Klass = function(){
	this.method = function(){
		var tmpINT_MAX = namespace.INT_MAX; //一旦ローカル変数にコピー
		var variable = tmpINT_MAX; //上記のローカル変数の方を参照している
		for(***){
			variable = (variable+1) & tmpINT_MAX; //こちらもローカル変数を参照
		}
	};
};

 このように一旦ローカルに保持しています。…これだけでかなり見づらくなるのでおすすめしません…。

 さらに書き換えられる事の多い変数に関しては、

this.method = function(){
	//一旦ローカルにコピーする
	var variable = this.variable;
	//いっぱい書き換えられる
	variable += this.calc1();
	variable += this.calc2();
	//thisのメンバ変数に戻す
	this.variable = variable;
}

 のようにして、一旦ローカル変数にコピーして最後に再度戻すといった事もしています。書き戻す前にthis.variableにアクセスすると分かりづらいバグになるので非常に注意です。なんてまあ不毛なことを…

 

 さらに、機能ごとにオブジェクトを分割、たとえば今回はエミュレータなのでCPUとサウンドとビデオにクラスを分けて実装してしまうと…

function Video(){
	this.method = new run() {
		//描画
	};
	this.parameter = 0; //何か
}
function CPU(){
	this.method = new run() {
		//CPUの命令実行
	};
	this.parameter = 0; //何か
}
function Emulator(){
	this.videoModule = new Video();
	this.cpuModule = new CPU();
	this.run = function(){
		this.videoModule.run();
		this.cpuModule.run();
	};
}

 このように、this.subModule.run()のように呼びださなくてはいけなくなってしまい、1秒間に数千回呼ぶとコストが馬鹿にならないため…

function Emulator(){
	this.videoModule = new Video();
	this.cpuModule = new CPU();
	this.run = function(){
		//描画処理
		//...
		//CPUの命令実行
		//...
	};
	//変数名の衝突を回避
	this.__video__parameter = 0;
	this.__cpu__parameter = 0;
}

 というようにしてしまっています。こうすると1番目の関数呼び出しのコストも避けられます…が、まずモジュールごとの名前空間が無くなるため、そこに気を付けなければなりません。今回の例ではVideoとCPUのparameterという変数名が衝突しているため、__cpu__と__video__というように接頭辞を付けて区別してますがあまりにも不毛です

JSでファミコンエミュレータ書いてみた:CycloaJS

Posted on

タイトルのまんまです

去年書いて駒場祭で作り方に関する本も出したCycloa」というファミコンエミュレータを、今回JavaScriptに移植してみました。

20120822_01.png

ご好意により、 Denis GrachevさんがZXスペクトラム向けに開発し、ShiruさんとKulorさんがファミコンに移植したAlter Egoというアクションパズルゲームを一緒に配布させていただいています(これはオープンライセンスではありません)。

20120822_02.png

バイナリィランドのように対称性をテーマにしたゲームで、とっても面白いので皆さんやってみてください〜!

JavaScriptのエミュレータはJavaScript NES エミュレータや、jsnesなどが既にありますが、前者は軽量なもののスプライトの再現で一部端折っているところがあり、また後者は通常のPC用エミュレータと同レベルの正確なエミュレーションを行なっているものの、非常に重くミドルレンジクラスのPCでは60FPSのリアルタイムが出ないという問題がありました。

今回のエミュレータでは、通常のPC向けのエミュレーション精度を保ちつつ、どこまで高速化できるのか検証するのを主目的としました。

どれくらい高速化できたのかを確かめてみようというわけで、既存のエミュレータとのベンチマーク取って見ました。動作環境は次の通り。

  • Core2Duo E8400
  • DDR2-800 4GB
  • GeForce 9600GT
  • Fedora 17 x86_64
  • Chrome 21

C++版のオリジナルCycloaと、今回のCycloaJS、JavaScript NES エミュレータとjsnesについて、Google ChromeでFPSリミットを外してどれぐらいの速度が出るのかを調べます。AlterEgoの起動画面でのFPSを比較してみました。

20120822_03.png

  • jsnes: 58.8fps
  • CycloaJS: 169fps
  • Cycloa: 691fps
  • JavaScript NES Emulator: 194fps

jsnesはそもそもこのPCだとリアルタイムで描画できません。JavaScript NES Emulatorより遅いですが、このエミュレータよりスプライトの再現性が高いので、まあ良いのかなと…。流石にC++ネイティブの元のエミュレータには全然勝てません。それでも3〜4倍にまで縮まってるのは、流石Chromeと言ったところでしょうか…

ソースコード

ソースコードはgithubで公開中ですC++版も同様に公開中

具体的な手法に関しては

また後日ということで…とりあえず、もうJavaScriptはあんまり書きたくないですね…。HTML5こわい。。。

リーダブルコード:あたりまえのこと、でもだいじ

Posted on

 なんかネット上を見てたら評判が良いので買ってしまいました、「リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック」。

 具体例としょーもないイラスト(褒め言葉)を交えながら読みやすくてシンプルなコードを書くための軽い読み物です。ラノベより軽いです。

アタリマエのことしか書いてない

 本当に当たり前のことしか書いてない本です。ちゃんと説明する名前の変数を付ける、tmpとかの抽象的な名前は基本的に避けるべきだけど、スコープが短くて本当にtmpならそれはそれでアリ、一度に一つのことしかしないコードにしないと頭がこんがらがる、短絡評価とかを使った「頭いいコード」は逆に読みづらい、…突拍子のある事は一切書いてなくて、どれも本当に「まあそうだよねぇ」って言いながら読み進められます。…でもその「当たり前」の事が出来ないんですよねぇorz

 同様の「当たり前の事しか書いてない」っていう理由で「達人プログラマ」は読む必要無いんじゃない?って前書きました。達人プログラマは当時としては先進的(?)な内容を書いていたので今となってはその説明は要らないかな…という感じなのですが、こちらは各々の持ってる「読みやすいソースコードの基準、目安」みたいなものを改めて文章とソースコードを使って説明しなおしているような本で、一種のたたき台として、「あー、前そういうのあったなー」とか「あの前のコード、ここに出てる駄目コードそのものじゃん!」とか、あーでもないこーでもないと昔の所業を懺悔しながら読める本としてお勧めです。薄いし。

複数人で読んでコードレビューとか楽しそう

 そんなわけで、会社とかで複数人で一つのソースコードを書いているようなシチュエーションで、コード書いてる人が各々この本を読んで、今までのソースコードをレビューする、みたいな使い方をすると楽しそうです。こういう本が無いと何がどう悪いのかを0から説明しなければなりませんけど、レビューする人全員がこの本を読んでれば「ここはさ、あの本の**章に書いてある駄目なコードそのものじゃん?」みたいに簡単に説明できてやりやすそうです。

バグフィックスをしたさきゅばす2.0b2を公開しました

Posted on

リリースノート

公開から2ヶ月以上たったので、バグ修正バージョンのさきゅばす2.0b2を公開しました。

ほぼバグフィックスのみのバージョンです。その他、NGワードスクリプトのサンプルを増やしたりしたので参考にしてみてください。

変更履歴

  • Pythonを最新版に載せ替え、配布サイズを削減しました。
  • スペルミスなどを修正しました。
  • NGスクリプトのサンプルを追加しました。
  • 公式動画をDLできないバグを修正しました。
  • Windowsにおいて、NGスクリプトの改行コードがCRLFだった場合、エラーを発生させないように変更しました
  • ライセンス表示を、配布バイナリ内からWebサイト上に移動しました。

ダウンロード

 ダウンロードはSourceforge内のダウンロードページから行えます。

スクリーンショット

20120805.jpg

 ようせいさんかわいい

 …GUIの変更は殆どありません(ぇ

その他

 registっていう単語は無い(!)そうですが、ねこまたでバッチリ使ってしまっておりました…か、悲しい。

 ライセンス表示のためにファイルが一個増えてしまって、普通に読まれないReadmeがさらに読まれなくなるのではと思って減らしてみました。一緒に配布してるテキストは見づらいのでできるだけ減らしたいです。

 今回はPythonのバイナリをほぼ全とっかえなので全部配布し直すのは理にかなってるのですが、これだけバイナリが大きいとなるとやっぱり自動更新を考えた方がよさそうですね