Commit | Line | Data |
---|---|---|
bd7c1c66 AB |
1 | Overview |
2 | ======== | |
3 | ||
4 | For general security related questions of perf_event_open() syscall usage, | |
5 | performance monitoring and observability operations by Perf see here: | |
6 | https://www.kernel.org/doc/html/latest/admin-guide/perf-security.html | |
7 | ||
8 | Enabling LSM based mandatory access control (MAC) to perf_event_open() syscall | |
9 | ============================================================================== | |
10 | ||
11 | LSM hooks for mandatory access control for perf_event_open() syscall can be | |
12 | used starting from Linux v5.3. Below are the steps to extend Fedora (v31) with | |
13 | Targeted policy with perf_event_open() access control capabilities: | |
14 | ||
15 | 1. Download selinux-policy SRPM package (e.g. selinux-policy-3.14.4-48.fc31.src.rpm on FC31) | |
16 | and install it so rpmbuild directory would exist in the current working directory: | |
17 | ||
18 | # rpm -Uhv selinux-policy-3.14.4-48.fc31.src.rpm | |
19 | ||
20 | 2. Get into rpmbuild/SPECS directory and unpack the source code: | |
21 | ||
22 | # rpmbuild -bp selinux-policy.spec | |
23 | ||
24 | 3. Place patch below at rpmbuild/BUILD/selinux-policy-b86eaaf4dbcf2d51dd4432df7185c0eaf3cbcc02 | |
25 | directory and apply it: | |
26 | ||
27 | # patch -p1 < selinux-policy-perf-events-perfmon.patch | |
28 | patching file policy/flask/access_vectors | |
29 | patching file policy/flask/security_classes | |
30 | # cat selinux-policy-perf-events-perfmon.patch | |
31 | diff -Nura a/policy/flask/access_vectors b/policy/flask/access_vectors | |
32 | --- a/policy/flask/access_vectors 2020-02-04 18:19:53.000000000 +0300 | |
33 | +++ b/policy/flask/access_vectors 2020-02-28 23:37:25.000000000 +0300 | |
34 | @@ -174,6 +174,7 @@ | |
35 | wake_alarm | |
36 | block_suspend | |
37 | audit_read | |
38 | + perfmon | |
39 | } | |
40 | ||
41 | # | |
42 | @@ -1099,3 +1100,15 @@ | |
43 | ||
44 | class xdp_socket | |
45 | inherits socket | |
46 | + | |
47 | +class perf_event | |
48 | +{ | |
49 | + open | |
50 | + cpu | |
51 | + kernel | |
52 | + tracepoint | |
53 | + read | |
54 | + write | |
55 | +} | |
56 | + | |
57 | + | |
58 | diff -Nura a/policy/flask/security_classes b/policy/flask/security_classes | |
59 | --- a/policy/flask/security_classes 2020-02-04 18:19:53.000000000 +0300 | |
60 | +++ b/policy/flask/security_classes 2020-02-28 21:35:17.000000000 +0300 | |
61 | @@ -200,4 +200,6 @@ | |
62 | ||
63 | class xdp_socket | |
64 | ||
65 | +class perf_event | |
66 | + | |
67 | # FLASK | |
68 | ||
69 | 4. Get into rpmbuild/SPECS directory and build policy packages from patched sources: | |
70 | ||
71 | # rpmbuild --noclean --noprep -ba selinux-policy.spec | |
72 | ||
73 | so you have this: | |
74 | ||
75 | # ls -alh rpmbuild/RPMS/noarch/ | |
76 | total 33M | |
77 | drwxr-xr-x. 2 root root 4.0K Mar 20 12:16 . | |
78 | drwxr-xr-x. 3 root root 4.0K Mar 20 12:16 .. | |
79 | -rw-r--r--. 1 root root 112K Mar 20 12:16 selinux-policy-3.14.4-48.fc31.noarch.rpm | |
80 | -rw-r--r--. 1 root root 1.2M Mar 20 12:17 selinux-policy-devel-3.14.4-48.fc31.noarch.rpm | |
81 | -rw-r--r--. 1 root root 2.3M Mar 20 12:17 selinux-policy-doc-3.14.4-48.fc31.noarch.rpm | |
82 | -rw-r--r--. 1 root root 12M Mar 20 12:17 selinux-policy-minimum-3.14.4-48.fc31.noarch.rpm | |
83 | -rw-r--r--. 1 root root 4.5M Mar 20 12:16 selinux-policy-mls-3.14.4-48.fc31.noarch.rpm | |
84 | -rw-r--r--. 1 root root 111K Mar 20 12:16 selinux-policy-sandbox-3.14.4-48.fc31.noarch.rpm | |
85 | -rw-r--r--. 1 root root 14M Mar 20 12:17 selinux-policy-targeted-3.14.4-48.fc31.noarch.rpm | |
86 | ||
87 | 5. Install SELinux packages from Fedora repo, if not already done so, and | |
88 | update with the patched rpms above: | |
89 | ||
90 | # rpm -Uhv rpmbuild/RPMS/noarch/selinux-policy-* | |
91 | ||
92 | 6. Enable SELinux Permissive mode for Targeted policy, if not already done so: | |
93 | ||
94 | # cat /etc/selinux/config | |
95 | ||
96 | # This file controls the state of SELinux on the system. | |
97 | # SELINUX= can take one of these three values: | |
98 | # enforcing - SELinux security policy is enforced. | |
99 | # permissive - SELinux prints warnings instead of enforcing. | |
100 | # disabled - No SELinux policy is loaded. | |
101 | SELINUX=permissive | |
102 | # SELINUXTYPE= can take one of these three values: | |
103 | # targeted - Targeted processes are protected, | |
104 | # minimum - Modification of targeted policy. Only selected processes are protected. | |
105 | # mls - Multi Level Security protection. | |
106 | SELINUXTYPE=targeted | |
107 | ||
108 | 7. Enable filesystem SELinux labeling at the next reboot: | |
109 | ||
110 | # touch /.autorelabel | |
111 | ||
112 | 8. Reboot machine and it will label filesystems and load Targeted policy into the kernel; | |
113 | ||
114 | 9. Login and check that dmesg output doesn't mention that perf_event class is unknown to SELinux subsystem; | |
115 | ||
116 | 10. Check that SELinux is enabled and in Permissive mode | |
117 | ||
118 | # getenforce | |
119 | Permissive | |
120 | ||
121 | 11. Turn SELinux into Enforcing mode: | |
122 | ||
123 | # setenforce 1 | |
124 | # getenforce | |
125 | Enforcing | |
126 | ||
127 | Opening access to perf_event_open() syscall on Fedora with SELinux | |
128 | ================================================================== | |
129 | ||
130 | Access to performance monitoring and observability operations by Perf | |
131 | can be limited for superuser or CAP_PERFMON or CAP_SYS_ADMIN privileged | |
132 | processes. MAC policy settings (e.g. SELinux) can be loaded into the kernel | |
133 | and prevent unauthorized access to perf_event_open() syscall. In such case | |
134 | Perf tool provides a message similar to the one below: | |
135 | ||
136 | # perf stat | |
137 | Error: | |
138 | Access to performance monitoring and observability operations is limited. | |
139 | Enforced MAC policy settings (SELinux) can limit access to performance | |
140 | monitoring and observability operations. Inspect system audit records for | |
141 | more perf_event access control information and adjusting the policy. | |
142 | Consider adjusting /proc/sys/kernel/perf_event_paranoid setting to open | |
143 | access to performance monitoring and observability operations for users | |
144 | without CAP_PERFMON or CAP_SYS_ADMIN Linux capability. | |
145 | perf_event_paranoid setting is -1: | |
146 | -1: Allow use of (almost) all events by all users | |
147 | Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK | |
148 | >= 0: Disallow raw and ftrace function tracepoint access | |
149 | >= 1: Disallow CPU event access | |
150 | >= 2: Disallow kernel profiling | |
151 | To make the adjusted perf_event_paranoid setting permanent preserve it | |
152 | in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>) | |
153 | ||
154 | To make sure that access is limited by MAC policy settings inspect system | |
155 | audit records using journalctl command or /var/log/audit/audit.log so the | |
156 | output would contain AVC denied records related to perf_event: | |
157 | ||
158 | # journalctl --reverse --no-pager | grep perf_event | |
159 | ||
160 | python3[1318099]: SELinux is preventing perf from open access on the perf_event labeled unconfined_t. | |
161 | If you believe that perf should be allowed open access on perf_event labeled unconfined_t by default. | |
162 | 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 | |
163 | 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 | |
164 | ||
165 | In order to open access to perf_event_open() syscall MAC policy settings can | |
166 | require to be extended. On SELinux system this can be done by loading a special | |
167 | policy module extending base policy settings. Perf related policy module can | |
168 | be generated using the system audit records about blocking perf_event access. | |
169 | Run the command below to generate my-perf.te policy extension file with | |
170 | perf_event related rules: | |
171 | ||
172 | # ausearch -c 'perf' --raw | audit2allow -M my-perf && cat my-perf.te | |
173 | ||
174 | module my-perf 1.0; | |
175 | ||
176 | require { | |
177 | type unconfined_t; | |
178 | class perf_event { cpu kernel open read tracepoint write }; | |
179 | } | |
180 | ||
181 | #============= unconfined_t ============== | |
182 | allow unconfined_t self:perf_event { cpu kernel open read tracepoint write }; | |
183 | ||
184 | Now compile, pack and load my-perf.pp extension module into the kernel: | |
185 | ||
186 | # checkmodule -M -m -o my-perf.mod my-perf.te | |
187 | # semodule_package -o my-perf.pp -m my-perf.mod | |
188 | # semodule -X 300 -i my-perf.pp | |
189 | ||
190 | After all those taken steps above access to perf_event_open() syscall should | |
191 | now be allowed by the policy settings. Check access running Perf like this: | |
192 | ||
193 | # perf stat | |
194 | ^C | |
195 | Performance counter stats for 'system wide': | |
196 | ||
197 | 36,387.41 msec cpu-clock # 7.999 CPUs utilized | |
198 | 2,629 context-switches # 0.072 K/sec | |
199 | 57 cpu-migrations # 0.002 K/sec | |
200 | 1 page-faults # 0.000 K/sec | |
201 | 263,721,559 cycles # 0.007 GHz | |
202 | 175,746,713 instructions # 0.67 insn per cycle | |
203 | 19,628,798 branches # 0.539 M/sec | |
204 | 1,259,201 branch-misses # 6.42% of all branches | |
205 | ||
206 | 4.549061439 seconds time elapsed | |
207 | ||
208 | The generated perf-event.pp related policy extension module can be removed | |
209 | from the kernel using this command: | |
210 | ||
211 | # semodule -X 300 -r my-perf | |
212 | ||
213 | Alternatively the module can be temporarily disabled and enabled back using | |
214 | these two commands: | |
215 | ||
216 | # semodule -d my-perf | |
217 | # semodule -e my-perf | |
218 | ||
219 | If something went wrong | |
220 | ======================= | |
221 | ||
222 | To turn SELinux into Permissive mode: | |
223 | # setenforce 0 | |
224 | ||
225 | To fully disable SELinux during kernel boot [3] set kernel command line parameter selinux=0 | |
226 | ||
227 | To remove SELinux labeling from local filesystems: | |
228 | # find / -mount -print0 | xargs -0 setfattr -h -x security.selinux | |
229 | ||
230 | To fully turn SELinux off a machine set SELINUX=disabled at /etc/selinux/config file and reboot; | |
231 | ||
232 | Links | |
233 | ===== | |
234 | ||
235 | [1] https://download-ib01.fedoraproject.org/pub/fedora/linux/updates/31/Everything/SRPMS/Packages/s/selinux-policy-3.14.4-49.fc31.src.rpm | |
236 | [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 | |
237 | [3] https://danwalsh.livejournal.com/10972.html |