Capability audit_writeとaudit_controlの解析

まずは結論から。

  • audit_writeの意味:
    • ユーザスペースのAVCのログをカーネルに送る(拒否,許可されてもログ出ない)
  • audit_controlの意味:
    • LAuS(Linux Auditing System)の設定を変えるために必要(拒否,許可されてもログでない)
    • /proc/self/loginuidの変更(これは何意味するのだろう?)

結構困った仕様?になってるなぁ。詳しくは下を。

解析

これはトリッキーな実装。
MLでStephen Smalley氏に聞いて始めて分かった…ありがたや。
SELinuxと普通のLinuxのcapabilityが依存しているとは。
まずhooks.cから。

static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
{
        struct task_security_struct *tsec;
        struct av_decision avd;
        int err;

        err = secondary_ops->netlink_send(sk, skb);
        if (err)
                return err;

        tsec = current->security;

        avd.allowed = 0;
        avc_has_perm_noaudit(tsec->sid, tsec->sid,
                                SECCLASS_CAPABILITY, ~0, &avd);★1
        cap_mask(NETLINK_CB(skb).eff_cap, avd.allowed);  ★2

★1で,プロセスがどんなcapabilityをallowされてるかをavdにセット。
★2で, NETLINK_CB(skb).eff_capに,★1の値をセット。既存のcapabilityがあっても,SELinuxのavd.allowedをandを取る。
確か既存のcapabilityはデフォルト全ビット1なので,上書きということになる。
cap_maskは↓参照。

●capability.h
 #define cap_mask(c,mask)     do { cap_t(c) &= cap_t(mask); } while(0)

ここまでは気づいていた。この後の使われ方が難しい。
kernel/audit.cにワープ。

static int audit_netlink_ok(kernel_cap_t eff_cap, u16 msg_type)
{
        int err = 0;

        switch (msg_type) {
        case AUDIT_GET:
        case AUDIT_LIST:
        case AUDIT_SET:
        case AUDIT_ADD:
        case AUDIT_DEL:
        case AUDIT_SIGNAL_INFO:
                if (!cap_raised(eff_cap, CAP_AUDIT_CONTROL))★3
                        err = -EPERM;
                break;
        case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
                if (!cap_raised(eff_cap, CAP_AUDIT_WRITE))★4
                        err = -EPERM;
                break;
……
…省略
…
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
…
        err = audit_netlink_ok(NETLINK_CB(skb).eff_cap, msg_type);★5
       if (err)
                return err;

さて,auditメッセージをカーネルが受信するときに,★5が呼ばれる。
でこの中で★3,★4のように,
なんと★1,2でセットされた値を使ってチェックをしている!
SELinuxに関係ない場所で,SELinuxの値を使っているのはよくない気がする。
なぜなら,permissiveモードとselinux無効な場合の振る舞いが違ってくるから。
例:
1)permissiveモードで,capability:audit_control権限が足りないポリシーを書く。
2)★1、2で,capability:audit_controlがセットされない。
3)★3,4で,拒否される。しかもログも出ない
のようにpermissiveモードにも関わらず、アクセス拒否され,さらにはログが出ないという状態が発生。

ただ,
★4は,滅多に呼ばれない(つまりaudit_writeはほとんど使われない)気がする。
AUDIT_USERは,すでに廃止されてるし,
AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSGは、ユーザスペースのAVCのメッセージ(使われてないし)
★3はauditctlコマンドぐらいしかチェックされないかなぁ。

他にaudit_controlが使われてる場所

fs/proc/base.c
 if (!capable(CAP_AUDIT_CONTROL))
Smalley氏いわく,
/proc/self/loginuidに書き込む時にチェックされるそうだ。
なんかaudit_controlと意味が違う気がするが…

Capability周りは厄介だ…

追記:
Smalley氏によると,上の問題(permissiveでも拒否される恐れがある)
は以前discussされたことがあるとか。
で,パッチが出てるそうだが,なぜか本流に入ってないとか…