rootとしてローカルロギングデーモンを実行します。Unixドメインソケット(通常/var/run/my-logger.socket
または同様のもの)でリッスンします。
単純なログライブラリを作成します。このライブラリでは、イベントメッセージがUnixドメインソケットを介してローカルで実行されているデーモンに送信されます。イベントごとに、補助メッセージを介してプロセスクレデンシャルも送信します。詳細については、 man7unixを参照してください。
ローカルロギングデーモンはメッセージを受信すると、補助メッセージをチェックし、メッセージがない場合はメッセージを破棄します。クレデンシャルのuid
とgid
は、ロギング要求を送信したプロセスを誰が実行しているかを正確に示します。これらはカーネル自体によって検証されるため、(root権限がない限り)なりすましはできません。
ここに巧妙なビットがあります。デーモンPID
は、資格情報をチェックインし、その値に基づいて、をチェックします/proc/PID/exe
。これは、メッセージを送信するプロセスによって実行されている実際のプロセスバイナリへのシンボリックリンクであり、ユーザーが偽造することはできません。メッセージを偽造できるようにするには、実際のバイナリを独自のバイナリで上書きする必要があり、root権限が必要です。
(競合状態が発生する可能性があります。ユーザーは同じことを行う特別なプログラムを作成し、すぐexec()
に許可されていることがわかっているバイナリを作成できます。その競合を回避するには、資格情報を確認した後にデーモンに応答させる必要があります。ロギングクライアントは(クレデンシャルを使用して)別のメッセージを送信するため、デーモンはクレデンシャルがまだ同じであり、/proc/PID/exe
symlinkが変更されていないことを確認できます。私はこれを個人的に使用して、メッセージの信憑性をチェックします(ロガーがイベントの確認を求めることにより、ランダムなCookieを使用し、イベントのチェックサムが正しいかどうかをリクエスターにチェックサムとCookieの両方で応答させます。ランダムなCookieを含めると、前に確認をソケットキューに詰め込むことができなくなりますexec()
。)
を使用すると、pid
さらにチェックを行うこともできます。たとえば、プロセスの親子関係をトレースして、sshまたはコンソールを介してログインを検出するまで親を追跡することにより、人間のユーザーがどのように接続しているかを確認できます。/proc/PID/stat
解析または/proc/PID/status
ファイル化する必要があり、移植性がないため、少し面倒です。OSXとBSDにはsysctl呼び出しがあり、親プロセスIDを見つけるために使用できるため、プラットフォーム固有の関数を記述して移植可能にすることができparent_process_of(pid_t pid)
ます。
このアプローチにより、ロギングデーモンは、1)ロギング要求がどの実行可能ファイルからのものであるか、および2)どのユーザー(およびプロセストレースを実行する場合は接続方法)がコマンドを実行したかを正確に認識します。
ローカルロギングデーモンはrootとして実行されているため、ルート専用ディレクトリ内のファイルにイベントを記録したり、メッセージをリモートマシンに転送したりできます。
明らかに、これは正確に軽量ではありませんが、1秒あたりのイベント数が12未満であると仮定すると、ロギングのオーバーヘッドは完全に無視できるはずです。