アカウント名:
パスワード:
pledge は流行ると思いますか?
まず pledge がどういうものかを説明します。プログラムって、最初は設定ファイルを読んだり一時ファイルを開いたりするけど、その後メインループに入ったら権限を殆ど必要としないことが多いですよね。だから、コマンドラインオプション等に応じて [openbsd.org]メインループ直前で権限を落とすという仕組みなんです。
だから最初は tame (調教する [openbsd.org]) という名前の関数でした。獰猛な野獣 (いったん任意のコマンド実行を許す脆弱性があると何でもできちゃう) を手なずける (脆弱性があっても殆どのシステムコールが実行不可能) という感じですね。
現在では主語が変わって、pledge (宣誓する) という名前です。「私は stdio の範囲のみ使用し、その他には近寄らないことを宣言します!」等と誓わせるわけですね。
ファイル単位、ユーザ/グループ単位のアクセス制限とは、かなり違う粒度です。プログラムの途中で権限を落としていくというのは、前例があるんでしょうか。最初は「Android apps みたいな権限宣言かな?」と思いましたが、考えてみるとこちらは権限を落とす一方だし、コード埋め込みだし、実行中に落としていくので、全然違いますね。
さて、開発陣は、これがセキュリティを大幅に向上させるというよりは「抜け道いっぱいだけど、まあシートベルトみたいなもんだね」と言っています。 [openbsd.org]これって意味あるんですかね。
あとはインターフェースが珍しいです。ふつうシステムコールって、ヘッダで定数を定義して OR 演算させたくなりませんか。ここ [tedunangst.com]にあるように
tame(TAME_STDIO | TAME_CMSG | TAME_GETPW | TAME_PROC | TAME_DNS, NULL);
というインターフェースにするのが普通の発想じゃないかと思うんですが、この pledge は
tame("stdio cmsg getpw proc dns", NULL);
という呼び方をします。「セキュリティ関連システムコールで文字列操作かよ!」ってツッコミたくなりません?
宣誓した範囲を超えようとするとエラーで終了するので、思わぬところで DNS にアクセスしてクラッシュする等の問題が出ているようです。OpenBSD (というか Theo) の哲学としては「プログラムが何をするのかを把握できないならプログラマの意味ないじゃん、信頼性とかゼロじゃん」 [marc.info]そして「オフにできる仕組みはユーザがオフにしちゃうから無意味」 [openbsd.org]らしいので、ユーザに何の利便性向上もなくシステムを不安定にして理論上セキュリティを向上させるという、茨の道に進んでいるわけです。すごいですねー()
ちょっと違うところはあるんですが, FreeBSDのcapsicum [gihyo.jp]あたりが近いと思います. 最初に必要な操作を発行しておいて, その後制限モードに移行するという所が同じですね. 基本的にプログラマの予期しない動作は何かおかしい, というフェイルセーフの思想だと思います.
capsicumについてはLinuxにも移植 [mynavi.jp]されていて, OpenBSDにも移植の話がいくつか出ていたみたいですし.
> tame(TAME_STDIO | TAME_CMSG | TAME_GETPW | TAME_PROC | TAME_DNS, NULL);>というインターフェースにするのが普通の発想じゃないかと思うんですが、この pledge は> tame("stdio cmsg getpw proc dns", NULL);
後者の方が,今風のAPIだと思います
理由は3つ
1) 後者のほうが短い(≒可読性も高い)
古典的なC言語だとtame(TAME_STDIO | TAME_CMSG | TAME_GETPW | TAME_PROC | TAME_DNS, NULL);はよく見かける記述ですが,これ冗長だと思いませんか?
2) 今時のCPUは高速なので,文字列処理は大したオーバヘッドにならない
特に tame() は頻繁に実行する処理ではないので,文字列処理のオーバヘッドはあまり問題になりません
3) 文字列のほうが拡張性・保守性が高い
カーネルのAPI/ABIでは,将来的な変更・修正が少ないことも重視されます
ヘッダで定数のORを取る方針だと,たとえば64bit整数だと最大64個しかオプションが定義できません.65個目のオプションが必要なった場合は API/ABI を追加,または変更しなければなりません.そのため細かい制御には不向きであると言えます
一方文字列で指定する方針だと,API/ABIを保ったまま柔軟な拡張ができます.たとえばtame("get*", NULL);tame("getpw[uid==1000]", NULL);などです.
この手の拡張は,定数でOR作戦だと実質無理です.
個人的には,3番目の理由だけで,私は定数をORで指定する方式は選択肢にさえなりません
ですねぇ。加えて言うと、文字列なら他の言語との親和性も高くなりますしね。ヘッダファイル等での余計な定義も不要になりますし。
それでも文字列はないな。考慮しなきゃならないケースが無駄に多くなりすぎる。それはバグの温床だし、すなわちセキュリティホールの温床にもなりうる。それに理由3は割と簡単にあとから拡張可能だしね。
文字列の方が拡張性が高いのはわかるんですが、保守性も高いんでしょうか?
プリコンパイルやリンクでチェックやリンクできずにエラーになるならいいと思うんですけど、実行時にしかエラーがわからなさそうなものってどうにも抵抗が…(javaや.NETのリフレクションで文字列指定するのとかも抵抗があるんですよね。あっちはIDEのリファクタリング機能の対象外になるのも敬遠したくなる所以ですが)。
優秀なIDEがあればコードtypoなんかは警告だしてくれそうですが、それもあるかどうか不明ですし。実際に作る時はマクロでもつかってそのあたりの不安を埋めてくんでしょうかね?
# 最近jsばかり書いてるせいか、どうせ文字列つかうなら文字列テーブルにすればいいのにとも。
プログラムの途中で権限を落としていくというのは、前例があるんでしょうか。
商用UNIXでは普通にありますよ。
Linux のcap-ngとの比較,批評をどなたかしていただけませんでしょうか.
http://people.redhat.com/sgrubb/libcap-ng/ [redhat.com]
(完全に余談です)
従来どおりのアクセス制限の範疇になりますが、Windowsでも「落とす」方向の作りは珍しくありません。Windowsサービスで可能です。
具体的にはこういう風にします。サービスの実行ユーザーをLocalSystemアカウント(これは例えるならroot、強い権限を持っている)にします。このプロセスから、弱い権限のアカウントを実引数としてImpersonate系関数(seteuid/setegidで一時的に落とす感じ)やCreateProcessAsUser関数(forkしてsetuid/setgidしてexecする感じ)を呼び出します。
Impersonateはseteuid/setegid同様に戻り値で成功したことの確認が必須です。一方、CreateProcessAsUserは失敗したらプロセスの作成が行われないので、最悪エラーチェックなしでも幾分安全と言えると思います(もちろん、しなくていいとは言っていない)。
#seteuid/setegidやsetuid/setgidでの例えが正しいのか不安。
IISがやっているのがまさにそれですね。
そういえば、もしかしたら特殊ながらWindowsで「プログラムの途中で権限を落としていく」のようなことはできるかもしれません。すなわち「前例がある」と言えるかもしれません。
「自プロセスをOpenProcessTokenして、AdjustTokenPrivilegesでSE_PRIVILEGE_REMOVEDする」が可能なら、できると言えます。ドキュメントにはそう書いていないけど、自プロセスに対してSE_PRIVILEGE_REMOVEDはできないという制限がもしあったら、できないということになります。
これで落とせるのは「特権」と呼ばれるものになります。「物理メモリのロック」とか「時刻変更」とか「シャットダウン」とか、ファイルや各種オブジェクトに対するアクセス権限とは別の種類のアクセス制限です。特権の一覧:特権 [microsoft.com](これはちょっと古いので、Vista世代で増えたものが載っていない)
Chromiumのサンドボックスプロセスが普通にやってますよ。初期化時にだけ権限が必要な操作をやって以後権限を落としたり。
あれ、そうでしたか。あれは、低い権限のアクセストークンで新しいプロセスを作っているだけだと思っていました。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
にわかな奴ほど語りたがる -- あるハッカー
pledge (スコア:5, 興味深い)
pledge は流行ると思いますか?
まず pledge がどういうものかを説明します。
プログラムって、最初は設定ファイルを読んだり一時ファイルを開いたりするけど、
その後メインループに入ったら権限を殆ど必要としないことが多いですよね。
だから、コマンドラインオプション等に応じて [openbsd.org]
メインループ直前で権限を落とすという仕組みなんです。
だから最初は tame (調教する [openbsd.org]) という名前の関数でした。
獰猛な野獣 (いったん任意のコマンド実行を許す脆弱性があると何でもできちゃう) を
手なずける (脆弱性があっても殆どのシステムコールが実行不可能) という感じですね。
現在では主語が変わって、pledge (宣誓する) という名前です。
「私は stdio の範囲のみ使用し、その他には近寄らないことを宣言します!」
等と誓わせるわけですね。
ファイル単位、ユーザ/グループ単位のアクセス制限とは、かなり違う粒度です。
プログラムの途中で権限を落としていくというのは、前例があるんでしょうか。
最初は「Android apps みたいな権限宣言かな?」と思いましたが、考えてみると
こちらは権限を落とす一方だし、コード埋め込みだし、実行中に落としていくので、全然違いますね。
さて、開発陣は、これがセキュリティを大幅に向上させるというよりは
「抜け道いっぱいだけど、まあシートベルトみたいなもんだね」
と言っています。 [openbsd.org]これって意味あるんですかね。
あとはインターフェースが珍しいです。
ふつうシステムコールって、ヘッダで定数を定義して OR 演算させたくなりませんか。
ここ [tedunangst.com]にあるように
というインターフェースにするのが普通の発想じゃないかと思うんですが、この pledge は
という呼び方をします。
「セキュリティ関連システムコールで文字列操作かよ!」ってツッコミたくなりません?
宣誓した範囲を超えようとするとエラーで終了するので、
思わぬところで DNS にアクセスしてクラッシュする等の問題が出ているようです。
OpenBSD (というか Theo) の哲学としては
「プログラムが何をするのかを把握できないならプログラマの意味ないじゃん、信頼性とかゼロじゃん」 [marc.info]
そして
「オフにできる仕組みはユーザがオフにしちゃうから無意味」 [openbsd.org]
らしいので、ユーザに何の利便性向上もなくシステムを不安定にして
理論上セキュリティを向上させるという、茨の道に進んでいるわけです。すごいですねー()
Re:pledge (スコア:1)
ちょっと違うところはあるんですが, FreeBSDのcapsicum [gihyo.jp]あたりが近いと思います. 最初に必要な操作を発行しておいて, その後制限モードに移行するという所が同じですね. 基本的にプログラマの予期しない動作は何かおかしい, というフェイルセーフの思想だと思います.
capsicumについてはLinuxにも移植 [mynavi.jp]されていて, OpenBSDにも移植の話がいくつか出ていたみたいですし.
Re:pledge (スコア:1)
> tame(TAME_STDIO | TAME_CMSG | TAME_GETPW | TAME_PROC | TAME_DNS, NULL);
>というインターフェースにするのが普通の発想じゃないかと思うんですが、この pledge は
> tame("stdio cmsg getpw proc dns", NULL);
後者の方が,今風のAPIだと思います
理由は3つ
1) 後者のほうが短い(≒可読性も高い)
古典的なC言語だと
tame(TAME_STDIO | TAME_CMSG | TAME_GETPW | TAME_PROC | TAME_DNS, NULL);
はよく見かける記述ですが,これ冗長だと思いませんか?
2) 今時のCPUは高速なので,文字列処理は大したオーバヘッドにならない
特に tame() は頻繁に実行する処理ではないので,文字列処理のオーバヘッドはあまり問題になりません
3) 文字列のほうが拡張性・保守性が高い
カーネルのAPI/ABIでは,将来的な変更・修正が少ないことも重視されます
ヘッダで定数のORを取る方針だと,たとえば64bit整数だと最大64個しかオプションが定義できません.
65個目のオプションが必要なった場合は API/ABI を追加,または変更しなければなりません.そのため細かい制御には不向きであると言えます
一方文字列で指定する方針だと,API/ABIを保ったまま柔軟な拡張ができます.
たとえば
tame("get*", NULL);
tame("getpw[uid==1000]", NULL);
などです.
この手の拡張は,定数でOR作戦だと実質無理です.
個人的には,3番目の理由だけで,私は定数をORで指定する方式は選択肢にさえなりません
Re:pledge (スコア:2)
ですねぇ。加えて言うと、文字列なら他の言語との親和性も高くなりますしね。ヘッダファイル等での余計な定義も不要になりますし。
ほえほえ
Re: (スコア:0)
それでも文字列はないな。考慮しなきゃならないケースが無駄に多くなりすぎる。
それはバグの温床だし、すなわちセキュリティホールの温床にもなりうる。
それに理由3は割と簡単にあとから拡張可能だしね。
Re: (スコア:0)
文字列の方が拡張性が高いのはわかるんですが、保守性も高いんでしょうか?
プリコンパイルやリンクでチェックやリンクできずにエラーになるならいいと思うんですけど、
実行時にしかエラーがわからなさそうなものってどうにも抵抗が…
(javaや.NETのリフレクションで文字列指定するのとかも抵抗があるんですよね。あっちはIDEのリファクタリング機能の対象外になるのも敬遠したくなる所以ですが)。
優秀なIDEがあればコードtypoなんかは警告だしてくれそうですが、それもあるかどうか不明ですし。
実際に作る時はマクロでもつかってそのあたりの不安を埋めてくんでしょうかね?
# 最近jsばかり書いてるせいか、どうせ文字列つかうなら文字列テーブルにすればいいのにとも。
Re: (スコア:0)
商用UNIXでは普通にありますよ。
Re: (スコア:0)
Linux のcap-ngとの比較,批評をどなたかしていただけませんでしょうか.
http://people.redhat.com/sgrubb/libcap-ng/ [redhat.com]
Re: (スコア:0)
> プログラムの途中で権限を落としていくというのは、前例があるんでしょうか。
「落とす」ではなくて、プログラム上の必要な箇所だけ「上げる」というのは、Winodws NTがそうなってますね。
基本ポリシーとして Unix (TrustedUnix系を除く) は、全権限を持つものを根にして、子供が権限を落としていくという方法ですけど Windows は、全く権限の無い状態から、必要な箇所だけ認証して権限を上げるという方向です。
旧Unix 的な方式では、子供の不具合で親にロールバックした場合に権限が上がってしまうというアーキテクチャとしての欠陥があるので Windows 型の方式になった TrustedUnix というのが出てきたわけです。
Re:pledge (スコア:1)
(完全に余談です)
従来どおりのアクセス制限の範疇になりますが、Windowsでも「落とす」方向の作りは珍しくありません。Windowsサービスで可能です。
具体的にはこういう風にします。サービスの実行ユーザーをLocalSystemアカウント(これは例えるならroot、強い権限を持っている)にします。このプロセスから、弱い権限のアカウントを実引数としてImpersonate系関数(seteuid/setegidで一時的に落とす感じ)やCreateProcessAsUser関数(forkしてsetuid/setgidしてexecする感じ)を呼び出します。
Impersonateはseteuid/setegid同様に戻り値で成功したことの確認が必須です。一方、CreateProcessAsUserは失敗したらプロセスの作成が行われないので、最悪エラーチェックなしでも幾分安全と言えると思います(もちろん、しなくていいとは言っていない)。
#seteuid/setegidやsetuid/setgidでの例えが正しいのか不安。
Re: (スコア:0)
IISがやっているのがまさにそれですね。
Re:pledge (スコア:1)
そういえば、もしかしたら特殊ながらWindowsで「プログラムの途中で権限を落としていく」のようなことはできるかもしれません。すなわち「前例がある」と言えるかもしれません。
「自プロセスをOpenProcessTokenして、AdjustTokenPrivilegesでSE_PRIVILEGE_REMOVEDする」が可能なら、できると言えます。ドキュメントにはそう書いていないけど、自プロセスに対してSE_PRIVILEGE_REMOVEDはできないという制限がもしあったら、できないということになります。
これで落とせるのは「特権」と呼ばれるものになります。「物理メモリのロック」とか「時刻変更」とか「シャットダウン」とか、ファイルや各種オブジェクトに対するアクセス権限とは別の種類のアクセス制限です。特権の一覧:特権 [microsoft.com](これはちょっと古いので、Vista世代で増えたものが載っていない)
Re: (スコア:0)
Chromiumのサンドボックスプロセスが普通にやってますよ。初期化時にだけ権限が必要な操作をやって以後権限を落としたり。
Re:pledge (スコア:1)
あれ、そうでしたか。あれは、低い権限のアクセストークンで新しいプロセスを作っているだけだと思っていました。