blob: 3575b0e7c7fdd03b1334349422a53cf8b9e0baea [file] [log] [blame]
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +09001/*
2 * security/tomoyo/domain.c
3 *
Tetsuo Handac3ef1502010-05-17 10:12:46 +09004 * Domain transition functions for TOMOYO.
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +09005 *
Tetsuo Handac3ef1502010-05-17 10:12:46 +09006 * Copyright (C) 2005-2010 NTT DATA CORPORATION
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +09007 */
8
9#include "common.h"
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +090010#include <linux/binfmts.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +090012
13/* Variables definitions.*/
14
15/* The initial domain. */
16struct tomoyo_domain_info tomoyo_kernel_domain;
17
Tetsuo Handa237ab452010-06-12 20:46:22 +090018/**
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +090019 * tomoyo_update_policy - Update an entry for exception policy.
20 *
21 * @new_entry: Pointer to "struct tomoyo_acl_info".
22 * @size: Size of @new_entry in bytes.
23 * @is_delete: True if it is a delete request.
24 * @list: Pointer to "struct list_head".
25 * @check_duplicate: Callback function to find duplicated entry.
26 *
27 * Returns 0 on success, negative value otherwise.
28 *
29 * Caller holds tomoyo_read_lock().
30 */
31int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
32 bool is_delete, struct list_head *list,
33 bool (*check_duplicate) (const struct tomoyo_acl_head
34 *,
35 const struct tomoyo_acl_head
36 *))
37{
38 int error = is_delete ? -ENOENT : -ENOMEM;
39 struct tomoyo_acl_head *entry;
40
41 if (mutex_lock_interruptible(&tomoyo_policy_lock))
42 return -ENOMEM;
43 list_for_each_entry_rcu(entry, list, list) {
44 if (!check_duplicate(entry, new_entry))
45 continue;
46 entry->is_deleted = is_delete;
47 error = 0;
48 break;
49 }
50 if (error && !is_delete) {
51 entry = tomoyo_commit_ok(new_entry, size);
52 if (entry) {
53 list_add_tail_rcu(&entry->list, list);
54 error = 0;
55 }
56 }
57 mutex_unlock(&tomoyo_policy_lock);
58 return error;
59}
60
61/**
Tetsuo Handa237ab452010-06-12 20:46:22 +090062 * tomoyo_update_domain - Update an entry for domain policy.
63 *
64 * @new_entry: Pointer to "struct tomoyo_acl_info".
65 * @size: Size of @new_entry in bytes.
66 * @is_delete: True if it is a delete request.
67 * @domain: Pointer to "struct tomoyo_domain_info".
68 * @check_duplicate: Callback function to find duplicated entry.
69 * @merge_duplicate: Callback function to merge duplicated entry.
70 *
71 * Returns 0 on success, negative value otherwise.
72 *
73 * Caller holds tomoyo_read_lock().
74 */
75int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
76 bool is_delete, struct tomoyo_domain_info *domain,
77 bool (*check_duplicate) (const struct tomoyo_acl_info
78 *,
79 const struct tomoyo_acl_info
80 *),
81 bool (*merge_duplicate) (struct tomoyo_acl_info *,
82 struct tomoyo_acl_info *,
83 const bool))
84{
85 int error = is_delete ? -ENOENT : -ENOMEM;
86 struct tomoyo_acl_info *entry;
87
88 if (mutex_lock_interruptible(&tomoyo_policy_lock))
89 return error;
90 list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
91 if (!check_duplicate(entry, new_entry))
92 continue;
93 if (merge_duplicate)
94 entry->is_deleted = merge_duplicate(entry, new_entry,
95 is_delete);
96 else
97 entry->is_deleted = is_delete;
98 error = 0;
99 break;
100 }
101 if (error && !is_delete) {
102 entry = tomoyo_commit_ok(new_entry, size);
103 if (entry) {
104 list_add_tail_rcu(&entry->list, &domain->acl_info_list);
105 error = 0;
106 }
107 }
108 mutex_unlock(&tomoyo_policy_lock);
109 return error;
110}
111
Tetsuo Handa99a85252010-06-16 16:22:51 +0900112void tomoyo_check_acl(struct tomoyo_request_info *r,
113 bool (*check_entry) (const struct tomoyo_request_info *,
114 const struct tomoyo_acl_info *))
115{
116 const struct tomoyo_domain_info *domain = r->domain;
117 struct tomoyo_acl_info *ptr;
118
119 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
120 if (ptr->is_deleted || ptr->type != r->param_type)
121 continue;
122 if (check_entry(r, ptr)) {
123 r->granted = true;
124 return;
125 }
126 }
127 r->granted = false;
128}
129
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900130/* The list for "struct tomoyo_domain_info". */
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900131LIST_HEAD(tomoyo_domain_list);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900132
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900133struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY];
134struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP];
135
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900136/**
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900137 * tomoyo_get_last_name - Get last component of a domainname.
138 *
139 * @domain: Pointer to "struct tomoyo_domain_info".
140 *
141 * Returns the last component of the domainname.
142 */
143const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
144{
145 const char *cp0 = domain->domainname->name;
146 const char *cp1 = strrchr(cp0, ' ');
147
148 if (cp1)
149 return cp1 + 1;
150 return cp0;
151}
152
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900153static bool tomoyo_same_domain_initializer_entry(const struct tomoyo_acl_head *
154 a,
155 const struct tomoyo_acl_head *
156 b)
157{
158 const struct tomoyo_domain_initializer_entry *p1 =
159 container_of(a, typeof(*p1), head);
160 const struct tomoyo_domain_initializer_entry *p2 =
161 container_of(b, typeof(*p2), head);
162 return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
163 && p1->domainname == p2->domainname
164 && p1->program == p2->program;
165}
166
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900167/**
168 * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
169 *
170 * @domainname: The name of domain. May be NULL.
171 * @program: The name of program.
172 * @is_not: True if it is "no_initialize_domain" entry.
173 * @is_delete: True if it is a delete request.
174 *
175 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900176 *
177 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900178 */
179static int tomoyo_update_domain_initializer_entry(const char *domainname,
180 const char *program,
181 const bool is_not,
182 const bool is_delete)
183{
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900184 struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900185 int error = is_delete ? -ENOENT : -ENOMEM;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900186
Tetsuo Handa75093152010-06-16 16:23:55 +0900187 if (!tomoyo_correct_path(program))
Tetsuo Handa3f629632010-06-03 20:37:26 +0900188 return -EINVAL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900189 if (domainname) {
Tetsuo Handa75093152010-06-16 16:23:55 +0900190 if (!tomoyo_domain_def(domainname) &&
191 tomoyo_correct_path(domainname))
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900192 e.is_last_name = true;
Tetsuo Handa75093152010-06-16 16:23:55 +0900193 else if (!tomoyo_correct_domain(domainname))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900194 return -EINVAL;
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900195 e.domainname = tomoyo_get_name(domainname);
196 if (!e.domainname)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900197 goto out;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900198 }
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900199 e.program = tomoyo_get_name(program);
200 if (!e.program)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900201 goto out;
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900202 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900203 &tomoyo_policy_list
204 [TOMOYO_ID_DOMAIN_INITIALIZER],
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900205 tomoyo_same_domain_initializer_entry);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900206 out:
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900207 tomoyo_put_name(e.domainname);
208 tomoyo_put_name(e.program);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900209 return error;
210}
211
212/**
213 * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
214 *
215 * @head: Pointer to "struct tomoyo_io_buffer".
216 *
217 * Returns true on success, false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900218 *
219 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900220 */
221bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
222{
223 struct list_head *pos;
224 bool done = true;
225
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900226 list_for_each_cookie(pos, head->read_var2, &tomoyo_policy_list
227 [TOMOYO_ID_DOMAIN_INITIALIZER]) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900228 const char *no;
229 const char *from = "";
230 const char *domain = "";
231 struct tomoyo_domain_initializer_entry *ptr;
232 ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
Tetsuo Handa82e0f002010-06-15 09:22:42 +0900233 head.list);
234 if (ptr->head.is_deleted)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900235 continue;
236 no = ptr->is_not ? "no_" : "";
237 if (ptr->domainname) {
238 from = " from ";
239 domain = ptr->domainname->name;
240 }
Tetsuo Handa7d2948b2009-06-02 20:42:24 +0900241 done = tomoyo_io_printf(head,
242 "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
243 "%s%s%s\n", no, ptr->program->name,
244 from, domain);
245 if (!done)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900246 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900247 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900248 return done;
249}
250
251/**
252 * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
253 *
254 * @data: String to parse.
255 * @is_not: True if it is "no_initialize_domain" entry.
256 * @is_delete: True if it is a delete request.
257 *
258 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900259 *
260 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900261 */
262int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
263 const bool is_delete)
264{
265 char *cp = strstr(data, " from ");
266
267 if (cp) {
268 *cp = '\0';
269 return tomoyo_update_domain_initializer_entry(cp + 6, data,
270 is_not,
271 is_delete);
272 }
273 return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
274 is_delete);
275}
276
277/**
Tetsuo Handa75093152010-06-16 16:23:55 +0900278 * tomoyo_domain_initializer - Check whether the given program causes domainname reinitialization.
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900279 *
280 * @domainname: The name of domain.
281 * @program: The name of program.
282 * @last_name: The last component of @domainname.
283 *
284 * Returns true if executing @program reinitializes domain transition,
285 * false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900286 *
287 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900288 */
Tetsuo Handa75093152010-06-16 16:23:55 +0900289static bool tomoyo_domain_initializer(const struct tomoyo_path_info *
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900290 domainname,
291 const struct tomoyo_path_info *program,
292 const struct tomoyo_path_info *
293 last_name)
294{
295 struct tomoyo_domain_initializer_entry *ptr;
296 bool flag = false;
297
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900298 list_for_each_entry_rcu(ptr, &tomoyo_policy_list
299 [TOMOYO_ID_DOMAIN_INITIALIZER], head.list) {
Tetsuo Handa82e0f002010-06-15 09:22:42 +0900300 if (ptr->head.is_deleted)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900301 continue;
302 if (ptr->domainname) {
303 if (!ptr->is_last_name) {
304 if (ptr->domainname != domainname)
305 continue;
306 } else {
307 if (tomoyo_pathcmp(ptr->domainname, last_name))
308 continue;
309 }
310 }
311 if (tomoyo_pathcmp(ptr->program, program))
312 continue;
313 if (ptr->is_not) {
314 flag = false;
315 break;
316 }
317 flag = true;
318 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900319 return flag;
320}
321
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900322static bool tomoyo_same_domain_keeper_entry(const struct tomoyo_acl_head *a,
323 const struct tomoyo_acl_head *b)
324{
325 const struct tomoyo_domain_keeper_entry *p1 =
326 container_of(a, typeof(*p1), head);
327 const struct tomoyo_domain_keeper_entry *p2 =
328 container_of(b, typeof(*p2), head);
329 return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name
330 && p1->domainname == p2->domainname
331 && p1->program == p2->program;
332}
333
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900334/**
335 * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
336 *
337 * @domainname: The name of domain.
338 * @program: The name of program. May be NULL.
339 * @is_not: True if it is "no_keep_domain" entry.
340 * @is_delete: True if it is a delete request.
341 *
342 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900343 *
344 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900345 */
346static int tomoyo_update_domain_keeper_entry(const char *domainname,
347 const char *program,
348 const bool is_not,
349 const bool is_delete)
350{
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900351 struct tomoyo_domain_keeper_entry e = { .is_not = is_not };
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900352 int error = is_delete ? -ENOENT : -ENOMEM;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900353
Tetsuo Handa75093152010-06-16 16:23:55 +0900354 if (!tomoyo_domain_def(domainname) &&
355 tomoyo_correct_path(domainname))
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900356 e.is_last_name = true;
Tetsuo Handa75093152010-06-16 16:23:55 +0900357 else if (!tomoyo_correct_domain(domainname))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900358 return -EINVAL;
359 if (program) {
Tetsuo Handa75093152010-06-16 16:23:55 +0900360 if (!tomoyo_correct_path(program))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900361 return -EINVAL;
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900362 e.program = tomoyo_get_name(program);
363 if (!e.program)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900364 goto out;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900365 }
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900366 e.domainname = tomoyo_get_name(domainname);
367 if (!e.domainname)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900368 goto out;
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900369 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900370 &tomoyo_policy_list
371 [TOMOYO_ID_DOMAIN_KEEPER],
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900372 tomoyo_same_domain_keeper_entry);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900373 out:
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900374 tomoyo_put_name(e.domainname);
375 tomoyo_put_name(e.program);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900376 return error;
377}
378
379/**
380 * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
381 *
382 * @data: String to parse.
383 * @is_not: True if it is "no_keep_domain" entry.
384 * @is_delete: True if it is a delete request.
385 *
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900386 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900387 */
388int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
389 const bool is_delete)
390{
391 char *cp = strstr(data, " from ");
392
393 if (cp) {
394 *cp = '\0';
395 return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
396 is_delete);
397 }
398 return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
399}
400
401/**
402 * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
403 *
404 * @head: Pointer to "struct tomoyo_io_buffer".
405 *
406 * Returns true on success, false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900407 *
408 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900409 */
410bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
411{
412 struct list_head *pos;
Tetsuo Handa33043cb2009-02-13 16:00:58 +0900413 bool done = true;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900414
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900415 list_for_each_cookie(pos, head->read_var2,
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900416 &tomoyo_policy_list[TOMOYO_ID_DOMAIN_KEEPER]) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900417 struct tomoyo_domain_keeper_entry *ptr;
418 const char *no;
419 const char *from = "";
420 const char *program = "";
421
Tetsuo Handa82e0f002010-06-15 09:22:42 +0900422 ptr = list_entry(pos, struct tomoyo_domain_keeper_entry,
423 head.list);
424 if (ptr->head.is_deleted)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900425 continue;
426 no = ptr->is_not ? "no_" : "";
427 if (ptr->program) {
428 from = " from ";
429 program = ptr->program->name;
430 }
Tetsuo Handa7d2948b2009-06-02 20:42:24 +0900431 done = tomoyo_io_printf(head,
432 "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
433 "%s%s%s\n", no, program, from,
434 ptr->domainname->name);
435 if (!done)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900436 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900437 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900438 return done;
439}
440
441/**
Tetsuo Handa75093152010-06-16 16:23:55 +0900442 * tomoyo_domain_keeper - Check whether the given program causes domain transition suppression.
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900443 *
444 * @domainname: The name of domain.
445 * @program: The name of program.
446 * @last_name: The last component of @domainname.
447 *
448 * Returns true if executing @program supresses domain transition,
449 * false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900450 *
451 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900452 */
Tetsuo Handa75093152010-06-16 16:23:55 +0900453static bool tomoyo_domain_keeper(const struct tomoyo_path_info *domainname,
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900454 const struct tomoyo_path_info *program,
455 const struct tomoyo_path_info *last_name)
456{
457 struct tomoyo_domain_keeper_entry *ptr;
458 bool flag = false;
459
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900460 list_for_each_entry_rcu(ptr,
461 &tomoyo_policy_list[TOMOYO_ID_DOMAIN_KEEPER],
462 head.list) {
Tetsuo Handa82e0f002010-06-15 09:22:42 +0900463 if (ptr->head.is_deleted)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900464 continue;
465 if (!ptr->is_last_name) {
466 if (ptr->domainname != domainname)
467 continue;
468 } else {
469 if (tomoyo_pathcmp(ptr->domainname, last_name))
470 continue;
471 }
472 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
473 continue;
474 if (ptr->is_not) {
475 flag = false;
476 break;
477 }
478 flag = true;
479 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900480 return flag;
481}
482
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900483static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a,
484 const struct tomoyo_acl_head *b)
485{
486 const struct tomoyo_aggregator_entry *p1 = container_of(a, typeof(*p1),
487 head);
488 const struct tomoyo_aggregator_entry *p2 = container_of(b, typeof(*p2),
489 head);
490 return p1->original_name == p2->original_name &&
491 p1->aggregated_name == p2->aggregated_name;
492}
493
Tetsuo Handa10843072010-06-03 20:38:03 +0900494/**
495 * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator_entry" list.
496 *
497 * @original_name: The original program's name.
498 * @aggregated_name: The program name to use.
499 * @is_delete: True if it is a delete request.
500 *
501 * Returns 0 on success, negative value otherwise.
502 *
503 * Caller holds tomoyo_read_lock().
504 */
505static int tomoyo_update_aggregator_entry(const char *original_name,
506 const char *aggregated_name,
507 const bool is_delete)
508{
Tetsuo Handa10843072010-06-03 20:38:03 +0900509 struct tomoyo_aggregator_entry e = { };
510 int error = is_delete ? -ENOENT : -ENOMEM;
511
Tetsuo Handa75093152010-06-16 16:23:55 +0900512 if (!tomoyo_correct_path(original_name) ||
513 !tomoyo_correct_path(aggregated_name))
Tetsuo Handa10843072010-06-03 20:38:03 +0900514 return -EINVAL;
515 e.original_name = tomoyo_get_name(original_name);
516 e.aggregated_name = tomoyo_get_name(aggregated_name);
517 if (!e.original_name || !e.aggregated_name ||
518 e.aggregated_name->is_patterned) /* No patterns allowed. */
519 goto out;
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900520 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900521 &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR],
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900522 tomoyo_same_aggregator_entry);
Tetsuo Handa10843072010-06-03 20:38:03 +0900523 out:
524 tomoyo_put_name(e.original_name);
525 tomoyo_put_name(e.aggregated_name);
526 return error;
527}
528
529/**
530 * tomoyo_read_aggregator_policy - Read "struct tomoyo_aggregator_entry" list.
531 *
532 * @head: Pointer to "struct tomoyo_io_buffer".
533 *
534 * Returns true on success, false otherwise.
535 *
536 * Caller holds tomoyo_read_lock().
537 */
538bool tomoyo_read_aggregator_policy(struct tomoyo_io_buffer *head)
539{
540 struct list_head *pos;
541 bool done = true;
542
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900543 list_for_each_cookie(pos, head->read_var2,
544 &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR]) {
Tetsuo Handa10843072010-06-03 20:38:03 +0900545 struct tomoyo_aggregator_entry *ptr;
546
Tetsuo Handa82e0f002010-06-15 09:22:42 +0900547 ptr = list_entry(pos, struct tomoyo_aggregator_entry,
548 head.list);
549 if (ptr->head.is_deleted)
Tetsuo Handa10843072010-06-03 20:38:03 +0900550 continue;
551 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_AGGREGATOR
552 "%s %s\n", ptr->original_name->name,
553 ptr->aggregated_name->name);
554 if (!done)
555 break;
556 }
557 return done;
558}
559
560/**
561 * tomoyo_write_aggregator_policy - Write "struct tomoyo_aggregator_entry" list.
562 *
563 * @data: String to parse.
564 * @is_delete: True if it is a delete request.
565 *
566 * Returns 0 on success, negative value otherwise.
567 *
568 * Caller holds tomoyo_read_lock().
569 */
570int tomoyo_write_aggregator_policy(char *data, const bool is_delete)
571{
572 char *cp = strchr(data, ' ');
573
574 if (!cp)
575 return -EINVAL;
576 *cp++ = '\0';
577 return tomoyo_update_aggregator_entry(data, cp, is_delete);
578}
579
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900580static bool tomoyo_same_alias_entry(const struct tomoyo_acl_head *a,
581 const struct tomoyo_acl_head *b)
582{
583 const struct tomoyo_alias_entry *p1 = container_of(a, typeof(*p1),
584 head);
585 const struct tomoyo_alias_entry *p2 = container_of(b, typeof(*p2),
586 head);
587 return p1->original_name == p2->original_name &&
588 p1->aliased_name == p2->aliased_name;
589}
590
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900591/**
592 * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
593 *
594 * @original_name: The original program's real name.
595 * @aliased_name: The symbolic program's symbolic link's name.
596 * @is_delete: True if it is a delete request.
597 *
598 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900599 *
600 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900601 */
602static int tomoyo_update_alias_entry(const char *original_name,
603 const char *aliased_name,
604 const bool is_delete)
605{
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900606 struct tomoyo_alias_entry e = { };
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900607 int error = is_delete ? -ENOENT : -ENOMEM;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900608
Tetsuo Handa75093152010-06-16 16:23:55 +0900609 if (!tomoyo_correct_path(original_name) ||
610 !tomoyo_correct_path(aliased_name))
Tetsuo Handa3f629632010-06-03 20:37:26 +0900611 return -EINVAL;
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900612 e.original_name = tomoyo_get_name(original_name);
613 e.aliased_name = tomoyo_get_name(aliased_name);
Tetsuo Handa3f629632010-06-03 20:37:26 +0900614 if (!e.original_name || !e.aliased_name ||
615 e.original_name->is_patterned || e.aliased_name->is_patterned)
616 goto out; /* No patterns allowed. */
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900617 error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900618 &tomoyo_policy_list[TOMOYO_ID_ALIAS],
Tetsuo Handa36f5e1f2010-06-15 09:23:26 +0900619 tomoyo_same_alias_entry);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900620 out:
Tetsuo Handa9e4b50e2010-05-06 12:40:02 +0900621 tomoyo_put_name(e.original_name);
622 tomoyo_put_name(e.aliased_name);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900623 return error;
624}
625
626/**
627 * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
628 *
629 * @head: Pointer to "struct tomoyo_io_buffer".
630 *
631 * Returns true on success, false otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900632 *
633 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900634 */
635bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
636{
637 struct list_head *pos;
638 bool done = true;
639
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900640 list_for_each_cookie(pos, head->read_var2,
641 &tomoyo_policy_list[TOMOYO_ID_ALIAS]) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900642 struct tomoyo_alias_entry *ptr;
643
Tetsuo Handa82e0f002010-06-15 09:22:42 +0900644 ptr = list_entry(pos, struct tomoyo_alias_entry, head.list);
645 if (ptr->head.is_deleted)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900646 continue;
Tetsuo Handa7d2948b2009-06-02 20:42:24 +0900647 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
648 ptr->original_name->name,
649 ptr->aliased_name->name);
650 if (!done)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900651 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900652 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900653 return done;
654}
655
656/**
657 * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
658 *
659 * @data: String to parse.
660 * @is_delete: True if it is a delete request.
661 *
662 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900663 *
664 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900665 */
666int tomoyo_write_alias_policy(char *data, const bool is_delete)
667{
668 char *cp = strchr(data, ' ');
669
670 if (!cp)
671 return -EINVAL;
672 *cp++ = '\0';
673 return tomoyo_update_alias_entry(data, cp, is_delete);
674}
675
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900676/**
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900677 * tomoyo_find_or_assign_new_domain - Create a domain.
678 *
679 * @domainname: The name of domain.
680 * @profile: Profile number to assign if the domain was newly created.
681 *
682 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900683 *
684 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900685 */
686struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
687 domainname,
688 const u8 profile)
689{
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900690 struct tomoyo_domain_info *entry;
Tetsuo Handa29282382010-05-06 00:18:15 +0900691 struct tomoyo_domain_info *domain = NULL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900692 const struct tomoyo_path_info *saved_domainname;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900693 bool found = false;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900694
Tetsuo Handa75093152010-06-16 16:23:55 +0900695 if (!tomoyo_correct_domain(domainname))
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900696 return NULL;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900697 saved_domainname = tomoyo_get_name(domainname);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900698 if (!saved_domainname)
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900699 return NULL;
Tetsuo Handa4e5d6f72010-04-28 14:17:42 +0900700 entry = kzalloc(sizeof(*entry), GFP_NOFS);
Tetsuo Handa29282382010-05-06 00:18:15 +0900701 if (mutex_lock_interruptible(&tomoyo_policy_lock))
702 goto out;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900703 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
704 if (domain->is_deleted ||
705 tomoyo_pathcmp(saved_domainname, domain->domainname))
706 continue;
707 found = true;
708 break;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900709 }
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900710 if (!found && tomoyo_memory_ok(entry)) {
711 INIT_LIST_HEAD(&entry->acl_info_list);
712 entry->domainname = saved_domainname;
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900713 saved_domainname = NULL;
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900714 entry->profile = profile;
715 list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
716 domain = entry;
717 entry = NULL;
718 found = true;
719 }
Tetsuo Handaf737d952010-01-03 21:16:32 +0900720 mutex_unlock(&tomoyo_policy_lock);
Tetsuo Handa29282382010-05-06 00:18:15 +0900721 out:
Tetsuo Handabf24fb02010-02-11 09:41:58 +0900722 tomoyo_put_name(saved_domainname);
Tetsuo Handaca0b7df2010-02-07 20:23:59 +0900723 kfree(entry);
724 return found ? domain : NULL;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900725}
726
727/**
728 * tomoyo_find_next_domain - Find a domain.
729 *
Tetsuo Handa56f8c9b2009-06-19 14:13:27 +0900730 * @bprm: Pointer to "struct linux_binprm".
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900731 *
732 * Returns 0 on success, negative value otherwise.
Tetsuo Handafdb8ebb2009-12-08 09:34:43 +0900733 *
734 * Caller holds tomoyo_read_lock().
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900735 */
Tetsuo Handa56f8c9b2009-06-19 14:13:27 +0900736int tomoyo_find_next_domain(struct linux_binprm *bprm)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900737{
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900738 struct tomoyo_request_info r;
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900739 char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900740 struct tomoyo_domain_info *old_domain = tomoyo_domain();
741 struct tomoyo_domain_info *domain = NULL;
742 const char *old_domain_name = old_domain->domainname->name;
743 const char *original_name = bprm->filename;
Tetsuo Handa57c25902010-06-03 20:38:44 +0900744 u8 mode;
745 bool is_enforce;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900746 int retval = -ENOMEM;
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900747 bool need_kfree = false;
748 struct tomoyo_path_info rn = { }; /* real name */
749 struct tomoyo_path_info sn = { }; /* symlink name */
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900750 struct tomoyo_path_info ln; /* last name */
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900751
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900752 ln.name = tomoyo_get_last_name(old_domain);
753 tomoyo_fill_path_info(&ln);
Tetsuo Handa57c25902010-06-03 20:38:44 +0900754 mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
755 is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900756 if (!tmp)
757 goto out;
758
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900759 retry:
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900760 if (need_kfree) {
761 kfree(rn.name);
762 need_kfree = false;
763 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900764 /* Get tomoyo_realpath of program. */
765 retval = -ENOENT;
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900766 rn.name = tomoyo_realpath(original_name);
767 if (!rn.name)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900768 goto out;
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900769 tomoyo_fill_path_info(&rn);
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900770 need_kfree = true;
771
772 /* Get tomoyo_realpath of symbolic link. */
773 sn.name = tomoyo_realpath_nofollow(original_name);
774 if (!sn.name)
775 goto out;
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900776 tomoyo_fill_path_info(&sn);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900777
778 /* Check 'alias' directive. */
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900779 if (tomoyo_pathcmp(&rn, &sn)) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900780 struct tomoyo_alias_entry *ptr;
781 /* Is this program allowed to be called via symbolic links? */
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900782 list_for_each_entry_rcu(ptr,
783 &tomoyo_policy_list[TOMOYO_ID_ALIAS],
784 head.list) {
Tetsuo Handa82e0f002010-06-15 09:22:42 +0900785 if (ptr->head.is_deleted ||
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900786 tomoyo_pathcmp(&rn, ptr->original_name) ||
787 tomoyo_pathcmp(&sn, ptr->aliased_name))
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900788 continue;
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900789 kfree(rn.name);
790 need_kfree = false;
791 /* This is OK because it is read only. */
792 rn = *ptr->aliased_name;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900793 break;
794 }
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900795 }
796
Tetsuo Handa10843072010-06-03 20:38:03 +0900797 /* Check 'aggregator' directive. */
798 {
799 struct tomoyo_aggregator_entry *ptr;
Tetsuo Handaa230f9e2010-06-17 16:53:24 +0900800 list_for_each_entry_rcu(ptr, &tomoyo_policy_list
801 [TOMOYO_ID_AGGREGATOR], head.list) {
Tetsuo Handa82e0f002010-06-15 09:22:42 +0900802 if (ptr->head.is_deleted ||
Tetsuo Handa10843072010-06-03 20:38:03 +0900803 !tomoyo_path_matches_pattern(&rn,
804 ptr->original_name))
805 continue;
806 if (need_kfree)
807 kfree(rn.name);
808 need_kfree = false;
809 /* This is OK because it is read only. */
810 rn = *ptr->aggregated_name;
811 break;
812 }
813 }
814
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900815 /* Check execute permission. */
Tetsuo Handa05336de2010-06-16 16:20:24 +0900816 retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn);
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900817 if (retval == TOMOYO_RETRY_REQUEST)
818 goto retry;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900819 if (retval < 0)
820 goto out;
821
Tetsuo Handa75093152010-06-16 16:23:55 +0900822 if (tomoyo_domain_initializer(old_domain->domainname, &rn, &ln)) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900823 /* Transit to the child of tomoyo_kernel_domain domain. */
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900824 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
825 TOMOYO_ROOT_NAME " " "%s", rn.name);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900826 } else if (old_domain == &tomoyo_kernel_domain &&
827 !tomoyo_policy_loaded) {
828 /*
829 * Needn't to transit from kernel domain before starting
830 * /sbin/init. But transit from kernel domain if executing
831 * initializers because they might start before /sbin/init.
832 */
833 domain = old_domain;
Tetsuo Handa75093152010-06-16 16:23:55 +0900834 } else if (tomoyo_domain_keeper(old_domain->domainname, &rn, &ln)) {
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900835 /* Keep current domain. */
836 domain = old_domain;
837 } else {
838 /* Normal domain transition. */
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900839 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
840 "%s %s", old_domain_name, rn.name);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900841 }
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900842 if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900843 goto done;
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900844 domain = tomoyo_find_domain(tmp);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900845 if (domain)
846 goto done;
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900847 if (is_enforce) {
848 int error = tomoyo_supervisor(&r, "# wants to create domain\n"
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900849 "%s\n", tmp);
Tetsuo Handa17fcfbd2010-05-17 10:11:36 +0900850 if (error == TOMOYO_RETRY_REQUEST)
851 goto retry;
852 if (error < 0)
853 goto done;
854 }
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900855 domain = tomoyo_find_or_assign_new_domain(tmp, old_domain->profile);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900856 done:
857 if (domain)
858 goto out;
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900859 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900860 if (is_enforce)
861 retval = -EPERM;
862 else
Tetsuo Handaea13ddb2010-02-03 06:43:06 +0900863 old_domain->transition_failed = true;
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900864 out:
Tetsuo Handa56f8c9b2009-06-19 14:13:27 +0900865 if (!domain)
866 domain = old_domain;
Tetsuo Handaec8e6a42010-02-11 09:43:20 +0900867 /* Update reference count on "struct tomoyo_domain_info". */
868 atomic_inc(&domain->users);
Tetsuo Handa56f8c9b2009-06-19 14:13:27 +0900869 bprm->cred->security = domain;
Tetsuo Handac8c57e82010-06-03 20:36:43 +0900870 if (need_kfree)
871 kfree(rn.name);
872 kfree(sn.name);
Tetsuo Handa8e2d39a2010-01-26 20:45:27 +0900873 kfree(tmp);
Kentaro Takeda26a2a1c2009-02-05 17:18:15 +0900874 return retval;
875}