1
# This publication is intellectual property of Novell Inc. and Canonical
2
# Ltd. Its contents can be duplicated, either in part or in whole, provided
3
# that a copyright label is visibly located on each copy.
5
# All information found in this book has been compiled with utmost
6
# attention to detail. However, this does not guarantee complete accuracy.
7
# Neither SUSE LINUX GmbH, Canonical Ltd, the authors, nor the translators
8
# shall be held liable for possible errors or the consequences thereof.
10
# Many of the software and hardware descriptions cited in this book
11
# are registered trademarks. All trade names are subject to copyright
12
# restrictions and may be registered trade marks. SUSE LINUX GmbH
13
# and Canonical Ltd. essentially adhere to the manufacturer's spelling.
15
# Names of products and trademarks appearing in this book (with or without
16
# specific notation) are likewise subject to trademark and trade protection
17
# laws and may thus fall under copyright restrictions.
25
aa_change_hat - change to or from a "hat" within a AppArmor profile
29
B<#include E<lt>sys/apparmor.hE<gt>>
31
B<int aa_change_hat (char *subprofile, unsigned long magic_token);>
32
B<int aa_change_hatv (char *subprofiles[], unsigned long magic_token);>
33
B<int aa_change_hat_vargs (unsigned long magic_token, ...);>
35
Link with B<-lapparmor> when compiling.
39
An AppArmor profile applies to an executable program; if a portion of
40
the program needs different access permissions than other portions,
41
the program can "change hats" to a different role, also known as a
44
To change into a new hat, it calls one of the family of change_hat
45
functions to do so. It passes in a pointer to the I<subprofile> which it
46
wants to change into, and a 64bit I<magic_token>. The I<magic_token>
47
is used to return out of the subprofile at a later time.
49
The aa_change_hat() function allows specifying the name of a single
50
I<subprofile> that the application wants to change into. A pointer to the
51
name of the I<subprofile> is passed along with the I<magic_token>. If the
52
profile is not present the call will fail with the appropriate error.
54
The aa_change_hatv() function allows passing a I<NULL> terminated vector
55
of pointers to I<subprofile> names which will be tried in order. The
56
first I<subprofile> in the vector that exists will be transitioned to
57
and if none of the I<subprofiles> exist the call will fail with the
60
The aa_change_hat_vargs() function is a convenience wrapper for the
61
aa_change_hatv() function. After the I<magic_token> it takes an arbitrary
62
number of pointers to I<subprofile> names. Similar to execl(3),
63
aa_change_hat_vargs() assembles the list of I<subprofile> names into a
64
vector and calls aa_change_hatv().
66
If a program wants to return out of the current subprofile to the
67
original profile, it calls aa_change_hat() with a pointer to NULL as
68
the I<subprofile>, and the original I<magic_token> value. If the
69
I<magic_token> does not match the original I<magic_token> passed into the
70
kernel when the program entered the subprofile, the change back to the
71
original profile will not happen, and the current task will be killed.
72
If the I<magic_token> matches the original token, then the process will
73
change back to the original profile.
76
As both read(2) and write(2) are mediated, a file must be listed in a
77
subprofile definition if the file is to be accessed while the process
82
On success zero is returned. On error, -1 is returned, and
83
errno(3) is set appropriately.
91
The apparmor kernel module is not loaded or the communication via the
92
F</proc/*/attr/current> file did not conform to protocol.
96
Insufficient kernel memory was available.
100
The calling application is not confined by apparmor.
104
The application's profile has no hats defined for it.
108
The specified I<subprofile> does not exist in this profile or the
109
process tried to change another process's domain.
115
The following code examples shows simple, if contrived, uses of
116
aa_change_hat(); a typical use of aa_change_hat() will separate
117
privileged portions of a process from unprivileged portions of a process,
118
such as keeping unauthenticated network traffic handling separate
119
from authenticated network traffic handling in OpenSSH or executing
120
user-supplied CGI scripts in apache.
122
The use of random(3) is simply illustrative. Use of F</dev/urandom> is
125
First, a simple high-level overview of aa_change_hat() use:
128
unsigned long magic_token;
130
/* get a random magic token value
131
from our huge entropy pool */
132
magic_token = random_function();
134
/* change into the subprofile while
135
* we do stuff we don't trust */
136
aa_change_hat("stuff_we_dont_trust", magic_token);
138
/* Go do stuff we don't trust -- this is all
139
* done in *this* process space, no separate
140
* fork()/exec()'s are done. */
141
interpret_perl_stuff(stuff_from_user);
143
/* now change back to our original profile */
144
aa_change_hat(NULL, magic_token);
147
Second, an example to show that files not listed in a subprofile ("hat")
148
aren't accessible after an aa_change_hat() call:
152
#include <sys/apparmor.h>
153
#include <sys/types.h>
154
#include <sys/stat.h>
160
int main(int argc, char *argv[]) {
165
/* random() is a poor choice */
168
/* open /etc/passwd outside of any hat */
169
if ((fd=open("/etc/passwd", O_RDONLY)) < 0)
170
perror("Failure opening /etc/passwd");
172
/* confirm for ourselves that we can really read /etc/passwd */
174
if (read(fd, &buf, 10) == -1) {
175
perror("Failure reading /etc/passwd pre-hat");
179
printf("/etc/passwd: %s\n", buf);
181
/* change hat to the "hat" subprofile, which should not have
182
* read access to /etc/passwd -- even though we have a valid
183
* file descriptor at the time of the aa_change_hat() call. */
184
if (aa_change_hat("hat", tok)) {
185
perror("Failure changing hat -- aborting");
189
/* confirm that we cannot read /etc/passwd */
190
lseek(fd,0,SEEK_SET);
192
if (read(fd, &buf, 10) == -1)
193
perror("Failure reading /etc/passwd post-hat");
195
printf("/etc/passwd: %s\n", buf);
201
This code example requires the following profile to be loaded with
208
/usr/share/locale/** r,
209
/usr/share/zoneinfo/** r,
210
/usr/lib/locale/** mr,
211
/usr/lib/gconv/*.so mr,
212
/usr/lib/gconv/gconv-modules* mr,
216
/lib/libapparmor*.so* mr,
231
/etc/passwd: root:x:0:
232
Failure reading /etc/passwd post-hat: Permission denied
239
None known. If you find any, please report them at
240
L<http://https://bugs.launchpad.net/apparmor/+filebug>. Note that
241
aa_change_hat(2) provides no memory barriers between different areas of a
242
program; if address space separation is required, then separate processes
247
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2) and
248
L<http://wiki.apparmor.net>.