blob: a1723bbcde0e965e3f4cbf508d8b0ca94cbdacfb [file] [log] [blame]
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +09001/*
2 * security/tomoyo/domain.c
3 *
4 * Implementation of the Domain-Based Mandatory Access Control.
5 *
6 * Copyright (C) 2005-2009 NTT DATA CORPORATION
7 *
Tetsuo Handa39826a12009-04-08 22:31:28 +09008 * Version: 2.2.0 2009/04/01
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +09009 *
10 */
11
12#include "common.h"
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +090013#include <linux/binfmts.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/slab.h>
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +090015
16/* Variables definitions.*/
17
18/* The initial domain. */
19struct tomoyo_domain_info tomoyo_kernel_domain;
20
Tetsuo Handac3fa1092009-06-08 12:37:39 +090021/*
22 * tomoyo_domain_list is used for holding list of domains.
23 * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
24 * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
25 *
26 * An entry is added by
27 *
28 * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \
29 * /sys/kernel/security/tomoyo/domain_policy
30 *
31 * and is deleted by
32 *
33 * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \
34 * /sys/kernel/security/tomoyo/domain_policy
35 *
36 * and all entries are retrieved by
37 *
38 * # cat /sys/kernel/security/tomoyo/domain_policy
39 *
40 * A domain is added by
41 *
42 * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy
43 *
44 * and is deleted by
45 *
46 * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy
47 *
48 * and all domains are retrieved by
49 *
50 * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy
51 *
52 * Normally, a domainname is monotonically getting longer because a domainname
53 * which the process will belong to if an execve() operation succeeds is
54 * defined as a concatenation of "current domainname" + "pathname passed to
55 * execve()".
56 * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for
57 * exceptions.
58 */
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +090059LIST_HEAD(tomoyo_domain_list);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +090060
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +090061/**
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +090062 * tomoyo_get_last_name - Get last component of a domainname.
63 *
64 * @domain: Pointer to "struct tomoyo_domain_info".
65 *
66 * Returns the last component of the domainname.
67 */
68const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
69{
70 const char *cp0 = domain->domainname->name;
71 const char *cp1 = strrchr(cp0, ' ');
72
73 if (cp1)
74 return cp1 + 1;
75 return cp0;
76}
77
Tetsuo Handac3fa1092009-06-08 12:37:39 +090078/*
79 * tomoyo_domain_initializer_list is used for holding list of programs which
80 * triggers reinitialization of domainname. Normally, a domainname is
81 * monotonically getting longer. But sometimes, we restart daemon programs.
82 * It would be convenient for us that "a daemon started upon system boot" and
83 * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO
84 * provides a way to shorten domainnames.
85 *
86 * An entry is added by
87 *
88 * # echo 'initialize_domain /usr/sbin/httpd' > \
89 * /sys/kernel/security/tomoyo/exception_policy
90 *
91 * and is deleted by
92 *
93 * # echo 'delete initialize_domain /usr/sbin/httpd' > \
94 * /sys/kernel/security/tomoyo/exception_policy
95 *
96 * and all entries are retrieved by
97 *
98 * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy
99 *
100 * In the example above, /usr/sbin/httpd will belong to
101 * "<kernel> /usr/sbin/httpd" domain.
102 *
103 * You may specify a domainname using "from" keyword.
104 * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
105 * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd"
106 * domain to belong to "<kernel> /usr/sbin/httpd" domain.
107 *
108 * You may add "no_" prefix to "initialize_domain".
109 * "initialize_domain /usr/sbin/httpd" and
110 * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
111 * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
112 * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
113 */
Tetsuo Handa847b1732010-02-11 09:43:54 +0900114LIST_HEAD(tomoyo_domain_initializer_list);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900115
116/**
117 * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
118 *
119 * @domainname: The name of domain. May be NULL.
120 * @program: The name of program.
121 * @is_not: True if it is "no_initialize_domain" entry.
122 * @is_delete: True if it is a delete request.
123 *
124 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900125 *
126 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900127 */
128static int tomoyo_update_domain_initializer_entry(const char *domainname,
129 const char *program,
130 const bool is_not,
131 const bool is_delete)
132{
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900133 struct tomoyo_domain_initializer_entry *entry = NULL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900134 struct tomoyo_domain_initializer_entry *ptr;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900135 const struct tomoyo_path_info *saved_program = NULL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900136 const struct tomoyo_path_info *saved_domainname = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900137 int error = is_delete ? -ENOENT : -ENOMEM;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900138 bool is_last_name = false;
139
Tetsuo Handa17080002010-02-16 21:14:48 +0900140 if (!tomoyo_is_correct_path(program, 1, -1, -1))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900141 return -EINVAL; /* No patterns allowed. */
142 if (domainname) {
143 if (!tomoyo_is_domain_def(domainname) &&
Tetsuo Handa17080002010-02-16 21:14:48 +0900144 tomoyo_is_correct_path(domainname, 1, -1, -1))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900145 is_last_name = true;
Tetsuo Handa17080002010-02-16 21:14:48 +0900146 else if (!tomoyo_is_correct_domain(domainname))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900147 return -EINVAL;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900148 saved_domainname = tomoyo_get_name(domainname);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900149 if (!saved_domainname)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900150 goto out;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900151 }
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900152 saved_program = tomoyo_get_name(program);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900153 if (!saved_program)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900154 goto out;
155 if (!is_delete)
Tetsuo Handa4e5d6f72010-04-28 14:17:42 +0900156 entry = kmalloc(sizeof(*entry), GFP_NOFS);
Tetsuo Handa29282382010-05-06 00:18:15 +0900157 if (mutex_lock_interruptible(&tomoyo_policy_lock))
158 goto out;
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900159 list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900160 if (ptr->is_not != is_not ||
161 ptr->domainname != saved_domainname ||
162 ptr->program != saved_program)
163 continue;
164 ptr->is_deleted = is_delete;
165 error = 0;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900166 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900167 }
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900168 if (!is_delete && error && tomoyo_memory_ok(entry)) {
169 entry->domainname = saved_domainname;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900170 saved_domainname = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900171 entry->program = saved_program;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900172 saved_program = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900173 entry->is_not = is_not;
174 entry->is_last_name = is_last_name;
175 list_add_tail_rcu(&entry->list,
176 &tomoyo_domain_initializer_list);
177 entry = NULL;
178 error = 0;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900179 }
Tetsuo Handaf737d952010-01-03 21:16:32 +0900180 mutex_unlock(&tomoyo_policy_lock);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900181 out:
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900182 tomoyo_put_name(saved_domainname);
183 tomoyo_put_name(saved_program);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900184 kfree(entry);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900185 return error;
186}
187
188/**
189 * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
190 *
191 * @head: Pointer to "struct tomoyo_io_buffer".
192 *
193 * Returns true on success, false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900194 *
195 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900196 */
197bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
198{
199 struct list_head *pos;
200 bool done = true;
201
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900202 list_for_each_cookie(pos, head->read_var2,
203 &tomoyo_domain_initializer_list) {
204 const char *no;
205 const char *from = "";
206 const char *domain = "";
207 struct tomoyo_domain_initializer_entry *ptr;
208 ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
209 list);
210 if (ptr->is_deleted)
211 continue;
212 no = ptr->is_not ? "no_" : "";
213 if (ptr->domainname) {
214 from = " from ";
215 domain = ptr->domainname->name;
216 }
Tetsuo Handa7d2948b2009-06-02 20:42:24 +0900217 done = tomoyo_io_printf(head,
218 "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
219 "%s%s%s\n", no, ptr->program->name,
220 from, domain);
221 if (!done)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900222 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900223 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900224 return done;
225}
226
227/**
228 * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
229 *
230 * @data: String to parse.
231 * @is_not: True if it is "no_initialize_domain" entry.
232 * @is_delete: True if it is a delete request.
233 *
234 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900235 *
236 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900237 */
238int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
239 const bool is_delete)
240{
241 char *cp = strstr(data, " from ");
242
243 if (cp) {
244 *cp = '\0';
245 return tomoyo_update_domain_initializer_entry(cp + 6, data,
246 is_not,
247 is_delete);
248 }
249 return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
250 is_delete);
251}
252
253/**
254 * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
255 *
256 * @domainname: The name of domain.
257 * @program: The name of program.
258 * @last_name: The last component of @domainname.
259 *
260 * Returns true if executing @program reinitializes domain transition,
261 * false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900262 *
263 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900264 */
265static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
266 domainname,
267 const struct tomoyo_path_info *program,
268 const struct tomoyo_path_info *
269 last_name)
270{
271 struct tomoyo_domain_initializer_entry *ptr;
272 bool flag = false;
273
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900274 list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900275 if (ptr->is_deleted)
276 continue;
277 if (ptr->domainname) {
278 if (!ptr->is_last_name) {
279 if (ptr->domainname != domainname)
280 continue;
281 } else {
282 if (tomoyo_pathcmp(ptr->domainname, last_name))
283 continue;
284 }
285 }
286 if (tomoyo_pathcmp(ptr->program, program))
287 continue;
288 if (ptr->is_not) {
289 flag = false;
290 break;
291 }
292 flag = true;
293 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900294 return flag;
295}
296
Tetsuo Handac3fa1092009-06-08 12:37:39 +0900297/*
298 * tomoyo_domain_keeper_list is used for holding list of domainnames which
299 * suppresses domain transition. Normally, a domainname is monotonically
300 * getting longer. But sometimes, we want to suppress domain transition.
301 * It would be convenient for us that programs executed from a login session
302 * belong to the same domain. Thus, TOMOYO provides a way to suppress domain
303 * transition.
304 *
305 * An entry is added by
306 *
307 * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
308 * /sys/kernel/security/tomoyo/exception_policy
309 *
310 * and is deleted by
311 *
312 * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
313 * /sys/kernel/security/tomoyo/exception_policy
314 *
315 * and all entries are retrieved by
316 *
317 * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy
318 *
319 * In the example above, any process which belongs to
320 * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain,
321 * unless explicitly specified by "initialize_domain" or "no_keep_domain".
322 *
323 * You may specify a program using "from" keyword.
324 * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash"
325 * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash"
326 * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain.
327 *
328 * You may add "no_" prefix to "keep_domain".
329 * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and
330 * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will
331 * cause "/usr/bin/passwd" to belong to
332 * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
333 * explicitly specified by "initialize_domain".
334 */
Tetsuo Handa847b1732010-02-11 09:43:54 +0900335LIST_HEAD(tomoyo_domain_keeper_list);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900336
337/**
338 * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
339 *
340 * @domainname: The name of domain.
341 * @program: The name of program. May be NULL.
342 * @is_not: True if it is "no_keep_domain" entry.
343 * @is_delete: True if it is a delete request.
344 *
345 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900346 *
347 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900348 */
349static int tomoyo_update_domain_keeper_entry(const char *domainname,
350 const char *program,
351 const bool is_not,
352 const bool is_delete)
353{
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900354 struct tomoyo_domain_keeper_entry *entry = NULL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900355 struct tomoyo_domain_keeper_entry *ptr;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900356 const struct tomoyo_path_info *saved_domainname = NULL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900357 const struct tomoyo_path_info *saved_program = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900358 int error = is_delete ? -ENOENT : -ENOMEM;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900359 bool is_last_name = false;
360
361 if (!tomoyo_is_domain_def(domainname) &&
Tetsuo Handa17080002010-02-16 21:14:48 +0900362 tomoyo_is_correct_path(domainname, 1, -1, -1))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900363 is_last_name = true;
Tetsuo Handa17080002010-02-16 21:14:48 +0900364 else if (!tomoyo_is_correct_domain(domainname))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900365 return -EINVAL;
366 if (program) {
Tetsuo Handa17080002010-02-16 21:14:48 +0900367 if (!tomoyo_is_correct_path(program, 1, -1, -1))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900368 return -EINVAL;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900369 saved_program = tomoyo_get_name(program);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900370 if (!saved_program)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900371 goto out;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900372 }
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900373 saved_domainname = tomoyo_get_name(domainname);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900374 if (!saved_domainname)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900375 goto out;
376 if (!is_delete)
Tetsuo Handa4e5d6f72010-04-28 14:17:42 +0900377 entry = kmalloc(sizeof(*entry), GFP_NOFS);
Tetsuo Handa29282382010-05-06 00:18:15 +0900378 if (mutex_lock_interruptible(&tomoyo_policy_lock))
379 goto out;
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900380 list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900381 if (ptr->is_not != is_not ||
382 ptr->domainname != saved_domainname ||
383 ptr->program != saved_program)
384 continue;
385 ptr->is_deleted = is_delete;
386 error = 0;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900387 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900388 }
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900389 if (!is_delete && error && tomoyo_memory_ok(entry)) {
390 entry->domainname = saved_domainname;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900391 saved_domainname = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900392 entry->program = saved_program;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900393 saved_program = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900394 entry->is_not = is_not;
395 entry->is_last_name = is_last_name;
396 list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list);
397 entry = NULL;
398 error = 0;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900399 }
Tetsuo Handaf737d952010-01-03 21:16:32 +0900400 mutex_unlock(&tomoyo_policy_lock);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900401 out:
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900402 tomoyo_put_name(saved_domainname);
403 tomoyo_put_name(saved_program);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900404 kfree(entry);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900405 return error;
406}
407
408/**
409 * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
410 *
411 * @data: String to parse.
412 * @is_not: True if it is "no_keep_domain" entry.
413 * @is_delete: True if it is a delete request.
414 *
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900415 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900416 */
417int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
418 const bool is_delete)
419{
420 char *cp = strstr(data, " from ");
421
422 if (cp) {
423 *cp = '\0';
424 return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
425 is_delete);
426 }
427 return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
428}
429
430/**
431 * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
432 *
433 * @head: Pointer to "struct tomoyo_io_buffer".
434 *
435 * Returns true on success, false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900436 *
437 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900438 */
439bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
440{
441 struct list_head *pos;
Tetsuo Handa33043cb2009-02-13 16:00:58 +0900442 bool done = true;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900443
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900444 list_for_each_cookie(pos, head->read_var2,
445 &tomoyo_domain_keeper_list) {
446 struct tomoyo_domain_keeper_entry *ptr;
447 const char *no;
448 const char *from = "";
449 const char *program = "";
450
451 ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
452 if (ptr->is_deleted)
453 continue;
454 no = ptr->is_not ? "no_" : "";
455 if (ptr->program) {
456 from = " from ";
457 program = ptr->program->name;
458 }
Tetsuo Handa7d2948b2009-06-02 20:42:24 +0900459 done = tomoyo_io_printf(head,
460 "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
461 "%s%s%s\n", no, program, from,
462 ptr->domainname->name);
463 if (!done)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900464 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900465 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900466 return done;
467}
468
469/**
470 * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
471 *
472 * @domainname: The name of domain.
473 * @program: The name of program.
474 * @last_name: The last component of @domainname.
475 *
476 * Returns true if executing @program supresses domain transition,
477 * false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900478 *
479 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900480 */
481static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
482 const struct tomoyo_path_info *program,
483 const struct tomoyo_path_info *last_name)
484{
485 struct tomoyo_domain_keeper_entry *ptr;
486 bool flag = false;
487
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900488 list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900489 if (ptr->is_deleted)
490 continue;
491 if (!ptr->is_last_name) {
492 if (ptr->domainname != domainname)
493 continue;
494 } else {
495 if (tomoyo_pathcmp(ptr->domainname, last_name))
496 continue;
497 }
498 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
499 continue;
500 if (ptr->is_not) {
501 flag = false;
502 break;
503 }
504 flag = true;
505 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900506 return flag;
507}
508
Tetsuo Handac3fa1092009-06-08 12:37:39 +0900509/*
510 * tomoyo_alias_list is used for holding list of symlink's pathnames which are
511 * allowed to be passed to an execve() request. Normally, the domainname which
512 * the current process will belong to after execve() succeeds is calculated
513 * using dereferenced pathnames. But some programs behave differently depending
514 * on the name passed to argv[0]. For busybox, calculating domainname using
515 * dereferenced pathnames will cause all programs in the busybox to belong to
516 * the same domain. Thus, TOMOYO provides a way to allow use of symlink's
517 * pathname for checking execve()'s permission and calculating domainname which
518 * the current process will belong to after execve() succeeds.
519 *
520 * An entry is added by
521 *
522 * # echo 'alias /bin/busybox /bin/cat' > \
523 * /sys/kernel/security/tomoyo/exception_policy
524 *
525 * and is deleted by
526 *
527 * # echo 'delete alias /bin/busybox /bin/cat' > \
528 * /sys/kernel/security/tomoyo/exception_policy
529 *
530 * and all entries are retrieved by
531 *
532 * # grep ^alias /sys/kernel/security/tomoyo/exception_policy
533 *
534 * In the example above, if /bin/cat is a symlink to /bin/busybox and execution
535 * of /bin/cat is requested, permission is checked for /bin/cat rather than
536 * /bin/busybox and domainname which the current process will belong to after
537 * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
538 */
Tetsuo Handa847b1732010-02-11 09:43:54 +0900539LIST_HEAD(tomoyo_alias_list);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900540
541/**
542 * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
543 *
544 * @original_name: The original program's real name.
545 * @aliased_name: The symbolic program's symbolic link's name.
546 * @is_delete: True if it is a delete request.
547 *
548 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900549 *
550 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900551 */
552static int tomoyo_update_alias_entry(const char *original_name,
553 const char *aliased_name,
554 const bool is_delete)
555{
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900556 struct tomoyo_alias_entry *entry = NULL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900557 struct tomoyo_alias_entry *ptr;
558 const struct tomoyo_path_info *saved_original_name;
559 const struct tomoyo_path_info *saved_aliased_name;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900560 int error = is_delete ? -ENOENT : -ENOMEM;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900561
Tetsuo Handa17080002010-02-16 21:14:48 +0900562 if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
563 !tomoyo_is_correct_path(aliased_name, 1, -1, -1))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900564 return -EINVAL; /* No patterns allowed. */
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900565 saved_original_name = tomoyo_get_name(original_name);
566 saved_aliased_name = tomoyo_get_name(aliased_name);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900567 if (!saved_original_name || !saved_aliased_name)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900568 goto out;
569 if (!is_delete)
Tetsuo Handa4e5d6f72010-04-28 14:17:42 +0900570 entry = kmalloc(sizeof(*entry), GFP_NOFS);
Tetsuo Handa29282382010-05-06 00:18:15 +0900571 if (mutex_lock_interruptible(&tomoyo_policy_lock))
572 goto out;
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900573 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900574 if (ptr->original_name != saved_original_name ||
575 ptr->aliased_name != saved_aliased_name)
576 continue;
577 ptr->is_deleted = is_delete;
578 error = 0;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900579 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900580 }
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900581 if (!is_delete && error && tomoyo_memory_ok(entry)) {
582 entry->original_name = saved_original_name;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900583 saved_original_name = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900584 entry->aliased_name = saved_aliased_name;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900585 saved_aliased_name = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900586 list_add_tail_rcu(&entry->list, &tomoyo_alias_list);
587 entry = NULL;
588 error = 0;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900589 }
Tetsuo Handaf737d952010-01-03 21:16:32 +0900590 mutex_unlock(&tomoyo_policy_lock);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900591 out:
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900592 tomoyo_put_name(saved_original_name);
593 tomoyo_put_name(saved_aliased_name);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900594 kfree(entry);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900595 return error;
596}
597
598/**
599 * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
600 *
601 * @head: Pointer to "struct tomoyo_io_buffer".
602 *
603 * Returns true on success, false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900604 *
605 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900606 */
607bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
608{
609 struct list_head *pos;
610 bool done = true;
611
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900612 list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
613 struct tomoyo_alias_entry *ptr;
614
615 ptr = list_entry(pos, struct tomoyo_alias_entry, list);
616 if (ptr->is_deleted)
617 continue;
Tetsuo Handa7d2948b2009-06-02 20:42:24 +0900618 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
619 ptr->original_name->name,
620 ptr->aliased_name->name);
621 if (!done)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900622 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900623 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900624 return done;
625}
626
627/**
628 * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
629 *
630 * @data: String to parse.
631 * @is_delete: True if it is a delete request.
632 *
633 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900634 *
635 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900636 */
637int tomoyo_write_alias_policy(char *data, const bool is_delete)
638{
639 char *cp = strchr(data, ' ');
640
641 if (!cp)
642 return -EINVAL;
643 *cp++ = '\0';
644 return tomoyo_update_alias_entry(data, cp, is_delete);
645}
646
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900647/**
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900648 * tomoyo_find_or_assign_new_domain - Create a domain.
649 *
650 * @domainname: The name of domain.
651 * @profile: Profile number to assign if the domain was newly created.
652 *
653 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900654 *
655 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900656 */
657struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
658 domainname,
659 const u8 profile)
660{
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900661 struct tomoyo_domain_info *entry;
Tetsuo Handa29282382010-05-06 00:18:15 +0900662 struct tomoyo_domain_info *domain = NULL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900663 const struct tomoyo_path_info *saved_domainname;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900664 bool found = false;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900665
Tetsuo Handa17080002010-02-16 21:14:48 +0900666 if (!tomoyo_is_correct_domain(domainname))
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900667 return NULL;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900668 saved_domainname = tomoyo_get_name(domainname);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900669 if (!saved_domainname)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900670 return NULL;
Tetsuo Handa4e5d6f72010-04-28 14:17:42 +0900671 entry = kzalloc(sizeof(*entry), GFP_NOFS);
Tetsuo Handa29282382010-05-06 00:18:15 +0900672 if (mutex_lock_interruptible(&tomoyo_policy_lock))
673 goto out;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900674 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
675 if (domain->is_deleted ||
676 tomoyo_pathcmp(saved_domainname, domain->domainname))
677 continue;
678 found = true;
679 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900680 }
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900681 if (!found && tomoyo_memory_ok(entry)) {
682 INIT_LIST_HEAD(&entry->acl_info_list);
683 entry->domainname = saved_domainname;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900684 saved_domainname = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900685 entry->profile = profile;
686 list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
687 domain = entry;
688 entry = NULL;
689 found = true;
690 }
Tetsuo Handaf737d952010-01-03 21:16:32 +0900691 mutex_unlock(&tomoyo_policy_lock);
Tetsuo Handa29282382010-05-06 00:18:15 +0900692 out:
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900693 tomoyo_put_name(saved_domainname);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900694 kfree(entry);
695 return found ? domain : NULL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900696}
697
698/**
699 * tomoyo_find_next_domain - Find a domain.
700 *
Tetsuo Handa56f8c9b2009-06-19 14:13:27 +0900701 * @bprm: Pointer to "struct linux_binprm".
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900702 *
703 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900704 *
705 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900706 */
Tetsuo Handa56f8c9b2009-06-19 14:13:27 +0900707int tomoyo_find_next_domain(struct linux_binprm *bprm)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900708{
709 /*
710 * This function assumes that the size of buffer returned by
711 * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
712 */
Tetsuo Handa4e5d6f72010-04-28 14:17:42 +0900713 struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900714 struct tomoyo_domain_info *old_domain = tomoyo_domain();
715 struct tomoyo_domain_info *domain = NULL;
716 const char *old_domain_name = old_domain->domainname->name;
717 const char *original_name = bprm->filename;
718 char *new_domain_name = NULL;
719 char *real_program_name = NULL;
720 char *symlink_program_name = NULL;
721 const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
722 const bool is_enforce = (mode == 3);
723 int retval = -ENOMEM;
724 struct tomoyo_path_info r; /* real name */
725 struct tomoyo_path_info s; /* symlink name */
726 struct tomoyo_path_info l; /* last name */
727 static bool initialized;
728
729 if (!tmp)
730 goto out;
731
732 if (!initialized) {
733 /*
734 * Built-in initializers. This is needed because policies are
735 * not loaded until starting /sbin/init.
736 */
737 tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
738 false, false);
739 tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
740 false, false);
741 initialized = true;
742 }
743
744 /* Get tomoyo_realpath of program. */
745 retval = -ENOENT;
746 /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
747 real_program_name = tomoyo_realpath(original_name);
748 if (!real_program_name)
749 goto out;
750 /* Get tomoyo_realpath of symbolic link. */
751 symlink_program_name = tomoyo_realpath_nofollow(original_name);
752 if (!symlink_program_name)
753 goto out;
754
755 r.name = real_program_name;
756 tomoyo_fill_path_info(&r);
757 s.name = symlink_program_name;
758 tomoyo_fill_path_info(&s);
759 l.name = tomoyo_get_last_name(old_domain);
760 tomoyo_fill_path_info(&l);
761
762 /* Check 'alias' directive. */
763 if (tomoyo_pathcmp(&r, &s)) {
764 struct tomoyo_alias_entry *ptr;
765 /* Is this program allowed to be called via symbolic links? */
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900766 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900767 if (ptr->is_deleted ||
768 tomoyo_pathcmp(&r, ptr->original_name) ||
769 tomoyo_pathcmp(&s, ptr->aliased_name))
770 continue;
771 memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
772 strncpy(real_program_name, ptr->aliased_name->name,
773 TOMOYO_MAX_PATHNAME_LEN - 1);
774 tomoyo_fill_path_info(&r);
775 break;
776 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900777 }
778
779 /* Check execute permission. */
Tetsuo Handabcb86972009-06-04 15:14:34 +0900780 retval = tomoyo_check_exec_perm(old_domain, &r);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900781 if (retval < 0)
782 goto out;
783
784 new_domain_name = tmp->buffer;
785 if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
786 /* Transit to the child of tomoyo_kernel_domain domain. */
787 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
788 TOMOYO_ROOT_NAME " " "%s", real_program_name);
789 } else if (old_domain == &tomoyo_kernel_domain &&
790 !tomoyo_policy_loaded) {
791 /*
792 * Needn't to transit from kernel domain before starting
793 * /sbin/init. But transit from kernel domain if executing
794 * initializers because they might start before /sbin/init.
795 */
796 domain = old_domain;
797 } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
798 /* Keep current domain. */
799 domain = old_domain;
800 } else {
801 /* Normal domain transition. */
802 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
803 "%s %s", old_domain_name, real_program_name);
804 }
805 if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
806 goto done;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900807 domain = tomoyo_find_domain(new_domain_name);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900808 if (domain)
809 goto done;
810 if (is_enforce)
811 goto done;
812 domain = tomoyo_find_or_assign_new_domain(new_domain_name,
813 old_domain->profile);
814 done:
815 if (domain)
816 goto out;
817 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
818 new_domain_name);
819 if (is_enforce)
820 retval = -EPERM;
821 else
Tetsuo Handaea13ddb2010-02-03 06:43:06 +0900822 old_domain->transition_failed = true;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900823 out:
Tetsuo Handa56f8c9b2009-06-19 14:13:27 +0900824 if (!domain)
825 domain = old_domain;
Tetsuo Handaec8e6a42010-02-11 09:43:20 +0900826 /* Update reference count on "struct tomoyo_domain_info". */
827 atomic_inc(&domain->users);
Tetsuo Handa56f8c9b2009-06-19 14:13:27 +0900828 bprm->cred->security = domain;
Tetsuo Handa8e2d39a2010-01-26 20:45:27 +0900829 kfree(real_program_name);
830 kfree(symlink_program_name);
831 kfree(tmp);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900832 return retval;
833}