追記

野良犬日記 2.1

RDF/RSS
この日記の検索

最近のツッコミ:


2016-09-19 (Mon) [長年日記]

_ [obsd]doas mastery和訳

あまり見直していないけど、こんなものかな。自分用の覚え書きということで。

doas を世に出して一年になりますので、一冊本を書く時期ですな。あるいは薄い本程度でもいいかもしれませんが。

UNIX システムには二種類のユーザがいます。スーパーユーザと一般ユーザです。スーパーユーザはスーパーですが、あとは誰もスーパーじゃありません。これほど権力が独占されていると、物事は単純になりますが、権力が過剰に付与されることもよく起こります。たいていは一つの作業をするためにだけスーパーユーザの権力が必要になるものです。常日頃それほどの権力を持っていたいとは思いませんね。そこに付随する責任を考えてみてください! そこで doas は、sudo コマンドと同様、スーパーユーザの特権を小分けにして、特定の作業のためだけに付与するものです。

doas コマンド自体にも少しばかりのオプションがあり、それも後のほうで扱いますが、いちばん面白いのは設定ファイルです。ここがキモなんです。

doas.conf

可能な限りシンプルな doas.conf ファイルは実にまったくシンプルです。まばたきすると見逃しますよ。いいですか。





この空ファイルは何もしませんが、それのおかげで我々はデフォルトのルールセットを説明できます。すなわち、そんなものはないということです。doas は DENY 状態からルール評価を始めるのです。どのルールにもマッチしなければ、その動作は拒否されます。そうです。root でさえ permission denied エラーを食らいます。このファイル自体に関していえば実用性は皆無ですが、これで、システムの doas.conf ファイルを読みさえすれば挙動をすべて完全に理解できることが保証されるわけです。

ただ、もし設定ファイルが存在すらしない場合 doas は、有効でない旨のメッセージを出して終了します。

実用性のある範囲で最もシンプルな設定は、おそらくこんな感じの見た目になるでしょう。

permit :wheel

これは wheel グループ内のあらゆるユーザが、あらゆるコマンドを root として実行できるようにします。おおまかに言えば su コマンドと同じようなことです。もっと似せるには、root がパスワードなしでコマンドを実行できるようにしたいですね。

permit :wheel
permit nopass keepenv root

ここで root のルールを二番目にしたのは、doas が最後のマッチ式にルールを評価するからです。root は wheel グループに属しているので最初のルールがマッチし、それを二番目のルールで上書きする必要があるのです。いつでも一般的なルールから始めて、あとから具体的にしていくようにしてください。

root なのに doas を実行するのはなぜでしょう。それは、権限の少ないユーザに切り換えたいときがあるからです。あるいは手元のスクリプトが、重要な操作で権限を上昇するために doas を使っていて、しかし自分は既に root になっている場合があるからです。

パスワード

デフォルトで doas は、毎度ユーザがコマンドを実行するたびに認証を要求します。通常これはパスワードの入力を意味します。複数のコマンドを実行する場合にはウンザリしてしまうかもしれませんね。これを改変するため doas.conf に追加できるキーワードが二つあります。

nopass キーワードを追加すると、そのユーザは常にパスワード入力なしでコマンドの実行を許可されます。これは上述の root 用ルールにありました。既に root であり、好きなことができるのですから、パスワードを要求する理由はありませんね。

persist キーワードを追加すると、doas はそのユーザが以前に認証したことを記憶し、その後の五分間は確認を求めなくなります。

permit persist :wheel

このルールは、よくある sudo 設定のとおり、wheel のユーザが初めてコマンドを実行するときにパスワードを要求します。

doas の使う認証情報はカーネル内に記録され、そのセッションに紐付けられます。ファイルシステム情報とは異なり、他のユーザからアクセスすることができませんから、偽造が困難です。タイムアウトはコンピュータ時間ではなくリアル時間で起こるので、システム時計を巻き戻しても、時間切れを無かったことにはできません。時間内に再実行すると残り時間はリセットされますが、それはルールが persist な場合だけです。一つのルールが persist と nopass の両方であることもできませんし、nopass ルールが残り時間を増やすこともできません。

一つのマシンに複数ログインしている場合には、それぞれのログインで認証が必要になります。加えて、認証情報には親シェルのプロセス ID が含まれていますから、何らかのシェルスクリプト内で doas を実行するときには再認証が必要ということになります。すなわち、同じことを別の言い方で表現するなら、品質の不確かなスクリプトやプログラムを実行する場合でも、知らないうちに権限を上昇されることはない、ということです。(まあ理論上の話です。実際のところは、このチェックにはかなりゴニョゴニョする余地が残っています。)

permit persist :wheel
permit :wheel cmd reboot

認証チェックが省略されるのは persist の付いたルールだけです。ミスを防ぐため、重要なコマンドは persist なしで再び載せておけば、常にパスワードを要求することができます。

コマンドラインの -L オプションを doas に渡すと、ログアウトしたのと同じように、そのターミナルにおける persist の認証情報を消してくれます。時間切れまで待つ必要はありません。

環境変数

実行するコマンドに情報を渡す方法は二つあります。第一の、明白な方はコマンドラインです。第二の、見えにくい方法は環境変数を経由するものです。ほとんど目に見えないにもかかわらず、環境変数はプログラムの挙動を劇的に左右することがあります。そういうわけで、不測の結果を避けるために doas が何らかのフィルタリングを提供するのは大切なことです。デフォルトでは、ほんのわずかな変数だけが渡されます。

環境変数に関わる設定キーワードが二つあります。keepenv と setenv です。前者はとても単純。前に、root のルールで見たことがあります。環境変数をすべてそのままコマンドに渡すだけです。信頼できるユーザには便利な手抜き方法です。

setenv を使うのはもう少し複雑です。というのも、環境変数の追加、変更、削除が可能だからです。例を見てみましょう。

permit setenv { PKG_PATH ENV=/root/.kshrc PS1=$DOAS_PS1 } zoltan

このルールは zoltan に root としてコマンドを実行できるようにします。PKG_PATH 環境変数は保持されます。ENV という、ksh の設定ファイルを指定する環境変数は、root の所有するものに変更されます。最後に、シェルのプロンプト表示を制御する PS1 の設定を上書きしています。この設定ファイルでは具体的な値を指定せず、DOAS_PS1 の値を使います。これにより、zoltan が root 時のプロンプトを自在に調整できます。

ユーザと権限

doas.conf に書かれた各ルールは、permit や他のオプションの後に指定された個人やグループに適用されます。ユーザ名かグループ名かを識別するキーワードはありません。代わりに chown に似た書式が使われ、ユーザ名ならそのまま書き、グループ名は頭にコロンを付けます (:group)。このあたりで、ルールは最後にマッチしたもの勝ちで評価されるということを思い出しておきましょう。個別ユーザのルールが自動的にグループのルールより優先されるわけではありませんから、個別ユーザは後のほうに書かなければいけません。

ほとんどの状況で doas は root としてコマンドを実行するために使われます。その場合、特別な書式は必要ありません。しかしながら、特定のユーザになるようルールを制限したいということもありえます。

permit nopass zoltan as dbadmin

このルールは zoltan に、パスワード入力なしでデータベース管理者としてコマンドを実行できるよう許可しますが、しかしこれだけでは何も root として実行できません。

コマンド

doas.conf 文法の旅も、終わりが近づいてきました。doas は、ルールが特定のコマンドにしか適用されないように制限することもできます。さらには、特定のコマンドに特定の引数を与えた場合のみにも制限できます。

permit nopass :operator cmd reboot

通常、reboot には root 権限が必要ですが、直接実行されるのではなく、setuid なプログラムである shutdown から実行されます。shutdown を実行できるのは operator グループだけです。上のルールは、このグループのユーザが reboot を直接実行できるようにします。しかしながら operators が root として他のコマンドを実行したりシェルを取得したりすることはできません。

permit zoltan cmd sh args /etc/netstart

こちらでは zoltan に、netstart という (ネットワークインタフェースを設定する) スクリプトの再実行を許可します。他のシェルコマンド実行は許可しません。netstart スクリプトだけです。

この例ではどちらも、cmd にファイル名しか指定しませんでした。このような場合、doas はシステムの PATH (/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin) のコマンドだけに実行を限定します。zoltan が自分のホームディレクトリに sh というバイナリを設置して PATH を ~/bin にしても、我々の裏をかくことはできません。cmd には絶対パスを指定することもできますが、その場合、ユーザは毎回フルで打ち込む必要があります。

コマンド引数は残さず指定しなければなりません。

permit zoltan cmd ifconfig args iwm0 up
permit zoltan cmd ifconfig args iwm0 down

この二つのルールでは、zoltan に wifi インタフェースのオンオフを許可していますが、他のパラメータは一切変更させません。

カーネルから情報を集めるユーティリティの中には、一般ユーザとして実行すると情報の一部しか出してくれないものがあります。フルで出すには root として実行する必要があります。たとえば fstat は、unix ドメインソケットに関して最小限の情報しか表示しません。

tedu     Xorg       94581   16* unix stream 0x0
tedu     Xorg       94581   17* unix stream 0x0
tedu     Xorg       94581   18* unix stream 0x0
tedu     Xorg       94581   19* unix stream 0x0
tedu     Xorg       94581   20* unix stream 0x0

しかし root として実行しなおすと、ずっと多くの情報が得られます。

tedu     Xorg       94581   16* unix stream 0xffff800000b45980 <-> 0xffff800000b3d700
tedu     Xorg       94581   17* unix stream 0xffff800000b3d880 <-> 0xffff800000b45500
tedu     Xorg       94581   18* unix stream 0xffff800000b45480 <-> 0xffff800000b45300
tedu     Xorg       94581   19* unix stream 0xffff800000b45080 <-> 0xffff800000128e80
tedu     Xorg       94581   20* unix stream 0xffff800000b60280 <-> 0xffff800000b60780

こうなっていれば、ソケットを向こう側のプロセスと対応づけることができます。

tedu     xterm      33159    3* unix stream 0xffff800000b45300 <-> 0xffff800000b45480
tedu     Xorg       94581   18* unix stream 0xffff800000b45480 <-> 0xffff800000b45300

これらのカーネルアドレスは、カーネルのメモリ配置について情報を漏らしてしまい、攻撃を容易にしかねないので、通常は隠されています。しかし tedu を信頼している場合 (というか信頼しない人なんていないでしょマジで) なら、簡単な設定ルールで変更できます。

permit nopass tedu cmd fstat args -u tedu

fstat を使うと他のユーザのプロセスが開いているファイルも見えてしまうのですが、ここでは引数を指定して、tedu が接続とプロセスを対応づけられないようにしています。

deny

ここまで見てきた permit ルールとは対照的に、特定のコマンド実行を拒否する deny ルールを作ることも可能です。この機能が真価を発揮するのは、信頼している操作者がうっかり typo してしまうのを防ぐ安全装置としてです。セキュリティ機能としては使わないほうが賢明です。というのも、漏れのないブラックリストを作ると、漏れなく疲労困憊するからです。それよりはまず (訳注: permit を絞って) 意図せず権限を与えることのないようなルールセットを工夫すべきです。

permit :wheel
deny zoltan cmd reboot

zoltan が wheel グループに入っているとすれば、ここで彼はあらゆるコマンドを実行できます。ただし reboot を除きます。zoltan には、少しトリガーハッピーになって、違うターミナルに打ち込む癖があるのかもしれません。このルールセットは実際のところ、zoltan がマシンを再起動させることを防いでなどいません。最初のルールがあれば、doas.conf を編集して次のルールを消すなど、色々やるだけの権限があるのです。全員が仲間だという前提になっています。

doas

doas コマンド自体には、少しばかりのオプションがあります。

ちょうど設定ファイルの文法を見終えたわけですから、新しいファイルをインストールする前に -C オプションを使って文法チェックすることができますね。特定のコマンドと引数について、実際に実行せずにルールセット評価の結果をチェックすることもできます。さきほどの fstat の例を続けて、そのコマンドに引数があるときだけマッチすることをチェックできます。

$ doas -C doas.conf fstat
deny
$ doas -C doas.conf fstat -u tedu
permit nopass

入力を受け付けないようなスクリプトに doas を組み入れるときは、-n オプションを付けると失敗を未然に防ぐ役に立ちます。nopass ルールしか実行せず、パスワードの必要なルールは即座に失敗を返すのです。これには persist なルールも含まれており、直前に認証していようがいまいが関係なく失敗にします。

謝辞

たくさんの OpenBSD 開発者およびユーザの支援なしに doas を完成させることはできなかったでしょう。特に Vadim Zhukov は設定パーザと後退テストスイートに甚大なる貢献をしてくれました; Todd Miller, Damien Miller, および Martijn van Duren は、アイディアやインスピレーションを提供してくれました; Theo de Raadt は追加機能を却下するうえで支えになってくれました; Henning Brauer はターミナルに認証維持を結びつけるアイディアをくれました; そして Michael Lucas には、キャッチーなタイトルをパクったことで借りができました。


2016-04-04 (Mon) [mutt]Mutt-1.6.0出た [長年日記]

_ Mutt は、奇数と偶数の法則はもうやめるみたい

もう 1.4 が安定版と信じて使ってる人なんて殆どいなかったからユーザ的には意味ないけど、開発者が以前のコードを無視できるという意味では大きい。

Rocco の遺産であるテスト追加とか、やるのかな。


2016-01-17 (Sun) [長年日記]

_ [obsd][sec]tedu の outrageous roaming fees の適当訳

翻訳は適当なので、ちゃんと原文を見てください。

海外で予想外の電話料金になってしまうのって最低ですよね。のんびり快適な旅行のつもりが、ガーン! 1メガバイト 20 ドル!? ちゃんと契約書を読んでおけばよかったですね。もちろん、契約書を読む程度の情報強者なら、海外ローミング料金のことも知っていて、契約書を読む必要もなかったでしょうけど。まあそんなもんですよ人生も ssh も。

えっ、ssh にローミングが関係あるのかって? ちゃんと書面を読んでおくべきでしたね。Qualys のセキュリティアドバイザリ (https://www.qualys.com/2016/01/14/cve-2016-0777-cve-2016-0778/openssh-cve-2016-0777-cve-2016-0778.txt ) は、完壁どころじゃない最高の出来栄えです。さて、アドバイザリを読んだ我々 (訳注: OpenBSD 開発者たち) は、どうすればいいのでしょうか。

最大のバグは (とりあえず二番目のオーバーフローのやつは無視して)、秘密データのメモリが再利用されて漏れたことです。これが起こる可能性は前から知られていますし、対策も用意されていますが、頭を使わずに対策されるようにはなっていません。

まず、stdio はバッファを free しても中身をクリアしません。その選択は理解できます。stdio は秘密じゃないデータにもたくさん使われますから、パフォーマンスが重要なのですよね。あれ? そうかな。ファイルを閉じたりバッファを解放するのって、おそらく速度を稼ぐ必要のある場所ではありません。じゃあ、もうちょっときれいに掃除してもいいかもしれませんね。あるいは glibc のように mmap/munmap を使うか。やる価値はあるかもしれませんが、私は libc のサブシステムがそれぞれ独自のミニ malloc を開発するのを見たいとは思いません。今でも結構な数があって、それぞれにクセやバグがあるんです。

一段低レベルの話。free 自体はもう既定で (5.6 から) 冒頭 2k をクリアしています。これは別種の use-after-free バグに対する緩和策として設計されましたので、私としては、大きなバッファを毎回クリアするのはパフォーマンス低下に見合うほどの価値がないと見なしました。この検討過程で、バッファ内のデータとしても、ほとんどの鍵は 2048 バイトより小さいことを確認しました。

私の実験では、既定の動作で十分に鍵の暴露を防げるはずでした。どうやって Qualys が 5.8 で鍵をリークさせたのか、私はよくわかっていません。stdio バッファの中身を fclose の前と後で出力させるよう ssh にセットして中に鍵データがないことを確認したのですが、あまり時間がなかったので、今度は exploit を使ってもっと時間をかける必要がありますね。

OpenBSD の free には、攻撃者がデータの「お手入れ」をしにくくするよう邪魔するランダム化機能もいくつかありますが、その多くは小さめのチャンクのほうが効果を発揮するものです。free ページリストの挙動は今でもほぼ予測可能です。それでももちろん、攻撃者に一撃のチャンスしかないのか無限に試行できるのかによって事情は異なります。roaming バグの悪用は (訳注: 「connection suspended, press return to resume」と表示されるので) ごちゃごちゃ表示されますが、おそらく気付かれずに消えますよね? (訳注: ssh に ls をパイプしたりする例が Qualys の Mitigating Factors のところにある)

一段レベルを上げます。ssh は鍵の読み取りに stdio を使わないようにすべきか? 独自にメモリを mmap してそこに読み出すか? という問題、それをやれば分離はできますが、ちょっと私にはわかりません。Heartbleed の後に Akamai が同じようなことを提案していましたが、ちゃんとしたものになるまで何度か試行錯誤が必要でしたし、stdio の再発明は新しいバグを招き入れる良い方法でもありますから。使っている道具が信頼できないなら、もっと良い道具か何かを入手しましょう。余談ですが signify は stdio を使っていません。それが先見の明によるものだとは言えませんけどね。

ssh のあちらこちらに explicit_bzero を振りかけてまわった苦労が実際に功を奏して、潜在的な exploit vector をひとつつぶしていたのは嬉しいことです。それで、いつまでたってもどこか (stdio) にリークがあるように思える一方で、ふさぎ続けていれば全部ふさげるかもしれない、とも思えます。

メモリ統合の緩和策に関して (訳注: 断片化したリーク情報から鍵を再構成しにくくすることか?) は、よくやっていると考えています。バグをその正体がわからないうちに防ぐのは大変なことですし、チップが思ったとおりにランドしないことだってありますから (訳注: IC を乗せる余地がないという意味??)。確かに、stdio の中で何が起こっているかを非常に注意深く検討する必要はあるでしょう。何か変更を加える前にまず exploit を再現させる必要がありますけれども。

今回のリークは ssh-agent を使っていれば緩和できるものでした。その場合には暗号化された鍵しか漏れないからです。ひとつ思いついたのは、ssh が常に小さな agent を起動して暗号化された鍵を処理させ、メインプロセスでリークがあっても何も外に出ないようにできるのでは、というアイディアです。権限分離は残念ながらリモートからのコード実行による影響の軽減に重きを置いており、他の種類のバグを見過ごしてきました。

どちらかを選ばなければいけないとしたら、自分の実験的機能で情報漏れが起こるなら認証前のサーバサイドよりも認証後のクライアントサイドにあってほしいと言うしかありませんが、頭の悪い実験を減らすという選択肢があれば大喜びでそちらにします (訳注: 利用者の少ない機能やプログラムを削除することを「tedu する」と呼ぶほど、筆者は OpenBSD 開発者たちにコード断捨離の人として知られている)。とは言うものの、ローミングは、完成していれば皆に便利がられる機能だったでしょうね。mosh ユーザも何人か改宗させることができたでしょうに。

あと気に入ったのは、ssh が git で開発されればバグがなくなるだろうという提案です。

ところで、念のために鍵を更新しておこうという方もそうでない方も、そろそろ暗号化された鍵のパスワードクラックに対して大幅に改善された防御を提供する新しい秘密鍵フォーマット (http://www.tedunangst.com/flak/post/new-openssh-key-format-and-bcrypt-pbkdf ) の利用を今一度考慮してみてはいかがでしょうか。


2015-11-22 (Sun) [長年日記]

_ [obsd][sec]tedu の going full pledge

適当和訳

Theo の pledge 更新状況にはプログラムがたくさん載っているが、その中には pledge するのが少しアホくさく思えるものもあるかもしれない。でも、その一見アホくさい努力のおかげで見つかったバグや設計ミスもあるのだ。

おそらく、いくつかのプログラムに pledge は必要ない。「もし id に exploitable なバグがあれば、それどころじゃないだろう」という議論も、さもありなん。しかし、何にでも pledge させるという作業は、pledge というコンセプトが実効性を持つことの証明になっている。テストした最初の 5 つのプログラムが一発で動かなければ、あと 5 つ直そうとする人はいないだろう。それに比べて、100 個までいけたなら、あと 100 個も大したことはないだろうと自信を持って言える。まあ最低でも、「あいつよりデカいぜ」と自慢できる、気分の良い数字にはなる。

その他の場合に pledge は無駄に思えるかもしれないが、ひょっとすると無駄ではない。ksh を使って簡単な cgi スクリプトを書くことを想像してほしい。ksh に何らかのオーバーフロー(shellshock?)が潜んでいるところまで想像しよう。シェルはあまりきつく縛ることができない。当然のことながら、fork して他のプログラムを exec したり、ファイルを作成・変更したりする必要がある。 しかし、最低でもネットワーク関連のシステムコールを無効にすることができる。cgi が小規模な chroot の場合、攻略された ksh は、少数のプログラムを実行することはできるものの、ソケットを開いて内側からネットワークを割り当てることはできない。

他には、設計ミスと言ったほうが良さそうな、ある条件下で fork / exec しようとするプログラムもある。patched 形式の diff を受け取ると、実際に ed を実行する。もちろん ed は「!」コマンドによるシェルエスケープをサポートしているから、diff が任意のプログラムを実行する危険が潜んでいるのだ。patch はそうしたシーケンスを探して未然に防ごうとするが、もし騙されたら……、5.7 の errata 13 になる。pledge を patch に入れることがきっかけで、必要な ed コマンドをエミュレートして一切 exec しないよう設計し直すことになった。もし pledge が 1 年早く来ていたなら、このバグが exploitable になるのを防ぐのみならず、そもそも存在しないようにしてくれただろうに。

iked に pledge を入れたときには、小さなバグが見つかって修正された。chroot 内の子プロセスが、自分の設定を出力しようとして /etc/protocols にアクセスを試みていた。それが失敗して、fatal ではないので、プロトコル名のかわりに数値のまま出力していただけだ。しかしながら、pledge がファイルの open 許可を与えないため子プロセスをクラッシュさせるようになって、そのバグが表面化した。出力コードは別プロセスに移り、今では本来の望みどおりプロトコル名を表示するようになっている。

revoke をコールしたがるプログラムがある。この関数は close の重量級といったところで、あらゆるプロセスのあらゆるファイルインスタンスを閉じることができる。もともとのユースケースは init が端末を安全に再利用できるよう、次のユーザに渡す前に端末を強制的に閉じることだったが、いつしか TTY だけでなく、あらゆる種類のファイルを受け付けるように拡張されたのだ。その revoke に関してカーネルポリシーをどうするか決定する際、この拡張が再検討された。「もしかして、任意のファイルタイプは必要なくない?」そのとおり

こうした状況がどれも他のセキュリティポリシー機構で検出できなかったなどと言うつもりはない。だが systrace ポリシーが patch にあったとしても、当時の主流な考え方として「通常の動作 (ed の実行) は許可」だったから、おそらく助けにならなかっただろう。patch に対する AppArmor ポリシーは見つからない。他のシステムについてはよくわからない。まあ優先順位の高い標的ではなさそうだけど、内部設計を見直せただけだとしても、セキュリティ改善という成果があるわけで。

Posted 2015-11-20 18:33:58 by tedu Updated: 2015-11-20 18:33:58

2014-09-02 (Tue) [長年日記]

_ Windows 7 で chkdsk が "Disk check has been cancelled" になる場合

A disk check has been scheduled が表示されてカウントダウンになるけど、 10、9 となって 8 が表示される前に

   Disk check has been cancelled

と無慈悲に拒否されてしまう場合 (ぐぐったらこれでかなり悩んでる人がいるみたい) には

   chkntfs /t:0

と打っておくと、10 の時点で開始してくれるので大丈夫。

でも一体どうしてキーが押されたと思ってしまうのか。それは不明なまま……


2002|06|07|08|09|10|11|12|
2003|01|02|03|04|05|06|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|10|11|12|
2011|02|04|05|06|07|08|09|10|11|12|
2012|01|03|04|05|06|09|11|12|
2013|02|03|09|10|11|
2014|02|03|04|06|09|
2015|11|
2016|01|04|09|