CentOS7上で SE Linux の独自ラベル、独自ドメイン、ルール(allow)を定義してみた

# やってみたこと

CentOS7上で、

- 独自タイプ定義
- 独自ドメイン定義
- ドメイン遷移定義
- 独自 allow ルール定義

をやってみました。
ネット上にも資料が少なく、かなり苦労しました…
＃既存マクロの一部を書き換えての対応が必要だったり…

# [SE Linux] 実習環境 on CentOS7

## (事前準備)

### 関連パッケージのインストール

```bash
$ sudo yum install selinux-policy-mls
$ sudo yum install selinux-policy-devel
```

### /etc/selinux/config書き換え

  SELINUX=permissive ※絶対にenforcingのままにしないこと！
  SELINUXTYPE=mls    ※selinux-policy-mlsをインストールしないと起動不可になるよ！

## こんな風にします(ファイルの配置とラベル)

```text
  /home/tomonobu/
    + mypolicy/ ......... 独自ポリシー置場
    |   + Makefile    ... ビルド用メイクファイル
    |   + mypolicy.te ... teファイル
    |   + mypolicy.fc ... fcファイル
    |
    + myapp/myapp ... ドメイン (my_secure_app_t) / タイプ (my_secure_app_exec_t)
    + secure_data ... タイプ   (my_secure_data_t)
        + hello.txt
```

## 作業内容(ほとんど作業メモですが)

### /home/tomonobu/secure_data に my_secure_data_t を付与

```bash
  $ mkdir mypolicy
  $ cd mypolicy
  $ touch mypolicy.te
  $ touch mypolicy.fc
  $ cp /usr/share/selinux/devel/Makefile .

  $ vi mypolicy.te
  -----
  module mypolicy 1.0;          # mypolicyはファイル名と合わせる(合わせないとエラー)
  type my_secure_data_t;
  file_type(my_secure_data_t)
  -----

  $ vi mypolicy.fc
  -----
  /home/tomonobu/secure_data(/.*)? gen_context(system_u:object_r:my_secure_data_t, s0)
  -----

  $ make
  $ tree
  .
  ├─ Makefile
  ├─ mypolicy.fc
  ├─ mypolicy.if *
  ├─ mypolicy.pp *
  ├─ mypolicy.te
  └─ tmp *
      ├─ all_interfaces.conf *
      ├─ iferror.m4 *
      └─ mypolicy.tmp *
```

  makeすると * のファイルが出来上がる

```bash

  $ sudo semodule -i mypolicy.pp # ポリシーのインストール

  $ cd
  $ mkdir secure_data
  $ restoreconf -RF .
  $ ls -Z
  -rwxrwxr-x. tomonobu tomonobu user_u:object_r:user_home_t:s0   a.out
  -rw-rw-r--. tomonobu tomonobu user_u:object_r:user_home_t:s0   hello.c
  drwxrwxr-x. tomonobu tomonobu user_u:object_r:user_home_t:s0   mypolicy
  drwxrwxr-x. tomonobu tomonobu user_u:object_r:user_home_t:s0 secure_data
                                                ^^^^^^^^^^^
```

  独自タイプ(my_secure_data_t)がついていない(想定内)
  ホームディレクトリ配下に独自ラベルを付けるためには、以下の対応が必要

```bash
  $ cd /etc/selinux/mls/contexts/files
                    ^^^
                    SELINUXTYPEと連動する
  $ vi file_contexts
  $ cat file_contexts | grep tomonobu
  /home/tomonobu/secure_data(/.*)?        system_u:object_r:my_secure_data_t:s0

  $ sudo vi file_contexts          ... 上記の行を消す
  $ sudo vi file_contexts.homedirs ... 上記の行を追加する

  $ cd
  $ restorecon -RF .
  $ ls -Z
  -rwxrwxr-x. tomonobu tomonobu user_u:object_r:user_home_t:s0   a.out
  -rw-rw-r--. tomonobu tomonobu user_u:object_r:user_home_t:s0   hello.c
  drwxrwxr-x. tomonobu tomonobu user_u:object_r:user_home_t:s0   mypolicy
  drwxrwxr-x. tomonobu tomonobu system_u:object_r:my_secure_data_t:s0 secure_data
                                                  ^^^^^^^^^^^^^^^^
                                                  OK!!
```

### audit.logの確認

```bash
  $ echo "hello" > secure_data/hello.txt

  $ su
  # cd /var/log/audit

  # grep hello audit.log
  type=AVC msg=audit(1516640677.824:259): avc:  denied  { add_name } for  pid=1108 comm="bash" name="hello.txt" scontext=user_u:user_r:user_t:s0 tcontext=system_u:object_r:my_secure_data_t:s0 tclass=dir
  type=AVC msg=audit(1516640677.824:259): avc:  denied  { create } for  pid=1108 comm="bash" name="hello.txt" scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:my_secure_data_t:s0 tclass=file
  type=AVC msg=audit(1516640677.824:259): avc:  denied  { write open } for  pid=1108 comm="bash" path="/home/tomonobu/secure_data/hello.txt" dev="dm-0" ino=17104421 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:my_secure_data_t:s0 tclass=file

  # grep secure_data audit.log もしてみていろいろ確認してみよう
```
### myappの作成と audit.log の確認

```bash
  $ cd
  $ mkdir myapp
  $ cd myapp
  $ vi myapp.c
```

/home/tomonobu/secure_data 以下のファイルを触りに行くコードを書きます。
(hello.txtは echo "hello" > hello.txt とでもして作っておいてください)

```C
  #include <stdio.h>

  #define SIZE 256

  int main(int argc, char** argv) {
      FILE *fp;
      char buf[SIZE];

      fp = fopen("/home/tomonobu/secure_data/hello.txt", "r");
      if (NULL == fp) {
          printf("ERROR : fopen\n");
          return -1;
      }
      else {
          while (fgets(buf, SIZE, fp) != NULL) {
              printf("%s", buf);
          }
      }
      fclose(fp);

      return 0;
  }
```

実行して、audit.log の avcエラーを確認してみます。

```bash
  $ echo "hello" > /home/tomonobu/secure_data/hello.txt
  $ gcc myapp.c -o myapp
  $ myapp

  $ su
  # cd /var/log/audit
  # grep myapp audit.log
  type=AVC msg=audit(1516641337.815:295): avc:  denied  { read } for  pid=1448 comm="myapp" name="hello.txt" dev="dm-0" ino=17104421 scontext=user_u:user_r:user_t:s0 tcontext=user_u:object_r:my_secure_data_t:s0 tclass=file
```
※ myapp が hello.txt を読もうとして read の avcエラー が出ている (期待動作)

### myappにドメインの付与(ドメインの準備と付与)

```bash
  $ cd
  $ cd mypolicy

  $ vi mypolicy.te
  -----
  policy_module(mypolicy, 2.0)

  type my_secure_data_t;
  files_type(my_secure_data_t)

  type my_secure_app_exec_t;
  files_type(my_secure_app_exec_t)

  type my_secure_app_t;
  domain_type(my_secure_app_t)
  domain_entry_file(my_secure_app_t, my_secure_app_exec_t)
  unconfined_domtrans_to(my_secure_app_t, my_secure_app_exec_t)

  allow my_secure_app_t my_secure_data_t:file read_file_perms;
  -----

  $ vi mypolicy.fc
  -----
  /home/tomonobu/secure_data(/.*)? gen_context(system_u:object_r:my_secure_data_t, s0)
  /home/tomonobu/myapp/myapp gen_context(system_u:object_r:my_secure_app_exec_t, s0)
  -----

  $ make clean
  $ make
  $ sudo semodule -i mypolicy.pp
  Failed to resolve typeattributeset statement at /etc/selinux/mls/tmp/modules/400/mypolicy/cil:22
  semodule:  Failed!
```

  ※ Fail...
  ※ なんとなく、過去に自分で作ったラベルと当たっちゃっててエラーになっている気がする...
> (事実を知った俺より過去の俺へ...)
違う
mlsには unconfied_t の定義が無いのに、
unconfied_domtrans_toマクロ内で利用しているので "Failt to resolve typeatributeset" となっている。
(エラー原因のラベル名をエラーメッセージに出してほしいよね...)

  unconfined_domtrans_to(my_secure_app_t, my_secure_app_exec_t)
  の行があると、上記エラーが出る。
  逆にこの一行を消すと上記エラーは発生しない。(一行ずつコメントアウトして確かめたよ... orz)

  http://linux.k-sakabe.com/LinuxSecurityEx.pdf
  とか
  https://qiita.com/bonon0/items/b027b673ef98af3ed4fd
  とか
  みても、正しそうだけどなぁ...

  /usr/share/selinux/devel/ にて grep "unconfined_domtrans_to"
  ↓
  ./devel/include/roles/unconfineduser.if:interface(`unconfined_domtrans_to',` ※これを見てみると...
  ./devel/include/roles.xml:<interface name="unconfined_domtrans_to" lineno="119">
  ./devel/policy.xml:<interface name="unconfined_domtrans_to" lineno="119">

  ※マクロ定義かな？？

  /usr/share/selinux/devel/include/roles/unconfineduser.if

```text
  ########################################
  ## <summary>
  ##      Allow unconfined to execute the specified program in
  ##      the specified domain.
  ## </summary>
  ## <desc>
  ##      <p>
  ##      Allow unconfined to execute the specified program in
  ##      the specified domain.
  ##      </p>
  ##      <p>
  ##      This is a interface to support third party modules
  ##      and its use is not allowed in upstream reference
  ##      policy.
  ##      </p>
  ## </desc>
  ## <param name="domain">
  ##      <summary>
  ##      Domain to execute in.
  ##      </summary>
  ## </param>
  ## <param name="entry_file">
  ##      <summary>
  ##      Domain entry point file.
  ##      </summary>
  ## </param>
  #
  interface(`unconfined_domtrans_to',`
          gen_require(`
                  type unconfined_t;
          ')

          domtrans_pattern(unconfined_t,$2,$1)
  ')
```

  ん？
  mlsだと、unconfied_t が定義されていなくてこけている？？？ <-- 正解

  ここを

```text
  interface(`unconfined_domtrans_to',`
          gen_require(`
                  type user_t;
          ')

          domtrans_pattern(user_t,$2,$1)
  ')
```

  に変更してみた。(ps -Z すると、bashやpsが user_t で動作している様子なので)

  ==> 通った！！！

```bash
  $ cd
  $ cd myapp
  $ ./myapp
```

  で audit.log の確認

```bash
type=AVC msg=audit(1516646161.634:861): avc:  denied  { search } for  pid=3023 comm="myapp" name="secure_data" dev="dm-0" ino=17104418 scontext=user_u:user_r:my_secure_app_t:s0 tcontext=user_u:object_r:user_home_t:s0 tclass=dir
type=AVC msg=audit(1516646161.634:861): avc:  denied  { read } for  pid=3023 comm="myapp" name="hello.txt" dev="dm-0" ino=17104421 scontext=user_u:user_r:my_secure_app_t:s0 tcontext=user_u:object_r:user_home_t:s0 tclass=file
type=AVC msg=audit(1516646161.634:861): avc:  denied  { open } for  pid=3023 comm="myapp" path="/home/tomonobu/secure_data/hello.txt" dev="dm-0" ino=17104421 scontext=user_u:user_r:my_secure_app_t:s0 tcontext=user_u:object_r:user_home_t:s0 tclass=file
type=AVC msg=audit(1516646161.636:862): avc:  denied  { getattr } for  pid=3023 comm="myapp" path="/home/tomonobu/secure_data/hello.txt" dev="dm-0" ino=17104421 scontext=user_u:user_r:my_secure_app_t:s0 tcontext=user_u:object_r:user_home_t:s0 tclass=file
type=AVC msg=audit(1516646161.636:863): avc:  denied  { getattr } for  pid=3023 comm="myapp" path="/dev/pts/0" dev="devpts" ino=3 scontext=user_u:user_r:my_secure_app_t:s0 tcontext=user_u:object_r:user_devpts_t:s0 tclass=chr_file
```

  ログアウト・ログイン で 再度試す

```bash
  type=AVC msg=audit(1516646161.636:863): avc:  denied  { getattr } for  pid=3023 comm="myapp" path="/dev/pts/0" dev="devpts" ino=3 scontext=user_u:user_r:my_secure_app_t:s0 tcontext=user_u:object_r:user_devpts_t:s0 tclass=chr_file
  ------
  type=AVC msg=audit(1516646477.318:945): avc:  denied  { read write } for  pid=3087 comm="myapp" path="/dev/pts/0" dev="devpts" ino=3 scontext=user_u:user_r:my_secure_app_t:s0 tcontext=user_u:object_r:user_devpts_t:s0 tclass=chr_file
  type=AVC msg=audit(1516646477.321:946): avc:  denied  { getattr } for  pid=3087 comm="myapp" path="/dev/pts/0" dev="devpts" ino=3 scontext=user_u:user_r:my_secure_app_t:s0 tcontext=user_u:object_r:user_devpts_t:s0 tclass=chr_file
  ------
```

  863以降は、hello.txtに対するアクセスエラーは出ていない様子

  ==> 成功っぽい ★要検証

- 検証方法-1) mypolicy.teから allow 行を消して検証
- 検証方法-2) myappを無限ループさせて、ps -Z で ドメインチェック

  ※ dev/pts/0 についてはこちら
  http://piyopiyocs.blog115.fc2.com/blog-entry-663.html