sudo + execをどのように実行しますか?

sudo + execをどのように実行しますか?

sudo他のユーザーとしてプロセスを実行するために使用する必要があります。ただし、sudo次のようなものを使用する方法は次のとおりですexec

sudo -u www-data exec php -r 'sleep(2); echo 5;'

sudoプロセスを変更しますか?

理由と要件は何ですか?

  • 総プロセス数の最小化
  • コマンドは引き続き開始されるため、一度にすべて開始することはできません。sudo
  • 解決策は何もないようにexec、つまり背景がないかのように動作するはずです。

答え1

sudo(8) のマニュアルページから:

特別な場合に、ポリシープラグインが閉じる機能を定義せずにptyを必要としない場合、sudoは最初にfork(2)を呼び出さずにコマンドを直接実行します。 sudoersポリシープラグインは、I / Oロギングが有効な場合、ptyが必要な場合、またはpam_sessionまたはpam_setcredオプションが有効になっている場合にのみシャットダウン機能を定義します。

一般的な状況では、これはプロセスがTTYから切断されていることを確認してもフォークされないことを意味します。たとえば、

sudo -u www-data php -r 'sleep(2); echo 5;' < /dev/null > /dev/null 2>&1

追加手順は省略されます。特定の出力が必要な場合は、TTY以外のファイルまたは同様のファイルに渡し、残りは上記の/dev/nullように残してください。

プロセスリストで元のsudoコマンドを見ている副作用がまだあることがわかりましたが、おそらく大丈夫でしょう。あるいは、これらの要件を補完するために、プロセスリストにプロセスの表示方法を変更するいくつかのPHP関数または同様の呼び出しがあります。

修正する:

多くのシステムでは、デフォルトでpamオプションが有効になっているようです。無効にできますが、「コマンドを実行してもリソース制限が更新されない可能性があります」などの副作用があることに注意してください。詳しくは sudoers(5) をご覧ください。グローバルに無効にするには、次の行を追加します/etc/sudoers

Defaults        !pam_setcred
Defaults        !pam_session

特定のユーザーまたは同様のユーザーに設定を制限する方法については、sudoers(5)のマニュアルページを参照してください。マニュアルページで「Default_Type」を探します。

答え2

編集:私の元の答えは次のとおりです(SOがキャンセルラインをサポートしていないので引用)。

オリジナル:

正解は単にできないということです。少なくとも安定して簡単ではありません。

修正済み:正解は「はい」です。とても慎重です。下部の付録を参照してください。

fork()他のコメント作成者が引用したセクションのマニュアルページの内容にもかかわらず、これはほとんどの場合(99.9%)システムの基本的なsudoプロセスモデルです。

htopなどのプロセスモニタを使用すると、直接真実を簡単に確認できますps --forest

提案された答え:

<?php
exec("exec sudo -u www-data php -r 'sleep(2); echo 5;' < /dev/null > /dev/null 2>&1");

遅いsudoプロセスが残ります。

php spawn-test.php
 └─ sudo -u www-data php -r 'sleep(2); echo 5;'
     └─ php -r 'sleep(2); echo 5;'

PHPがsudoを呼び出す限り、ドライバスクリプトは何らかの方法でいくつかの制御端末にバインドされます(編集:またはサブプロセスをptyに書き込みます)。

その理由は、「現代的な」sudo環境によるものかもしれません。セッションで必要なすべてのタスクを実行できるsudoチケットとプラグインにtty識別を使用してください。pam場合によっては、ほとんどのソフトウェアは通常、単にpamをコンパイルしてexecve()パスを無効にします。これには、systemd-logindなどのインタラクティブな「現代」機能があります。

sudo非常に複雑なソフトウェアなので、目的の操作を実行するのは簡単ではありません。

オリジナル:

そしてあなたの場合、これは基本的に不可能です。

編集:状況によってはまだ可能かもしれません。

ただし、複数のsudoインスタンスが子を待つようにすることは通常問題ではありません。 * nixシステムでは、プロセスは今日何百万もの.soライブラリに動的にリンクされている非常に手頃なエンティティです。

安心してsudo遅れることができます「適切に」これは、最小限のコンピューティングリソース(ほぼゼロ)を消費し、オペレーティングシステムは、実行中のすべてのインスタンス間でできるだけ多くのメモリを共有できるほどスマートであることを意味しますsudo。だから、まったく問題とは考えてはいけません。

今問題は、なぜsudo中間プロセスを削除することです。

理由が適切な理由なしにsudoプロセスを「好きではない」からだとしたら、これは間違った理由です。

もちろん、SUIDを介してrootして権限を削除することは確かに可能ですが、この方法は初心者になじみのない正しく実行するのが難しいので非常に危険です。

専門家でさえ一般的に反対するほど多すぎるので、ここではこれを達成する方法について議論しません。

しかし、十分に持続する場合は、ここでstackoverflowネットワークでもrootSUIDを介して再び切り替える方法に対する答えがあります。

このプロセスの状態では、何も信頼できず(環境変数も含む)、ターゲットユーザーにできるだけ早く(そして正しく実行する)権限を付与する必要があります。

また、デプロイメントプラットフォームによっては、selinuxやその他のセキュリティフレームワークなどを考慮することもできます。

最後に、子供のユーザーが親プロセスを駆動するユーザーと異なる場合、それ以上のプロセスを経ることなく状態を変更するように指示することはできません。

非常に困難でエラーが発生しやすいため、これが存在する唯一の理由です。ただし、すべてのユースケースに常に適しているわけではないsudoことに同意します。sudo

編集する:

pam 統合、pty 生成、ログサーバーなど、すべての高度な機能を無効にする方法については、user11658273 の回答を参照してください。これらすべての機能が機能するには無効にする必要があるようです。 PAMをローカルに設定しても、分岐しないモードでsudoする必要があります。

十分注意してください。

これを無効にすると、pam_session設定されているPAMセッションによって何かが中断される可能性があり、pam_setcredIPA、Kerberos、またはPAMによって発行された資格情報チケットに依存する他のものが中断される可能性があります。log_servers頻繁に使用しない場合、!use_ptyターゲットスクリプトは親スクリプトで設定した最初の3つのファイル記述子を継承します。この環境では、これが実際にsudoが「リモート」アカウントを認証するのを妨げるかどうかをテストすることはできません。

さらに、マシンの他のすべてのユーザーに対する潜在的なダメージを最小限に抑えるには、関連ユーザーにのみ次の特別な権限を付与する必要があります。 Defaults: yourscriptuser !pam_session,!pam_setcred,!use_pty,!log_servers

現在実行されているタスクと親スクリプトから送信されるシグナル(サブスクリプトの終了など)が機能しない可能性があることを理解してください。

$ sudo cat /etc/sudoers | grep \!use_pty
Defaults: testuser !pam_session,!pam_setcred,!use_pty,!log_servers

# in one terminal:
$ sudo sh -c 'echo $$ && exec sleep 88888' 
27749

# in other terminal:
$ kill -TERM 27749                 
kill: kill 27749 failed: operation not permitted

作業が終わった後、または標準入力ハンドルからゼロバイトを読み取るとき(つまり、頻繁に読み取られ、空の読み取りで終了する)、添え字が常に終了することを確認してください。これは、ファイルが閉じられたことを示す標準のUnixマークです(この場合は親から来るパイプの場合)、これにより親が終了したときに実行中に残っているすべての子が正しく終了します。それ以外の場合は、コードによって無期限に回転することがあります(Sudoハンドルをフォークします)。

答え3

Sudoは、指定したコマンドを実行する前にフォークします(編集:必ずしもそうではありません。他の回答を参照してください)。 execを使用してフォークを元に戻すことはできません。 bashでexecを使用すると、フォークが完全に防止されるため、bashで動作します。 sudo otohにはこの機能はありません。ただし、プログラムをバックグラウンドに分岐して中間プロセスを終了すると、次のように問題を解決できます。

sudo -u www-data bash -c "php -r 'sleep(2); echo 5;' &"

これには、元の親プロセス情報が失われ、プロセスが完了するのを待たないなど、問題になる可能性がある他の副作用があります。

答え4

ファイルに次の行を追加するだけですsudoerssudo visudoまたはを使用して編集sudo -e /etc/sudoers)。

# Run commands for all users with the exec system call directly.
# This may break some authentication systems or scripts.                              
Defaults !pam_session,!pam_setcred,!use_pty,!log_servers

# Run commands by "user" with the exec system call directly.
# This may also break authentication, but only for one user.
Defaults:user !pam_session,!pam_setcred,!use_pty,!log_servers

sudo上記の変更を実行する前に実行されていたプログラムのプロセスのリストは次のとおりです。

$ sudo sleep 500 &
[1] 4453
$ ps -f T
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
root      4453  3478  0 00:16 pts/3    S      0:00 sudo sleep 500
root      4454  4453  0 00:16 pts/3    S      0:00 sleep 500

上記のように変更した後:

$ sudo sleep 500 &
[1] 4479
$ ps -f T
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
root      4479  3478  0 00:18 pts/3    S      0:00 sleep 500

必要に応じて、異なる「デフォルト」タイプを使用して、「すべてのホストのすべてのユーザー、特定のホストのすべてのユーザー、特定のユーザー、特定のコマンド、または特定のユーザーとして実行されるコマンドに影響を与える」ことができます。sudoers(5)詳細についてはマニュアルを参照してください。

@etosanが述べたように、PAMを無効にするとPAM認証が中断され、特にマルチユーザーとリモートシステムでユーザーと管理者がロックする可能性があります。 @etosanもう1つの利点は、もともとsudoプロセスが実行されず、ユーザーに代わってシグナルを渡すことができないため、sudoを起動したユーザーとしてsudoで始まったプログラムを終了できなくなることです。場合によっては、これはセキュリティの改善と見なされる可能性がありますが、この機能に依存するプログラムが中断される可能性があります。

sudoドキュメントは常に包括的ではなく理解するのが難しいことが多いので、重要な場合はソースを読むことをお勧めします。

私のシステム(Gentoo Linuxプロファイルdefault/linux/amd64/17.1/no-multilib/hardened/selinux)では、ディストリビューションのデフォルト設定がデフォルトuse_ptyで無効になっているため、log_servers後者の2つのオプションは必要ありません。

この設定はセキュリティを弱める可能性があります。sudo以下をもう一度参照してください。sudoers(5)

pam_session  On systems that use PAM for authentication, sudo will
             create a new PAM session for the command to be run in.
             Unless sudo is given the -i or -s options, PAM session
             modules are run with the “silent” flag enabled.  This
             prevents last login information from being displayed
             for every command on some systems.  Disabling
             pam_session may be needed on older PAM implementations
             or on operating systems where opening a PAM session
             changes the utmp or wtmp files.  If PAM session support
             is disabled, resource limits may not be updated for the
             command being run.  If pam_session, pam_setcred, and
             use_pty are disabled, log_servers has not been set and
             I/O logging has not been configured, sudo will execute
             the command directly instead of running it as a child
             process.  This flag is on by default.

             This setting is only supported by version 1.8.7 or
             higher.

pam_setcred  On systems that use PAM for authentication, sudo will
             attempt to establish credentials for the target user by
             default, if supported by the underlying authentication
             system.  One example of a credential is a Kerberos
             ticket.  If pam_session, pam_setcred, and use_pty are
             disabled, log_servers has not been set and I/O logging
             has not been configured, sudo will execute the command
             directly instead of running it as a child process.
             This flag is on by default.

             This setting is only supported by version 1.8.8 or
             higher.

(デフォルトでuse_pty無効にすることができます):

use_pty      If set, and sudo is running in a terminal, the command
             will be run in a pseudo-terminal (even if no I/O log‐
             ging is being done).  If the sudo process is not at‐
             tached to a terminal, use_pty has no effect.

             A malicious program run under sudo may be capable of
             injecting commands into the user's terminal or running
             a background process that retains access to the user's
             terminal device even after the main program has fin‐
             ished executing.  By running the command in a separate
             pseudo-terminal, this attack is no longer possible.
             This flag is off by default.

関連情報