Red Hat Training

A Red Hat training course is available for RHEL 8

8.2. 为自定义应用程序创建并强制 SELinux 策略

您可以通过 SELinux 约束应用程序,以提高主机系统和用户数据的安全性。因为每个应用程序都有特定的要求,因此根据您的用例,修改这个示例流程,来创建约束一个简单的守护进程的 SELinux 策略。

先决条件

  • selinux-policy-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 建议的规则在某些情况下可能不正确,所以只使用其输出的一部分来找到对应的策略接口。使用 扩展 工具检查 logging_write_generic_logs (mydaemon_t) 宏,以查看宏提供的所有允许的规则:

    $ macro-expander "logging_write_generic_logs(mydaemon_t)"
    allow mydaemon_t var_t:dir { getattr search open };
    allow mydaemon_t var_log_t:dir { getattr search open read lock ioctl };
    allow mydaemon_t var_log_t:dir { getattr search open };
    allow mydaemon_t var_log_t:file { open { getattr write append lock ioctl } };
    allow mydaemon_t var_log_t:dir { getattr search open };
    allow mydaemon_t var_log_t:lnk_file { getattr read };
  9. 在这种情况下,您可以使用推荐的接口,因为它只提供对日志文件及其父目录的读写访问。在您的类型强制文件中添加对应的规则:

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

    另外,您可以添加这个规则而不是使用接口:

    $ echo "allow mydaemon_t var_log_t:file { open write getattr };" >> mydaemon.te
  10. 重新安装策略:

    # ./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>

其他资源