Back to home page

OSCL-LXR

 
 

    


0001 Overview
0002 ========
0003 
0004 For general security related questions of perf_event_open() syscall usage,
0005 performance monitoring and observability operations by Perf see here:
0006 https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html
0007 
0008 Enabling LSM based mandatory access control (MAC) to perf_event_open() syscall
0009 ==============================================================================
0010 
0011 LSM hooks for mandatory access control for perf_event_open() syscall can be
0012 used starting from Linux v5.3. Below are the steps to extend Fedora (v31) with
0013 Targeted policy with perf_event_open() access control capabilities:
0014 
0015 1. Download selinux-policy SRPM package (e.g. selinux-policy-3.14.4-48.fc31.src.rpm on FC31)
0016    and install it so rpmbuild directory would exist in the current working directory:
0017 
0018    # rpm -Uhv selinux-policy-3.14.4-48.fc31.src.rpm
0019 
0020 2. Get into rpmbuild/SPECS directory and unpack the source code:
0021 
0022    # rpmbuild -bp selinux-policy.spec
0023 
0024 3. Place patch below at rpmbuild/BUILD/selinux-policy-b86eaaf4dbcf2d51dd4432df7185c0eaf3cbcc02
0025    directory and apply it:
0026 
0027    # patch -p1 < selinux-policy-perf-events-perfmon.patch
0028    patching file policy/flask/access_vectors
0029    patching file policy/flask/security_classes
0030    # cat selinux-policy-perf-events-perfmon.patch
0031 diff -Nura a/policy/flask/access_vectors b/policy/flask/access_vectors
0032 --- a/policy/flask/access_vectors       2020-02-04 18:19:53.000000000 +0300
0033 +++ b/policy/flask/access_vectors       2020-02-28 23:37:25.000000000 +0300
0034 @@ -174,6 +174,7 @@
0035         wake_alarm
0036         block_suspend
0037         audit_read
0038 +       perfmon
0039  }
0040  
0041  #
0042 @@ -1099,3 +1100,15 @@
0043  
0044  class xdp_socket
0045  inherits socket
0046 +
0047 +class perf_event
0048 +{
0049 +       open
0050 +       cpu
0051 +       kernel
0052 +       tracepoint
0053 +       read
0054 +       write
0055 +}
0056 +
0057 +
0058 diff -Nura a/policy/flask/security_classes b/policy/flask/security_classes
0059 --- a/policy/flask/security_classes     2020-02-04 18:19:53.000000000 +0300
0060 +++ b/policy/flask/security_classes     2020-02-28 21:35:17.000000000 +0300
0061 @@ -200,4 +200,6 @@
0062  
0063  class xdp_socket
0064  
0065 +class perf_event
0066 +
0067  # FLASK
0068 
0069 4. Get into rpmbuild/SPECS directory and build policy packages from patched sources:
0070 
0071    # rpmbuild --noclean --noprep -ba selinux-policy.spec
0072 
0073    so you have this:
0074 
0075    # ls -alh rpmbuild/RPMS/noarch/
0076    total 33M
0077    drwxr-xr-x. 2 root root 4.0K Mar 20 12:16 .
0078    drwxr-xr-x. 3 root root 4.0K Mar 20 12:16 ..
0079    -rw-r--r--. 1 root root 112K Mar 20 12:16 selinux-policy-3.14.4-48.fc31.noarch.rpm
0080    -rw-r--r--. 1 root root 1.2M Mar 20 12:17 selinux-policy-devel-3.14.4-48.fc31.noarch.rpm
0081    -rw-r--r--. 1 root root 2.3M Mar 20 12:17 selinux-policy-doc-3.14.4-48.fc31.noarch.rpm
0082    -rw-r--r--. 1 root root  12M Mar 20 12:17 selinux-policy-minimum-3.14.4-48.fc31.noarch.rpm
0083    -rw-r--r--. 1 root root 4.5M Mar 20 12:16 selinux-policy-mls-3.14.4-48.fc31.noarch.rpm
0084    -rw-r--r--. 1 root root 111K Mar 20 12:16 selinux-policy-sandbox-3.14.4-48.fc31.noarch.rpm
0085    -rw-r--r--. 1 root root  14M Mar 20 12:17 selinux-policy-targeted-3.14.4-48.fc31.noarch.rpm
0086 
0087 5. Install SELinux packages from Fedora repo, if not already done so, and
0088    update with the patched rpms above:
0089 
0090    # rpm -Uhv rpmbuild/RPMS/noarch/selinux-policy-*
0091 
0092 6. Enable SELinux Permissive mode for Targeted policy, if not already done so:
0093 
0094    # cat /etc/selinux/config
0095 
0096    # This file controls the state of SELinux on the system.
0097    # SELINUX= can take one of these three values:
0098    #     enforcing - SELinux security policy is enforced.
0099    #     permissive - SELinux prints warnings instead of enforcing.
0100    #     disabled - No SELinux policy is loaded.
0101    SELINUX=permissive
0102    # SELINUXTYPE= can take one of these three values:
0103    #     targeted - Targeted processes are protected,
0104    #     minimum - Modification of targeted policy. Only selected processes are protected.
0105    #     mls - Multi Level Security protection.
0106    SELINUXTYPE=targeted
0107 
0108 7. Enable filesystem SELinux labeling at the next reboot:
0109 
0110    # touch /.autorelabel
0111 
0112 8. Reboot machine and it will label filesystems and load Targeted policy into the kernel;
0113 
0114 9. Login and check that dmesg output doesn't mention that perf_event class is unknown to SELinux subsystem;
0115 
0116 10. Check that SELinux is enabled and in Permissive mode
0117 
0118     # getenforce
0119     Permissive
0120 
0121 11. Turn SELinux into Enforcing mode:
0122 
0123     # setenforce 1
0124     # getenforce
0125     Enforcing
0126 
0127 Opening access to perf_event_open() syscall on Fedora with SELinux
0128 ==================================================================
0129 
0130 Access to performance monitoring and observability operations by Perf
0131 can be limited for superuser or CAP_PERFMON or CAP_SYS_ADMIN privileged
0132 processes. MAC policy settings (e.g. SELinux) can be loaded into the kernel
0133 and prevent unauthorized access to perf_event_open() syscall. In such case
0134 Perf tool provides a message similar to the one below:
0135 
0136    # perf stat
0137    Error:
0138    Access to performance monitoring and observability operations is limited.
0139    Enforced MAC policy settings (SELinux) can limit access to performance
0140    monitoring and observability operations. Inspect system audit records for
0141    more perf_event access control information and adjusting the policy.
0142    Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open
0143    access to performance monitoring and observability operations for users
0144    without CAP_PERFMON or CAP_SYS_ADMIN Linux capability.
0145    perf_event_paranoid setting is -1:
0146      -1: Allow use of (almost) all events by all users
0147          Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK
0148    >= 0: Disallow raw and ftrace function tracepoint access
0149    >= 1: Disallow CPU event access
0150    >= 2: Disallow kernel profiling
0151    To make the adjusted perf_event_paranoid setting permanent preserve it
0152    in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>)
0153 
0154 To make sure that access is limited by MAC policy settings inspect system
0155 audit records using journalctl command or /var/log/audit/audit.log so the
0156 output would contain AVC denied records related to perf_event:
0157 
0158    # journalctl --reverse --no-pager | grep perf_event
0159 
0160    python3[1318099]: SELinux is preventing perf from open access on the perf_event labeled unconfined_t.
0161                                          If you believe that perf should be allowed open access on perf_event labeled unconfined_t by default.
0162    setroubleshoot[1318099]: SELinux is preventing perf from open access on the perf_event labeled unconfined_t. For complete SELinux messages run: sealert -l 4595ce5b-e58f-462c-9d86-3bc2074935de
0163    audit[1318098]: AVC avc:  denied  { open } for  pid=1318098 comm="perf" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tclass=perf_event permissive=0
0164 
0165 In order to open access to perf_event_open() syscall MAC policy settings can
0166 require to be extended. On SELinux system this can be done by loading a special
0167 policy module extending base policy settings. Perf related policy module can
0168 be generated using the system audit records about blocking perf_event access.
0169 Run the command below to generate my-perf.te policy extension file with
0170 perf_event related rules:
0171 
0172    # ausearch -c 'perf' --raw | audit2allow -M my-perf && cat my-perf.te
0173 
0174    module my-perf 1.0;
0175 
0176    require {
0177         type unconfined_t;
0178         class perf_event { cpu kernel open read tracepoint write };
0179    }
0180 
0181    #============= unconfined_t ==============
0182    allow unconfined_t self:perf_event { cpu kernel open read tracepoint write };
0183 
0184 Now compile, pack and load my-perf.pp extension module into the kernel:
0185 
0186    # checkmodule -M -m -o my-perf.mod my-perf.te
0187    # semodule_package -o my-perf.pp -m my-perf.mod
0188    # semodule -X 300 -i my-perf.pp
0189 
0190 After all those taken steps above access to perf_event_open() syscall should
0191 now be allowed by the policy settings. Check access running Perf like this:
0192 
0193    # perf stat
0194    ^C
0195    Performance counter stats for 'system wide':
0196 
0197          36,387.41 msec cpu-clock                 #    7.999 CPUs utilized
0198              2,629      context-switches          #    0.072 K/sec
0199                 57      cpu-migrations            #    0.002 K/sec
0200                  1      page-faults               #    0.000 K/sec
0201        263,721,559      cycles                    #    0.007 GHz
0202        175,746,713      instructions              #    0.67  insn per cycle
0203         19,628,798      branches                  #    0.539 M/sec
0204          1,259,201      branch-misses             #    6.42% of all branches
0205 
0206        4.549061439 seconds time elapsed
0207 
0208 The generated perf-event.pp related policy extension module can be removed
0209 from the kernel using this command:
0210 
0211    # semodule -X 300 -r my-perf
0212 
0213 Alternatively the module can be temporarily disabled and enabled back using
0214 these two commands:
0215 
0216    # semodule -d my-perf
0217    # semodule -e my-perf
0218 
0219 If something went wrong
0220 =======================
0221 
0222 To turn SELinux into Permissive mode:
0223    # setenforce 0
0224 
0225 To fully disable SELinux during kernel boot [3] set kernel command line parameter selinux=0
0226 
0227 To remove SELinux labeling from local filesystems:
0228    # find / -mount -print0 | xargs -0 setfattr -h -x security.selinux
0229 
0230 To fully turn SELinux off a machine set SELINUX=disabled at /etc/selinux/config file and reboot;
0231 
0232 Links
0233 =====
0234 
0235 [1] https://download-ib01.fedoraproject.org/pub/fedora/linux/updates/31/Everything/SRPMS/Packages/s/selinux-policy-3.14.4-49.fc31.src.rpm
0236 [2] https://docs.fedoraproject.org/en-US/Fedora/11/html/Security-Enhanced_Linux/sect-Security-Enhanced_Linux-Working_with_SELinux-Enabling_and_Disabling_SELinux.html
0237 [3] https://danwalsh.livejournal.com/10972.html