2019/12/01

suid_sudo: sudo を使った setuid スクリプト用ライブラリ

並行して (?)、suid_sudo という「sudo を使った setuid」のヘルパーライブラリを公開しました。…「『いまさら』を2連発」なんて言わないで。

「一般ユーザ権限だけでは出来ないシステム操作を、ユーザごとにできることを制約して許可したい」という用途はUnixでは結構あり、全てがcapabilityのようなシステム提供の機能では制御できないため、Unix系OSではその多くがsetuidという仕組みを通じて実現されています。例えば、passwdコマンドでは「全員のパスワードが書かれたデータベースの内、自分のパスワードだけを変更できる」とか、そういう類のものです。

そして、もうかなりの昔語りですが、かつて Perl には suidperl という setuid をサポートする仕組みがありました。Unixのセキュリティ上の欠点を克服してスクリプトのsetuidをシミュレートする仕組みでしたが、なかなかkernelの支援なしに安全に作るのは難しく、2010年に削除されてしまいました。
Perlのマニュアルを見ると、

    Use of suidperl is highly discouraged.  If you  think you need it, try alternatives such as sudo first.

    「suidperl」の使用はお勧めしないよ。もし必要だと思ったら、sudoとか別のものを先に試してね!

と書いてあります……なんといい加減な。

というのは、sudo は実行できるコマンドは厳しく制限できるのですが、コマンドそのものは root 権限などでそのまま実行されるので、例えば上の passwd コマンドでいうと、「特定の人だけが全員のパスワードを変更できる」とか「AさんがAさんのパスワードを変更できる(それぞれ自分の、ではない)」のような制限しか出来ないのです。手元では suidperl script を置き換える段階で、この性質にかなり困りました。

というわけで、「じゃぁ sudo でちゃんとユーザ別の分岐処理できる環境を作るか」といって書き始めたところ、結構巨大なライブラリになってしまいました。

セキュリティ的には、実行可能なコマンドが「sudoの設定が許したコマンド」に限定されていて、「権限を落とすだけ」のライブラリなので、suidperlよりは随分楽で、確かに suidperl の better alternative にはなっていますが、それにしても結構複雑な処理が必要でした。

「自分で自分をsudoで呼ぶ」辺りは、できるだけユーザの使い勝手が悪くならないように工夫をしたところです。必要があったら参考にしてくれると良いなと思います。

ちなみに、技術的にこのヘルパーの内部実装で一番セキュリティ的に面倒なところは、「誰が起動したか」をきちんとsudoと連携して把握するところです。sudo は環境変数に「誰」の情報をセットしてくれるのですが、「本当にsudoがセットしたものなのか」がそう簡単にはわからない。その辺りをチェックするために、かなりシステムのいろいろな情報を調べています。それでも root だと色々微妙な判定しきれないケースを作れるので、その辺りは安全サイドに倒しています。(そのせいで、元からrootのときだけ使い勝手がちょっと悪い。)

0 件のコメント: