~ubuntu-branches/ubuntu/oneiric/apparmor/oneiric-security

« back to all changes in this revision

Viewing changes to libraries/libapparmor/doc/aa_change_hat.pod

  • Committer: Bazaar Package Importer
  • Author(s): Kees Cook
  • Date: 2011-04-27 10:38:07 UTC
  • mfrom: (5.1.118 natty)
  • Revision ID: james.westby@ubuntu.com-20110427103807-ym3rhwys6o84ith0
Tags: 2.6.1-2
debian/copyright: clarify for some full organization names.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
4
#
 
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.
 
9
#
 
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.
 
14
#
 
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.
 
18
#
 
19
 
 
20
 
 
21
=pod
 
22
 
 
23
=head1 NAME
 
24
 
 
25
aa_change_hat  - change to or from a "hat" within a AppArmor profile
 
26
 
 
27
=head1 SYNOPSIS
 
28
 
 
29
B<#include E<lt>sys/apparmor.hE<gt>>
 
30
 
 
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, ...);>
 
34
 
 
35
Link with B<-lapparmor> when compiling.
 
36
 
 
37
=head1 DESCRIPTION
 
38
 
 
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
 
42
subprofile.
 
43
 
 
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.
 
48
 
 
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.
 
53
 
 
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
 
58
appropriate error.
 
59
 
 
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().
 
65
 
 
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.
 
74
 
 
75
 
 
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
 
78
is in a "hat".
 
79
 
 
80
=head1 RETURN VALUE
 
81
 
 
82
On success zero is returned. On error, -1 is returned, and
 
83
errno(3) is set appropriately.
 
84
 
 
85
=head1 ERRORS
 
86
 
 
87
=over 4
 
88
 
 
89
=item B<EINVAL>
 
90
 
 
91
The apparmor kernel module is not loaded or the communication via the
 
92
F</proc/*/attr/current> file did not conform to protocol.
 
93
 
 
94
=item B<ENOMEM>
 
95
 
 
96
Insufficient kernel memory was available.
 
97
 
 
98
=item B<EPERM>
 
99
 
 
100
The calling application is not confined by apparmor.
 
101
 
 
102
=item B<ECHILD>
 
103
 
 
104
The application's profile has no hats defined for it.
 
105
 
 
106
=item B<EACCES>
 
107
 
 
108
The specified I<subprofile> does not exist in this profile or the
 
109
process tried to change another process's domain.
 
110
 
 
111
=back 
 
112
 
 
113
=head1 EXAMPLE
 
114
 
 
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.
 
121
 
 
122
The use of random(3) is simply illustrative. Use of F</dev/urandom> is
 
123
recommended.
 
124
 
 
125
First, a simple high-level overview of aa_change_hat() use:
 
126
 
 
127
 void foo (void) {
 
128
        unsigned long magic_token;
 
129
  
 
130
        /* get a random magic token value
 
131
        from our huge entropy pool */
 
132
        magic_token = random_function();
 
133
 
 
134
        /* change into the subprofile while
 
135
         * we do stuff we don't trust */
 
136
        aa_change_hat("stuff_we_dont_trust", magic_token);
 
137
 
 
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);
 
142
 
 
143
        /* now change back to our original profile */
 
144
        aa_change_hat(NULL, magic_token);
 
145
 }
 
146
 
 
147
Second, an example to show that files not listed in a subprofile ("hat")
 
148
aren't accessible after an aa_change_hat() call:
 
149
 
 
150
 #include <stdlib.h>
 
151
 #include <string.h>
 
152
 #include <sys/apparmor.h>
 
153
 #include <sys/types.h>
 
154
 #include <sys/stat.h>
 
155
 #include <fcntl.h>
 
156
 #include <stdio.h>
 
157
 #include <unistd.h>
 
158
 
 
159
 
 
160
 int main(int argc, char *argv[]) {
 
161
        int fd;
 
162
        unsigned long tok;
 
163
        char buf[10];
 
164
 
 
165
        /* random() is a poor choice */
 
166
        tok = random();
 
167
 
 
168
        /* open /etc/passwd outside of any hat */
 
169
        if ((fd=open("/etc/passwd", O_RDONLY)) < 0)
 
170
                perror("Failure opening /etc/passwd");
 
171
 
 
172
        /* confirm for ourselves that we can really read /etc/passwd */
 
173
        memset(&buf, 0, 10);
 
174
        if (read(fd, &buf, 10) == -1) {
 
175
                perror("Failure reading /etc/passwd pre-hat");
 
176
                _exit(1);
 
177
        }
 
178
        buf[9] = '\0';
 
179
        printf("/etc/passwd: %s\n", buf);
 
180
 
 
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");
 
186
                _exit(1);
 
187
        }
 
188
 
 
189
        /* confirm that we cannot read /etc/passwd */
 
190
        lseek(fd,0,SEEK_SET);
 
191
        memset(&buf, 0, 10);
 
192
        if (read(fd, &buf, 10) == -1)
 
193
                perror("Failure reading /etc/passwd post-hat");
 
194
        buf[9] = '\0';
 
195
        printf("/etc/passwd: %s\n", buf);
 
196
 
 
197
        return 0;
 
198
 }
 
199
 
 
200
 
 
201
This code example requires the following profile to be loaded with
 
202
apparmor_parser(8):
 
203
 
 
204
 /tmp/ch {
 
205
   /etc/ld.so.cache               mr,
 
206
   /etc/locale/**                 r,
 
207
   /etc/localtime                 r,
 
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,
 
213
 
 
214
   /lib/ld-*.so*         mrix,
 
215
   /lib/libc*.so*        mr,
 
216
   /lib/libapparmor*.so* mr,
 
217
   /dev/pts/*            rw,
 
218
   /tmp/ch               mr,
 
219
 
 
220
   /etc/passwd           r,
 
221
 
 
222
   ^hat {
 
223
     /dev/pts/*     rw,
 
224
   }
 
225
 }
 
226
 
 
227
 
 
228
The output when run:
 
229
 
 
230
 $ /tmp/ch
 
231
 /etc/passwd: root:x:0:
 
232
 Failure reading /etc/passwd post-hat: Permission denied
 
233
 /etc/passwd:
 
234
 $
 
235
 
 
236
 
 
237
=head1 BUGS
 
238
 
 
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
 
243
should be used.
 
244
 
 
245
=head1 SEE ALSO
 
246
 
 
247
apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2) and
 
248
L<http://wiki.apparmor.net>.
 
249
 
 
250
=cut