aboutsummaryrefslogtreecommitdiff
blob: a67f20b60f2c9e5f2180a7d34e3a29810c5a2ed5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE sections SYSTEM "/dtd/book.dtd">

<!-- The content of this document is licensed under the CC-BY-SA license -->
<!-- See http://creativecommons.org/licenses/by-sa/1.0 -->

<!-- $Header: /var/cvsroot/gentoo/xml/htdocs/proj/en/hardened/selinux/hb-using-commands.xml,v 1.3 2011/06/07 19:46:52 klondike Exp $ -->

<sections>
<version>4</version>
<date>2012-04-29</date>

<section>
<title>SELinux Policy Language</title>
<subsection>
<title>Introduction</title>
<body>

<p>
By default, Gentoo provides a generic, yet tightly controlled policy which is
deemed a good start policy for the majority of users. However, the purpose
behind a Mandatory Access Control system is to put the security administrator in
control. As such, a handbook on SELinux without information on how to write
policies wouldn't be complete.
</p>

<p>
In this chapter, we'll talk a bit about the language behind SELinux policies and
give some pointers on how to create your own policies, roles, etc.
</p>

</body>
</subsection>
<subsection>
<title>Building a SELinux Module</title>
<body>

<p>
First, before we go into the art of SELinux policy writing, let's first make a
small SELinux module with a rule we can test, build the module and see if things
work. Although these steps are fairly easy, they are important nonetheless.
Modifying the SELinux policy as offered by Gentoo is best done through
additional SELinux policy modules. Only when the core policy (the base policy)
is not to your liking should you see on using a totally different policy.
</p>

<p>
Let's start with a skeleton for a policy module we'll call <e>testmod</e>. You
should use simple names for the modules as the build infrastructure is quite
sensitive to special constructs. Use only letters a-z and numbers, and never
start a module name with a number.
</p>

<pre caption="Policy module skeleton">
policy_module(testmod, 1.0.0)
</pre>

<p>
Yes, that's it. But as you can see, it is fairly empty. So let's add a rule that
allows a regular user (in the user_t domain) to read ebuild files (of type
portage_ebuild_t).
</p>

<pre caption="Policy module testmod">
policy_module(testmod, 1.0.0)

require {
  type user_t;
  type portage_ebuild_t;
  class file { read open getattr };
  class dir { read search open getattr };
}

allow user_t portage_ebuild_t:file { read open getattr };
allow user_t portage_ebuild_t:dir { read search open getattr };
</pre>

<p>
As you can see, something as simple as allowing a user to read a file requires
quite a few privileges. The directory privileges are needed to allow a user to
navigate through the Portage tree structure whereas the file privileges are
needed for a user to be able to access and open the ebuilds. Save this file as
<path>testmod.te</path>.
</p>

<p>
To build the policy and convert it into the binary module that we can load into
the SELinux policy store, we can use the <path>Makefile</path> available in
<path>/usr/share/selinux/strict/include</path> (substitute strict with the
SELinux policy type you are using).
</p>

<pre caption="Building a binary policy module">
$ <i>make -f /usr/share/selinux/struct/include/Makefile testmod.pp</i>
</pre>

<p>
The filename (<path>testmod.pp</path>) is the destination binary SELinux module
name. The <path>Makefile</path> will automatically look for the
<path>testmod.te</path> file you have in the working directory.
</p>

<p>
As a result, you should now have a file called <path>testmod.pp</path>. This
module file can now be loaded in the SELinux policy store as follows:
</p>

<pre caption="Loading a binary module">
# <i>semodule -i /path/to/testmod.pp</i>
</pre>

<p>
Congratulations! You have now build your first SELinux policy module. If you
want to disable it, remove it through <c>semodule -r testmod</c>.
</p>

<p>
This method of building a policy (using the <path>Makefile</path> and
<c>semodule</c>) is something that you will need to do every time you want to
update the SELinux policy on your system. The contents of the policy however
does change as we will see in the rest of this document.
</p>

</body>
</subsection>
<subsection>
<title>Getting the SELinux Policy Interfaces</title>
<body>

<p>
To streamline policy development, the SELinux policy based on the reference
policy uses interfaces to access privileges within a module. If you have built
<path>selinux-base-policy</path> with <c>USE="doc"</c> then this information is
available at
<path>/usr/share/doc/selinux-base-policy-&lt;version&gt;/html</path>. It is
recommended to have this information at hand, since most policy
development/updates will be done through the interfaces offered by the policy.
</p>

<p>
If you are just interested, you can also find these interface definitions <uri
link="http://oss.tresys.com/docs/refpolicy/api/">online</uri>. Mind you though,
the online resource is only the reference policy and might differ a bit from the
policy available within Gentoo.
</p>

</body>
</subsection>
<subsection>
<title>Using Policy Interfaces</title>
<body>

<p>
Using the policy interfaces allows you to update the policy with more readable
functions. For instance, to allow the user_t domain to call and use Portage
applications, the module could look like so:
</p>

<pre caption="Example policy to allow user_t to use portage">
policy_module(testmod, 1.0.0)

require {
  type user_t;
  role user_r;
}

portage_run(user_t, user_r)
</pre>

<p>
Of course, this makes the user_t domain much more privileged than the previously
defined rules to read ebuild files: it allows the user to call portage, update
the system, etc. Of course, the user still requires the proper regular Linux
permissions (so he needs to be part of the portage group or become root).
Needless to say, we do not recommend to grant this to a regular user ;-)
</p>

</body>
</subsection>
</section>

<section>
<title>Full SELinux Policy Modules</title>
<subsection>
<title>Checking Out an Isolated Module</title>
<body>

<p>
With the above in mind, we can now go one step further and investigate a full
policy module, with both the type enforcement rules (<path>.te</path> file),
file contexts (<path>.fc</path>) and interfaces (<path>.if</path>).
</p>

<p>
You should know that writing a module requires you to get intimate with the
application. It isn't a matter of just hoping for the best: as a security
administrator, you will be responsible for defining what accesses are allowed
and which not. If you forget one, the application might break under the users'
hands. But if you add too much, you might grant privileges that can be abused
later on. And it will be a lot more difficult to track and remove privileges
later as you will be hesitating if the privilege is needed or not.
</p>

<p>
In this section, we will not divulge in how to write one. We have an excellent
<uri link="/proj/en/hardened/selinux-development.xml">Gentoo Hardened SELinux
Development</uri> resource that guides you in that. However, we will look into
such a full module to explain the other aspects of policy development.
</p>

</body>
</subsection>
<subsection>
<title>Type Enforcement File</title>
<body>

<p>
The <path>.te</path> file we wrote earlier is a <e>type enforcement file</e>.
Its purpose is to define the access rules related to the module that you are
building, but also - and more importantly - define new types (or even roles).
</p>

<p>
The example below is a snippet from a module for the skype application.
</p>

<pre caption="Snippet from skype.te">
policy_module(skype, 1.0.0)

type skype_t;
type skype_exec_t;
application_domain(skype_t, skype_exec_t)

type skype_home_t;
userdom_user_home_content(skype_home_t)

manage_dirs_pattern(skype_t, skype_home_t, skype_home_t)
manage_files_pattern(skype_t, skype_home_t, skype_home_t)
</pre>

<p>
In the above example, three new types are declared: <c>skype_t</c> (which will
be used for the application), <c>skype_exec_t</c> (which is the label given to
the application binary) and <c>skype_home_t</c> (which will be used for the
users' <path>~/.Skype</path> location). Also, the <c>skype_t</c> domain is given
some privileges with respect to the <c>skype_home_t</c> label (manage
directories and files).
</p>

</body>
</subsection>
<subsection>
<title>File Context File</title>
<body>

<p>
In the <path>.fc</path> file (which stands for <e>file context file</e>) the
module's resources (files, directories, sockets, ...) are defined. Once the
module is loaded, these rules are added so that file system relabeling will put
the correct context on the files.
</p>

<p>
The example below is a snippet from the skype modules' file context file.
</p>

<pre caption="Snippet from skype.fc">
HOME_DIR/\.Skype(/.*)?    gen_context(system_u:object_r:skype_home_t,s0)
/opt/skype/skype       -- gen_context(system_u:object_r:skype_exec_t,s0)
/usr/bin/skype         -- gen_context(system_u:object_r:skype_exec_t,s0)
</pre>

<p>
The format of the file context file has the following syntax:
</p>

<ol>
  <li>
    The regular expression that matches the file(s) and directorie(s) affected
    by that line
  </li>
  <li>
    An optional identifier to differentiate the type of files (file, directory,
    socket, symbolic link, ...)
  </li>
  <li>
    A <c>gen_context</c> line that contains the context to assign to the file(s)
    and directorie(s)
  </li>
</ol>

</body>
</subsection>
<subsection>
<title>Interface File</title>
<body>

<p>
In the <path>.if</path> file (for <e>interface file</e>) interfaces are declared
which can be used by other modules. It is through interfaces that a nicely
defined policy can be built on top of other, existing policy modules.
</p>

<p>
One interface could be to allow users to call and execute an application. For
instance, the following interface can be found in the skype module.
</p>

<pre caption="Snippet from skype.if">
interface(`skype_role',`
        gen_require(`
                type skype_t, skype_exec_t, skype_tmpfs_t, skype_home_t;
        ')

        role $1 types skype_t;

        domtrans_pattern($2, skype_exec_t, skype_t)

        allow $2 skype_t:process { ptrace signal_perms };

        manage_dirs_pattern($2, skype_home_t, skype_home_t)
        manage_files_pattern($2, skype_home_t, skype_home_t)
        manage_lnk_files_pattern($2, skype_home_t, skype_home_t)

        relabel_dirs_pattern($2, skype_home_t, skype_home_t)
        relabel_files_pattern($2, skype_home_t, skype_home_t)
        relabel_lnk_files_pattern($2, skype_home_t, skype_home_t)

        ps_process_pattern($2, skype_t)
')
</pre>

<p>
Through this <c>skype_role</c>, we can then allow users to call skype, as can be
found in the <path>unprivuser.te</path> file (which defines the user_t domain):
</p>

<pre caption="Snippet from unprivuser.te to call skype">
optional_policy(`
	skype_role(user_r, user_t)
')
</pre>

<p>
The following table shows a few common interfaces that could be in use. We
seriously recommend to look at the available interfaces when enhancing or
creating your own modules - and be sure to pick the interface that adds just
what you need, nothing more.
</p>

<table>
<tr>
  <th colspan="3">Templates</th>
</tr>
<tr>
  <th>Suffix</th>
  <th>Example</th>
  <th>Description</th>
</tr>
<tr>
  <ti>_template</ti>
  <ti>virt_domain_template(prefix)</ti>
  <ti>
    Not really an interface, templates create additional domains based on the
    information given to them. This is usually done for fine-grained policy
    templates with a common (sub)set of privileges.    
  </ti>
</tr>
<tr>
  <th colspan="3">Transformations</th>
</tr>
<tr>
  <th>Suffix</th>
  <th>Example</th>
  <th>Description</th>
</tr>
<tr>
  <ti></ti>
  <ti>miscfiles_cert_type(resource)</ti>
  <ti>
    Transformation interfaces generally add specific attributes to resources or
    domains. Attributes "transform" the given resource into something more. In
    the given example, the miscfiles_cert_type(resource) assigns the cert_type
    attribute to the resource (and also marks it as a file). Interfaces, like
    miscfiles_read_all_certs work on these attributes.
  </ti>
</tr>
<tr>
  <th colspan="3">Access interfaces</th>
</tr>
<tr>
  <th>Suffix</th>
  <th>Example</th>
  <th>Description</th>
</tr>
<tr>
  <ti>_&lt;access&gt;_&lt;resource&gt;</ti>
  <ti>mta_getattr_spool(domain)</ti>
  <ti>
    Grant the specified domain access towards the shown resource. The resource
    usually defines the type too (like kudzu_getattr_exec_files: grant getattr
    on the kudzu_exec_t files) unless it is obvious from the name, or when the
    resource is a more specific term towards the domain. It can also include
    dontaudit (like mta_dontaudit_getattr_spool).
  </ti>
</tr>
<tr>
  <ti>_exec</ti>
  <ti>dmesg_exec(domain)</ti>
  <ti>
    Grant one domain the right to execute the given domains' executable file (in
    the example, allow "domain" to execute dmesg_exec_t files), but without
    implying that the domains transition. In other words, dmesg gets executed
    but still confined by the privileges of the source domain.
  </ti>
</tr>
<tr>
  <ti>_domtrans</ti>
  <ti>dmesg_domtrans(domain)</ti>
  <ti>
    Grant one domain execute and transition privileges towards the new domain.
    This interface is most commonly used to allow application domains to
    transition to another. In the given example, dmesg is ran with the
    privileges of the dmesg_t domain.
  </ti>
</tr>
<tr>
  <ti>_run</ti>
  <ti>netutils_run(domain, role)</ti>
  <ti>
    Grant a given role and domain the rights to execute and transition towards
    the given domain. This is usually granted to (existing) user roles and
    domains and gives them the set of privileges needed to interact safely with
    the new (interactive) domain (such as terminal access).
  </ti>
</tr>
<tr>
  <ti>_role</ti>
  <ti>xserver_role(role, domain)</ti>
  <ti>
    Allow the given role and domain the necessary permissions to transition and
    interact with the given domain. This interface is enhanced with the
    privileges to interact with the domain (and its underlying files) more
    thoroughly, and is usually assigned to newly created users or roles within
    the policy (rather than enhance existing user domains and roles).
  </ti>
</tr>
<tr>
  <ti>_admin</ti>
  <ti>aide_admin(domain)</ti>
  <ti>
    Grant the given domain the rights to administer the target domains'
    environment. This usually involves privileges to manage and relabel all
    affiliated files, directories, sockets, etc.
  </ti>
</tr>
</table>

</body>
</subsection>
</section>

<section>
<title>Using audit2allow</title>
<subsection>
<title>Introduction</title>
<body>

<p>
When reading online resources on SELinux, you will notice that there are many
references to a tool called <c>audit2allow</c>. This tools' purpose is to read
AVC denial messages from the audit log file and transform them into a policy
module that you can load. The advantage is that it makes it a lot easier to
write policies. The downside is that the output (unless you use the <c>-R</c>
option) is not usable for the <path>Makefile</path> we used earlier to build
modules.
</p>

<p>
Another disadvantage is that the tool does not intelligently cope with changes.
It blindly accepts denials and treats them as if they need to be allowed, rather
than investigate if no other context should be given to the file, etc.
</p>

</body>
</subsection>
<subsection>
<title>Using audit2allow</title>
<body>

<p>
Using <c>audit2allow</c> is pretty straightforward. You send it the denials you
want to fix and store the result in a <path>.te</path> file. You then convert it
into an intermediary format which can then be translated into a <path>.pp</path>
file for final loading by <c>semodule</c>.
</p>

<p>
For instance, to catch all denials and transform them into allowed statements
from firefox-related denials:
</p>

<pre caption="Generate a new policy using audit2allow">
# <i>grep firefox /var/log/avc.log | audit2allow -m firefoxmod &gt; firefoxmod.te</i>
# <i>checkmodule -m -o firefoxmod.mod firefoxmod.te</i>
# <i>semodule_package -o firefoxmod.pp -m firefoxmod.mod</i>
# <i>semodule -i firefoxmod.pp</i>
</pre>

<p>
Keep the module name (given through the <c>-m</c> option) simple: only use
characters (<c>[a-z]</c>) and numbers (<c>[0-9]</c>), and start the module name
with a character.
</p>

</body>
</subsection>
</section>

</sections>