変わったのは /bin/sh
です どちらかが bash
になりました または dash
滞在 追加のフラグ -p
を取得しました bash の動作を模倣します。
Bash には -p
が必要です man ページで説明されているように、setuid 特権をドロップしないフラグ:
実際のユーザー (グループ) ID と等しくない実効ユーザー (グループ) ID でシェルが開始され、-p オプションが指定されていない場合、起動ファイルは読み取られず、シェル関数は環境 (SHELLOPTS) から継承されません。 BASHOPTS、CDPATH、および GLOBIGNORE 変数が環境に表示された場合、それらは無視され、有効なユーザー ID が実際のユーザー ID に設定されます .呼び出し時に -p オプションが指定されている場合、起動時の動作は同じですが、有効なユーザー ID はリセットされません。
以前、dash
これを気にせず、setuid の実行を許可しました (それを防ぐために何もしませんでした)。しかし、Ubuntu 16.04 の dash
のマンページには、 bash
のような追加のオプションが記述されています :
-p 特権
uid と一致しない場合は、有効な uid をリセットしようとしないでください。 誤った使用を避けるため、これはデフォルトでは設定されていません system(3) または popen(3) を介して root プログラムを bysetuid します。
このオプションは、アップストリーム (提案されたパッチに反応しなかった可能性があります) にも Debian 9 にも存在しませんでしたが、2018 年以降にパッチを取得した Debian バスターには存在します。
注:Stéphane Chazelas が説明したように、"/bin/sh -p"
を呼び出すには遅すぎます system()
で なぜなら system()
/bin/sh
で指定されたものをすべて実行します そのため、setuid は既に削除されています。 derobert's answer は、 system()
の前のコードで、これを処理する方法を説明しています .
あちこちに歴史の詳細があります。
おそらく、シェルは何らかの理由で起動の一部として有効なユーザー ID を実際のユーザー ID に戻しています。以下を追加することでこれを確認できます:
/* needs _GNU_SOURCE; non-Linux users see setregid/setreuid instead */
uid_t euid = geteuid(), egid = getegid();
setresgid(egid, egid, egid);
setresuid(euid, euid, euid);
system()
の前に . (実際には、Linux でも、おそらく実際のものだけを設定する必要があります。保存されているものはそのままにしておいて問題ありません。これは、デバッグするための強引な方法です。ID を設定する理由によっては、もちろん必要になる場合があります。実際の ID もどこかに保存します。)
[また、setid がどのように機能するかを学習するだけの演習ではない場合、特にシェルを呼び出すときに、心配すべきセキュリティ上の問題がたくさんあります。たとえば、シェルの動作に影響を与える多くの環境変数があります。 sudo
のような既存のアプローチを好む 可能であれば。]