Red Hat Training

A Red Hat training course is available for RHEL 8

8.2. カスタムアプリケーション用の SELinux ポリシーの作成および実施

この手順例では、SELinux で単純なデーモンを指定する手順を説明します。デーモンをカスタムアプリケーションに置き換え、そのアプリケーションとセキュリティーポリシーの要件に従ってサンプルルールを変更します。

前提条件

  • policycoreutils-devel パッケージとその依存関係がシステムにインストールされている。

手順

  1. この手順例では、/var/log/messages ファイルを開いて書き込みを行う簡単なデーモンを準備します。

    1. 新しいファイルを作成して、選択したテキストエディターで開きます。

      $ vi mydaemon.c
    2. 以下のコードを挿入します。

      #include <unistd.h>
      #include <stdio.h>
      
      FILE *f;
      
      int main(void)
      {
      while(1) {
      f = fopen("/var/log/messages","w");
              sleep(5);
              fclose(f);
          }
      }
    3. ファイルをコンパイルします。

      $ gcc -o mydaemon mydaemon.c
    4. デーモンの systemd ユニットファイルを作成します。

      $ vi mydaemon.service
      [Unit]
      Description=Simple testing daemon
      
      [Service]
      Type=simple
      ExecStart=/usr/local/bin/mydaemon
      
      [Install]
      WantedBy=multi-user.target
    5. デーモンをインストールして起動します。

      # cp mydaemon /usr/local/bin/
      # cp mydaemon.service /usr/lib/systemd/system
      # systemctl start mydaemon
      # systemctl status mydaemon
      ● mydaemon.service - Simple testing daemon
         Loaded: loaded (/usr/lib/systemd/system/mydaemon.service; disabled; vendor preset: disabled)
         Active: active (running) since Sat 2020-05-23 16:56:01 CEST; 19s ago
       Main PID: 4117 (mydaemon)
          Tasks: 1
         Memory: 148.0K
         CGroup: /system.slice/mydaemon.service
                 └─4117 /usr/local/bin/mydaemon
      
      May 23 16:56:01 localhost.localdomain systemd[1]: Started Simple testing daemon.
    6. 新しいデーモンが SELinux によって制限されていないことを確認します。

      $ ps -efZ | grep mydaemon
      system_u:system_r:unconfined_service_t:s0 root 4117    1  0 16:56 ?        00:00:00 /usr/local/bin/mydaemon
  2. デーモンのカスタムポリシーを生成します。

    $ sepolicy generate --init /usr/local/bin/mydaemon
    Created the following files:
    /home/example.user/mysepol/mydaemon.te # Type Enforcement file
    /home/example.user/mysepol/mydaemon.if # Interface file
    /home/example.user/mysepol/mydaemon.fc # File Contexts file
    /home/example.user/mysepol/mydaemon_selinux.spec # Spec file
    /home/example.user/mysepol/mydaemon.sh # Setup Script
  3. 直前のコマンドで作成した設定スクリプトを使用して、新しいポリシーモジュールでシステムポリシーを再構築します。

    # ./mydaemon.sh
    Building and Loading Policy
    + make -f /usr/share/selinux/devel/Makefile mydaemon.pp
    Compiling targeted mydaemon module
    Creating targeted mydaemon.pp policy package
    rm tmp/mydaemon.mod.fc tmp/mydaemon.mod
    + /usr/sbin/semodule -i mydaemon.pp
    ...

    restorecon コマンドを使用して、設定スクリプトがファイルシステムの対応する部分の再ラベル付けを行うことに注意してください。

    restorecon -v /usr/local/bin/mydaemon /usr/lib/systemd/system
  4. デーモンを再起動して、SELinux が制限のあるデーモンを実行していることを確認します。

    # systemctl restart mydaemon
    $ ps -efZ | grep mydaemon
    system_u:system_r:mydaemon_t:s0 root        8150       1  0 17:18 ?        00:00:00 /usr/local/bin/mydaemon
  5. デーモンは SELinux によって制限されているため、SELinux はこのデーモンが /var/log/messages にアクセスできないようにします。対応する拒否メッセージを表示します。

    # ausearch -m AVC -ts recent
    ...
    type=AVC msg=audit(1590247112.719:5935): avc:  denied  { open } for  pid=8150 comm="mydaemon" path="/var/log/messages" dev="dm-0" ino=2430831 scontext=system_u:system_r:mydaemon_t:s0 tcontext=unconfined_u:object_r:var_log_t:s0 tclass=file permissive=1
    ...
  6. sealert ツールを使用して追加情報を取得することもできます。

    $ sealert -l "*"
    SELinux is preventing mydaemon from open access on the file /var/log/messages.
    
     Plugin catchall (100. confidence) suggests *
    
    If you believe that mydaemon should be allowed open access on the messages file by default.
    Then you should report this as a bug.
    You can generate a local policy module to allow this access.
    Do
    allow this access for now by executing:
    # ausearch -c 'mydaemon' --raw | audit2allow -M my-mydaemon
    # semodule -X 300 -i my-mydaemon.pp
    
    Additional Information:
    Source Context                system_u:system_r:mydaemon_t:s0
    Target Context                unconfined_u:object_r:var_log_t:s0
    Target Objects                /var/log/messages [ file ]
    Source                        mydaemon
    
    ...
  7. audit2allow ツールを使用して、変更を提案します。

    $ ausearch -m AVC -ts recent | audit2allow -R
    
    require {
    	type mydaemon_t;
    }
    
    #============= mydaemon_t ==============
    logging_write_generic_logs(mydaemon_t)
  8. audit2allow が提案するルールは特定のケースでは正しくない可能性があるため、出力の一部のみを使用して対応するポリシーインターフェイスを見つけます。

    $ grep -r "logging_write_generic_logs" /usr/share/selinux/devel/include/ | grep .if
    /usr/share/selinux/devel/include/system/logging.if:interface(`logging_write_generic_logs',`
  9. インターフェイスの定義を確認します。

    $ cat /usr/share/selinux/devel/include/system/logging.if
    ...
    interface(`logging_write_generic_logs',`
            gen_require(`
                    type var_log_t;
            ')
    
            files_search_var($1)
            allow $1 var_log_t:dir list_dir_perms;
            write_files_pattern($1, var_log_t, var_log_t)
    ')
    ...
  10. この場合は、推奨されるインターフェイスを使用できます。Type Enforcement ファイルに対応するルールを追加します。

    $ echo "logging_write_generic_logs(mydaemon_t)" >> mydaemon.te

    または、インターフェイスを使用する代わりに、このルールを追加することもできます。

    $ echo "allow mydaemon_t var_log_t:file { open write getattr };" >> mydaemon.te
  11. ポリシーを再インストールします。

    # ./mydaemon.sh
    Building and Loading Policy
    + make -f /usr/share/selinux/devel/Makefile mydaemon.pp
    Compiling targeted mydaemon module
    Creating targeted mydaemon.pp policy package
    rm tmp/mydaemon.mod.fc tmp/mydaemon.mod
    + /usr/sbin/semodule -i mydaemon.pp
    ...

検証

  1. アプリケーションが SELinux によって制限されて実行されていることを確認します。以下に例を示します。

    $ ps -efZ | grep mydaemon
    system_u:system_r:mydaemon_t:s0 root        8150       1  0 17:18 ?        00:00:00 /usr/local/bin/mydaemon
  2. カスタムアプリケーションが SELinux 拒否を生じさせないことを確認します。

    # ausearch -m AVC -ts recent
    <no matches>

関連情報

  • sepolgen(8)ausearch(8)audit2allow(1)audit2why(1)sealert(8)、および restorecon(8) の man ページ