Auditについて

Linux2.6にはauditが入っている。
SELinuxなどのセキュアOSでは、これを使ってログ取ってるが、あまり知られていない。
組込み種ITやってたら、auditを直す必要に迫られたので、解析してみよう。

auditの構成

  • カーネル部分
    • kernel/audit.c
      • audit本体。kauditが動作。kauditは、netlinkソケットで接続待ちするカーネル空間で動作するデーモン。ログメッセージの窓口となるデーモン
    • kernel/auditsc.c
    • kernel/auditfilter.c
      • ソース読み中
  • ユーザランド
  • auditd,auditctl等
    • auditdはユーザランドで動くデーモンで、kauditd->auditd->audit.log書きこみのようにログが取られる。auditctlは、カーネルのauditのパラメータ調整などをする。auditdが動いてない場合は、kauditd->コンソールやsyslogのように飛ぶので、ユーザランドコンポーネントは必須ではない
    • 他、dispatchなどの仕組みもあるみたいだが、今回は飛ばす。

組込みSELinuxのauditの問題

SELinuxのアクセス拒否ログは、

type=PATH <アクセスしたファイルのフルパス情報>
type=AVC <アクセス拒否情報、ファイル名は、フルパスじゃない>

のように2種類の項目が出る(他にも色々出るけど、主なもの)

が、なぜかSHアーキテクチャだと、
type=AVCは出るのだが、type=PATHに相当する部分が出ないことが発覚。
これだと、アクセス拒否されたファイルのフルパスが分からなくて困る。
さて、何で出ないのかと調べてみると、、
type=PATHのログは、システムコールのログ取得部分(kernel/auditsc.c)で出力される。
が、auditsc.cの処理を正しく動かすためには、arch以下に手を加える必要がある。
が、SHでは、この対応がまだだったので、動かなかった。
auditはアーキテクチャ依存だったのか。。

SHでもauditを使えるようにしてみる

以下自分用メモ

システムコールの入口、出口の部分で、
audit関連の関数を呼ぶようにすればいい。

さて、システムコールの入口出口は、
SHの場合、arch/sh/entry-common.S
のようだ。これはアセンブラ。ついにアセンブラをいじる羽目に。

例えば、
システムコール出口のコードは以下のようだ。

arch/sh/entry-common.S
224 syscall_exit_work:
225         ! r0: current_thread_info->flags
226         ! r8: current_thread_info
227         tst     #_TIF_SYSCALL_TRACE, r0
228         bt/s    work_pending
229          tst    #_TIF_NEED_RESCHED, r0
230 #ifdef CONFIG_TRACE_IRQFLAGS
231         mov.l   5f, r0
232         jsr     @r0
233          nop
234 #endif
235         sti
236         ! XXX setup arguments...
237         mov.l   4f, r0                  ! do_syscall_trace
238         jsr     @r0         ->do_syscall_trace関数呼び出し
... 
407 4:      .long   do_syscall_trace

syscall_exit_workというところで始まり、

237 mov.l 4f, r0 ! do_syscall_trace
で、ptrace.cのdo_syscall_traceに処理が飛ぶ。
まず、このdo_syscall_trace(ptrace.c中)を、auditの処理をするように修正。

また、
auditに必要な情報として、do_syscall_traceに
システムコール番号と、
レジスタ情報を渡す必要がある

コードを眺めてみると、SHでは、
r3レジスタシステムコール番号、
r15レジスタがスタックポインタ、r15周辺に各種レジスタが退避されてるようだ。
r3、r15の値を、do_syscall_traceに渡せばいいはず。。
また、do_syscall_trace内では、
r4が第一引数、r5が第二引き数として使われる。
なので、r4にr3をコピー、r5にr15をコピーすればいい。

236         ! XXX setup arguments...
	    mov     r3   r4
            mov     r15  r5
237         mov.l   4f, r0                  ! do_syscall_trace
238         jsr     @r0

で、ゴニョゴニョやってみたら、
システムコールのログが取れるようになった。
auditdを使わない場合は、audit=1をカーネル起動パラメータに渡さないと、システムコールのログが出ないのに注意。


が、これでもなお念願のPATHエントリが出ない。。。
auditdを動かすと出るようだが、auditdを入れるのは面倒なので、
auditdは抜きにしたい。原因調査中。

kernel/auditsc.c
1080 void audit_syscall_entry(int arch, int major,
1081                          unsigned long a1, unsigned long a2,
1082                          unsigned long a3, unsigned long a4)
1083 {
..
1139         context->dummy = !audit_n_rules;
→context->dummyは、audit_n_rulesがゼロだと、1にセットされる

で、PATH取得に使われる処理は、context->dummyが1だと、何もしない。

ということは、PATH取得のためには、audit_n_rulesを何でもいいので非ゼロにする必要がある。それか、context->dummyに1をゼロにセットすればいいのか??