Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/1.7.x/ccs-patch/security/ccsecurity/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6035 - (show annotations) (download) (as text)
Fri May 4 13:01:02 2012 UTC (12 months, 2 weeks ago) by kumaneko
File MIME type: text/x-csrc
File size: 63156 byte(s)
1 /*
2 * security/ccsecurity/file.c
3 *
4 * Copyright (C) 2005-2012 NTT DATA CORPORATION
5 *
6 * Version: 1.7.3+ 2012/05/05
7 *
8 * This file is applicable to both 2.4.30 and 2.6.11 and later.
9 * See README.ccs for ChangeLog.
10 *
11 */
12
13 #include "internal.h"
14 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
15 #include <linux/mount.h>
16 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
17 #include <linux/namespace.h>
18 #endif
19 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
20 #include <linux/dcache.h>
21 #include <linux/namei.h>
22 #endif
23 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 33)
24 /*
25 * ACC_MODE() in this file uses old definition because may_open() receives
26 * open flags modified by open_to_namei_flags() until 2.6.33.
27 * may_open() receives unmodified flags after 2.6.34.
28 */
29 #undef ACC_MODE
30 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
31 #endif
32
33 #if defined(RHEL_MAJOR) && RHEL_MAJOR == 6
34 /* However, RHEL6 passes unmodified flags since 2.6.32-71.14.1.el6 . */
35 #undef ACC_MODE
36 #define ACC_MODE(x) ("\004\002\006"[(x)&O_ACCMODE])
37 #endif
38
39 static const char *ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
40 [CCS_TYPE_READ_WRITE] = "read/write",
41 [CCS_TYPE_EXECUTE] = "execute",
42 [CCS_TYPE_READ] = "read",
43 [CCS_TYPE_WRITE] = "write",
44 [CCS_TYPE_UNLINK] = "unlink",
45 [CCS_TYPE_RMDIR] = "rmdir",
46 [CCS_TYPE_TRUNCATE] = "truncate",
47 [CCS_TYPE_SYMLINK] = "symlink",
48 [CCS_TYPE_REWRITE] = "rewrite",
49 [CCS_TYPE_CHROOT] = "chroot",
50 [CCS_TYPE_UMOUNT] = "unmount",
51 [CCS_TYPE_TRANSIT] = "transit",
52 };
53
54 static const char *ccs_path_number3_keyword[CCS_MAX_PATH_NUMBER3_OPERATION] = {
55 [CCS_TYPE_MKBLOCK] = "mkblock",
56 [CCS_TYPE_MKCHAR] = "mkchar",
57 };
58
59 static const char *ccs_path2_keyword[CCS_MAX_PATH2_OPERATION] = {
60 [CCS_TYPE_LINK] = "link",
61 [CCS_TYPE_RENAME] = "rename",
62 [CCS_TYPE_PIVOT_ROOT] = "pivot_root",
63 };
64
65 static const char *ccs_path_number_keyword[CCS_MAX_PATH_NUMBER_OPERATION] = {
66 [CCS_TYPE_CREATE] = "create",
67 [CCS_TYPE_MKDIR] = "mkdir",
68 [CCS_TYPE_MKFIFO] = "mkfifo",
69 [CCS_TYPE_MKSOCK] = "mksock",
70 [CCS_TYPE_IOCTL] = "ioctl",
71 [CCS_TYPE_CHMOD] = "chmod",
72 [CCS_TYPE_CHOWN] = "chown",
73 [CCS_TYPE_CHGRP] = "chgrp",
74 };
75
76 static const u8 ccs_p2mac[CCS_MAX_PATH_OPERATION] = {
77 [CCS_TYPE_READ_WRITE] = CCS_MAC_FILE_OPEN,
78 [CCS_TYPE_EXECUTE] = CCS_MAC_FILE_EXECUTE,
79 [CCS_TYPE_READ] = CCS_MAC_FILE_OPEN,
80 [CCS_TYPE_WRITE] = CCS_MAC_FILE_OPEN,
81 [CCS_TYPE_UNLINK] = CCS_MAC_FILE_UNLINK,
82 [CCS_TYPE_RMDIR] = CCS_MAC_FILE_RMDIR,
83 [CCS_TYPE_TRUNCATE] = CCS_MAC_FILE_TRUNCATE,
84 [CCS_TYPE_SYMLINK] = CCS_MAC_FILE_SYMLINK,
85 [CCS_TYPE_REWRITE] = CCS_MAC_FILE_REWRITE,
86 [CCS_TYPE_CHROOT] = CCS_MAC_FILE_CHROOT,
87 [CCS_TYPE_UMOUNT] = CCS_MAC_FILE_UMOUNT,
88 [CCS_TYPE_TRANSIT] = CCS_MAC_FILE_TRANSIT,
89 };
90
91 static const u8 ccs_pnnn2mac[CCS_MAX_PATH_NUMBER3_OPERATION] = {
92 [CCS_TYPE_MKBLOCK] = CCS_MAC_FILE_MKBLOCK,
93 [CCS_TYPE_MKCHAR] = CCS_MAC_FILE_MKCHAR,
94 };
95
96 static const u8 ccs_pp2mac[CCS_MAX_PATH2_OPERATION] = {
97 [CCS_TYPE_LINK] = CCS_MAC_FILE_LINK,
98 [CCS_TYPE_RENAME] = CCS_MAC_FILE_RENAME,
99 [CCS_TYPE_PIVOT_ROOT] = CCS_MAC_FILE_PIVOT_ROOT,
100 };
101
102 static const u8 ccs_pn2mac[CCS_MAX_PATH_NUMBER_OPERATION] = {
103 [CCS_TYPE_CREATE] = CCS_MAC_FILE_CREATE,
104 [CCS_TYPE_MKDIR] = CCS_MAC_FILE_MKDIR,
105 [CCS_TYPE_MKFIFO] = CCS_MAC_FILE_MKFIFO,
106 [CCS_TYPE_MKSOCK] = CCS_MAC_FILE_MKSOCK,
107 [CCS_TYPE_IOCTL] = CCS_MAC_FILE_IOCTL,
108 [CCS_TYPE_CHMOD] = CCS_MAC_FILE_CHMOD,
109 [CCS_TYPE_CHOWN] = CCS_MAC_FILE_CHOWN,
110 [CCS_TYPE_CHGRP] = CCS_MAC_FILE_CHGRP,
111 };
112
113 /* Main functions. */
114
115 void ccs_put_name_union(struct ccs_name_union *ptr)
116 {
117 if (!ptr)
118 return;
119 if (ptr->is_group)
120 ccs_put_path_group(ptr->group);
121 else
122 ccs_put_name(ptr->filename);
123 }
124
125 void ccs_put_number_union(struct ccs_number_union *ptr)
126 {
127 if (ptr && ptr->is_group)
128 ccs_put_number_group(ptr->group);
129 }
130
131 bool ccs_compare_number_union(const unsigned long value,
132 const struct ccs_number_union *ptr)
133 {
134 if (ptr->is_group)
135 return ccs_number_matches_group(value, value, ptr->group);
136 return value >= ptr->values[0] && value <= ptr->values[1];
137 }
138
139 bool ccs_compare_name_union(const struct ccs_path_info *name,
140 const struct ccs_name_union *ptr)
141 {
142 if (ptr->is_group)
143 return ccs_path_matches_group(name, ptr->group, 1);
144 return ccs_path_matches_pattern(name, ptr->filename);
145 }
146
147 static bool ccs_compare_name_union_pattern(const struct ccs_path_info *name,
148 const struct ccs_name_union *ptr,
149 const bool may_use_pattern)
150 {
151 if (ptr->is_group)
152 return ccs_path_matches_group(name, ptr->group,
153 may_use_pattern);
154 if (may_use_pattern || !ptr->filename->is_patterned)
155 return ccs_path_matches_pattern(name, ptr->filename);
156 return false;
157 }
158
159 /**
160 * ccs_path2keyword - Get the name of path operations.
161 *
162 * @operation: Type of operation.
163 *
164 * Returns the name of path operation.
165 */
166 const char *ccs_path2keyword(const u8 operation)
167 {
168 return (operation < CCS_MAX_PATH_OPERATION)
169 ? ccs_path_keyword[operation] : NULL;
170 }
171
172 /**
173 * ccs_path_number32keyword - Get the name of path/number/number/number operations.
174 *
175 * @operation: Type of operation.
176 *
177 * Returns the name of path/number/number/number operation.
178 */
179 const char *ccs_path_number32keyword(const u8 operation)
180 {
181 return (operation < CCS_MAX_PATH_NUMBER3_OPERATION)
182 ? ccs_path_number3_keyword[operation] : NULL;
183 }
184
185 /**
186 * ccs_path22keyword - Get the name of path/path operations.
187 *
188 * @operation: Type of operation.
189 *
190 * Returns the name of path/path operation.
191 */
192 const char *ccs_path22keyword(const u8 operation)
193 {
194 return (operation < CCS_MAX_PATH2_OPERATION)
195 ? ccs_path2_keyword[operation] : NULL;
196 }
197
198 /**
199 * ccs_path_number2keyword - Get the name of path/number operations.
200 *
201 * @operation: Type of operation.
202 *
203 * Returns the name of path/number operation.
204 */
205 const char *ccs_path_number2keyword(const u8 operation)
206 {
207 return (operation < CCS_MAX_PATH_NUMBER_OPERATION)
208 ? ccs_path_number_keyword[operation] : NULL;
209 }
210
211 static void ccs_add_slash(struct ccs_path_info *buf)
212 {
213 if (buf->is_dir)
214 return;
215 /* This is OK because ccs_encode() reserves space for appending "/". */
216 strcat((char *) buf->name, "/");
217 ccs_fill_path_info(buf);
218 }
219
220 /**
221 * ccs_strendswith - Check whether the token ends with the given token.
222 *
223 * @name: The token to check.
224 * @tail: The token to find.
225 *
226 * Returns true if @name ends with @tail, false otherwise.
227 */
228 static bool ccs_strendswith(const char *name, const char *tail)
229 {
230 int len;
231 if (!name || !tail)
232 return false;
233 len = strlen(name) - strlen(tail);
234 return len >= 0 && !strcmp(name + len, tail);
235 }
236
237 /**
238 * ccs_get_realpath - Get realpath.
239 *
240 * @buf: Pointer to "struct ccs_path_info".
241 * @dentry: Pointer to "struct dentry".
242 * @mnt: Pointer to "struct vfsmount".
243 *
244 * Returns true success, false otherwise.
245 */
246 static bool ccs_get_realpath(struct ccs_path_info *buf, struct dentry *dentry,
247 struct vfsmount *mnt)
248 {
249 struct path path = { mnt, dentry };
250 buf->name = ccs_realpath_from_path(&path);
251 if (buf->name) {
252 ccs_fill_path_info(buf);
253 return true;
254 }
255 return false;
256 }
257
258 static int ccs_update_path_acl(const u8 type, const char *filename,
259 struct ccs_domain_info * const domain,
260 struct ccs_condition *condition,
261 const bool is_delete);
262
263 /**
264 * ccs_audit_path_log - Audit path request log.
265 *
266 * @r: Pointer to "struct ccs_request_info".
267 * @operation: The name of operation.
268 * @filename: Pathname.
269 * @is_granted: True if this is a granted log.
270 *
271 * Returns 0 on success, negative value otherwise.
272 */
273 static int ccs_audit_path_log(struct ccs_request_info *r,
274 const char *operation, const char *filename,
275 const bool is_granted)
276 {
277 if (!is_granted)
278 ccs_warn_log(r, "%s %s", operation, filename);
279 return ccs_write_audit_log(is_granted, r, "allow_%s %s\n", operation,
280 filename);
281 }
282
283 /**
284 * ccs_audit_path2_log - Audit path/path request log.
285 *
286 * @r: Pointer to "struct ccs_request_info".
287 * @operation: The name of operation.
288 * @filename1: First pathname.
289 * @filename2: Second pathname.
290 * @is_granted: True if this is a granted log.
291 *
292 * Returns 0 on success, negative value otherwise.
293 */
294 static int ccs_audit_path2_log(struct ccs_request_info *r,
295 const char *operation, const char *filename1,
296 const char *filename2, const bool is_granted)
297 {
298 if (!is_granted)
299 ccs_warn_log(r, "%s %s %s", operation, filename1, filename2);
300 return ccs_write_audit_log(is_granted, r, "allow_%s %s %s\n",
301 operation, filename1, filename2);
302 }
303
304 /**
305 * ccs_audit_path_number3_log - Audit path/number/number/number request log.
306 *
307 * @r: Pointer to "struct ccs_request_info".
308 * @operation: The name of operation.
309 * @filename: First pathname.
310 * @mode: Create mode.
311 * @major: Device major number.
312 * @minor: Device minor number.
313 * @is_granted: True if this is a granted log.
314 *
315 * Returns 0 on success, negative value otherwise.
316 */
317 static int ccs_audit_path_number3_log(struct ccs_request_info *r,
318 const char *operation,
319 const char *filename,
320 const unsigned int mode,
321 const unsigned int major,
322 const unsigned int minor,
323 const bool is_granted)
324 {
325 if (!is_granted)
326 ccs_warn_log(r, "%s %s 0%o %u %u", operation, filename, mode,
327 major, minor);
328 return ccs_write_audit_log(is_granted, r, "allow_%s %s 0%o %u %u\n",
329 operation, filename, mode, major, minor);
330 }
331
332 /**
333 * ccs_audit_path_number_log - Audit path/number request log.
334 *
335 * @r: Pointer to "struct ccs_request_info".
336 * @operation: Type of operation.
337 * @filename: Pathname.
338 * @value: Value.
339 * @is_granted: True if this is a granted log.
340 *
341 * Returns 0 on success, negative value otherwise.
342 */
343 static int ccs_audit_path_number_log(struct ccs_request_info *r,
344 const char *operation,
345 const char *filename, const char *value,
346 const bool is_granted)
347 {
348 if (!is_granted)
349 ccs_warn_log(r, "%s %s %s", operation, filename, value);
350 return ccs_write_audit_log(is_granted, r, "allow_%s %s %s\n",
351 operation, filename, value);
352 }
353
354 /* The list for "struct ccs_globally_readable_file_entry". */
355 LIST_HEAD(ccs_globally_readable_list);
356
357 /**
358 * ccs_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
359 *
360 * @filename: The filename to check.
361 *
362 * Returns true if any domain can open @filename for reading, false otherwise.
363 *
364 * Caller holds ccs_read_lock().
365 */
366 static bool ccs_is_globally_readable_file(const struct ccs_path_info *filename)
367 {
368 struct ccs_globally_readable_file_entry *ptr;
369 bool found = false;
370 list_for_each_entry_rcu(ptr, &ccs_globally_readable_list, list) {
371 if (ptr->is_deleted ||
372 !ccs_path_matches_pattern(filename, ptr->filename))
373 continue;
374 found = true;
375 break;
376 }
377 return found;
378 }
379
380 /**
381 * ccs_write_globally_readable_policy - Write "struct ccs_globally_readable_file_entry" list.
382 *
383 * @data: String to parse.
384 * @is_delete: True if it is a delete request.
385 *
386 * Returns 0 on success, negative value otherwise.
387 */
388 int ccs_write_globally_readable_policy(char *data, const bool is_delete)
389 {
390 struct ccs_globally_readable_file_entry *ptr;
391 struct ccs_globally_readable_file_entry e = { };
392 int error = is_delete ? -ENOENT : -ENOMEM;
393 if (!ccs_is_correct_path(data, 1, 0, -1))
394 return -EINVAL;
395 e.filename = ccs_get_name(data);
396 if (!e.filename)
397 return -ENOMEM;
398 if (mutex_lock_interruptible(&ccs_policy_lock))
399 goto out;
400 list_for_each_entry_rcu(ptr, &ccs_globally_readable_list, list) {
401 if (ptr->filename != e.filename)
402 continue;
403 ptr->is_deleted = is_delete;
404 error = 0;
405 break;
406 }
407 if (!is_delete && error) {
408 struct ccs_globally_readable_file_entry *entry =
409 ccs_commit_ok(&e, sizeof(e));
410 if (entry) {
411 list_add_tail_rcu(&entry->list,
412 &ccs_globally_readable_list);
413 error = 0;
414 }
415 }
416 mutex_unlock(&ccs_policy_lock);
417 out:
418 ccs_put_name(e.filename);
419 return error;
420 }
421
422 /**
423 * ccs_read_globally_readable_policy - Read "struct ccs_globally_readable_file_entry" list.
424 *
425 * @head: Pointer to "struct ccs_io_buffer".
426 *
427 * Returns true on success, false otherwise.
428 *
429 * Caller holds ccs_read_lock().
430 */
431 bool ccs_read_globally_readable_policy(struct ccs_io_buffer *head)
432 {
433 struct list_head *pos;
434 bool done = true;
435 list_for_each_cookie(pos, head->read_var2,
436 &ccs_globally_readable_list) {
437 struct ccs_globally_readable_file_entry *ptr;
438 ptr = list_entry(pos, struct ccs_globally_readable_file_entry,
439 list);
440 if (ptr->is_deleted)
441 continue;
442 done = ccs_io_printf(head, CCS_KEYWORD_ALLOW_READ "%s\n",
443 ptr->filename->name);
444 if (!done)
445 break;
446 }
447 return done;
448 }
449
450 /* The list for "struct ccs_pattern_entry". */
451 LIST_HEAD(ccs_pattern_list);
452
453 /**
454 * ccs_file_pattern - Get patterned pathname.
455 *
456 * @filename: Pointer to "struct ccs_path_info".
457 *
458 * Returns pointer to patterned pathname.
459 *
460 * Caller holds ccs_read_lock().
461 */
462 const char *ccs_file_pattern(const struct ccs_path_info *filename)
463 {
464 struct ccs_pattern_entry *ptr;
465 const struct ccs_path_info *pattern = NULL;
466 list_for_each_entry_rcu(ptr, &ccs_pattern_list, list) {
467 if (ptr->is_deleted)
468 continue;
469 if (!ccs_path_matches_pattern(filename, ptr->pattern))
470 continue;
471 pattern = ptr->pattern;
472 if (ccs_strendswith(pattern->name, "/\\*")) {
473 /* Do nothing. Try to find the better match. */
474 } else {
475 /* This would be the better match. Use this. */
476 break;
477 }
478 }
479 return pattern ? pattern->name : filename->name;
480 }
481
482 /**
483 * ccs_write_pattern_policy - Write "struct ccs_pattern_entry" list.
484 *
485 * @data: String to parse.
486 * @is_delete: True if it is a delete request.
487 *
488 * Returns 0 on success, negative value otherwise.
489 */
490 int ccs_write_pattern_policy(char *data, const bool is_delete)
491 {
492 struct ccs_pattern_entry *ptr;
493 struct ccs_pattern_entry e = { };
494 int error = is_delete ? -ENOENT : -ENOMEM;
495 if (!ccs_is_correct_path(data, 0, 1, 0))
496 return -EINVAL;
497 e.pattern = ccs_get_name(data);
498 if (!e.pattern)
499 return error;
500 if (mutex_lock_interruptible(&ccs_policy_lock))
501 goto out;
502 list_for_each_entry_rcu(ptr, &ccs_pattern_list, list) {
503 if (e.pattern != ptr->pattern)
504 continue;
505 ptr->is_deleted = is_delete;
506 error = 0;
507 break;
508 }
509 if (!is_delete && error) {
510 struct ccs_pattern_entry *entry = ccs_commit_ok(&e, sizeof(e));
511 if (entry) {
512 list_add_tail_rcu(&entry->list, &ccs_pattern_list);
513 error = 0;
514 }
515 }
516 mutex_unlock(&ccs_policy_lock);
517 out:
518 ccs_put_name(e.pattern);
519 return error;
520 }
521
522 /**
523 * ccs_read_file_pattern - Read "struct ccs_pattern_entry" list.
524 *
525 * @head: Pointer to "struct ccs_io_buffer".
526 *
527 * Returns true on success, false otherwise.
528 *
529 * Caller holds ccs_read_lock().
530 */
531 bool ccs_read_file_pattern(struct ccs_io_buffer *head)
532 {
533 struct list_head *pos;
534 bool done = true;
535 list_for_each_cookie(pos, head->read_var2, &ccs_pattern_list) {
536 struct ccs_pattern_entry *ptr;
537 ptr = list_entry(pos, struct ccs_pattern_entry, list);
538 if (ptr->is_deleted)
539 continue;
540 done = ccs_io_printf(head, CCS_KEYWORD_FILE_PATTERN "%s\n",
541 ptr->pattern->name);
542 if (!done)
543 break;
544 }
545 return done;
546 }
547
548 /* The list for "struct ccs_no_rewrite_entry". */
549 LIST_HEAD(ccs_no_rewrite_list);
550
551 /**
552 * ccs_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
553 *
554 * @filename: Filename to check.
555 *
556 * Returns true if @filename is specified by "deny_rewrite" directive,
557 * false otherwise.
558 *
559 * Caller holds ccs_read_lock().
560 */
561 static bool ccs_is_no_rewrite_file(const struct ccs_path_info *filename)
562 {
563 struct ccs_no_rewrite_entry *ptr;
564 bool matched = false;
565 list_for_each_entry_rcu(ptr, &ccs_no_rewrite_list, list) {
566 if (ptr->is_deleted)
567 continue;
568 if (!ccs_path_matches_pattern(filename, ptr->pattern))
569 continue;
570 matched = true;
571 break;
572 }
573 return matched;
574 }
575
576 /**
577 * ccs_write_no_rewrite_policy - Write "struct ccs_no_rewrite_entry" list.
578 *
579 * @data: String to parse.
580 * @is_delete: True if it is a delete request.
581 *
582 * Returns 0 on success, negative value otherwise.
583 */
584 int ccs_write_no_rewrite_policy(char *data, const bool is_delete)
585 {
586 struct ccs_no_rewrite_entry *ptr;
587 struct ccs_no_rewrite_entry e = { };
588 int error = is_delete ? -ENOENT : -ENOMEM;
589 if (!ccs_is_correct_path(data, 0, 0, 0))
590 return -EINVAL;
591 e.pattern = ccs_get_name(data);
592 if (!e.pattern)
593 return error;
594 if (mutex_lock_interruptible(&ccs_policy_lock))
595 goto out;
596 list_for_each_entry_rcu(ptr, &ccs_no_rewrite_list, list) {
597 if (ptr->pattern != e.pattern)
598 continue;
599 ptr->is_deleted = is_delete;
600 error = 0;
601 break;
602 }
603 if (!is_delete && error) {
604 struct ccs_no_rewrite_entry *entry =
605 ccs_commit_ok(&e, sizeof(e));
606 if (entry) {
607 list_add_tail_rcu(&entry->list, &ccs_no_rewrite_list);
608 error = 0;
609 }
610 }
611 mutex_unlock(&ccs_policy_lock);
612 out:
613 ccs_put_name(e.pattern);
614 return error;
615 }
616
617 /**
618 * ccs_read_no_rewrite_policy - Read "struct ccs_no_rewrite_entry" list.
619 *
620 * @head: Pointer to "struct ccs_io_buffer".
621 *
622 * Returns true on success, false otherwise.
623 *
624 * Caller holds ccs_read_lock().
625 */
626 bool ccs_read_no_rewrite_policy(struct ccs_io_buffer *head)
627 {
628 struct list_head *pos;
629 bool done = true;
630 list_for_each_cookie(pos, head->read_var2, &ccs_no_rewrite_list) {
631 struct ccs_no_rewrite_entry *ptr;
632 ptr = list_entry(pos, struct ccs_no_rewrite_entry, list);
633 if (ptr->is_deleted)
634 continue;
635 done = ccs_io_printf(head, CCS_KEYWORD_DENY_REWRITE "%s\n",
636 ptr->pattern->name);
637 if (!done)
638 break;
639 }
640 return done;
641 }
642
643 /**
644 * ccs_update_file_acl - Update file's read/write/execute ACL.
645 *
646 * @perm: Permission (between 1 to 7).
647 * @filename: Filename.
648 * @domain: Pointer to "struct ccs_domain_info".
649 * @condition: Pointer to "struct ccs_condition". May be NULL.
650 * @is_delete: True if it is a delete request.
651 *
652 * Returns 0 on success, negative value otherwise.
653 *
654 * This is legacy support interface for older policy syntax.
655 * Current policy syntax uses "allow_read/write" instead of "6",
656 * "allow_read" instead of "4", "allow_write" instead of "2",
657 * "allow_execute" instead of "1".
658 */
659 static inline int ccs_update_file_acl(u8 perm, const char *filename,
660 struct ccs_domain_info * const domain,
661 struct ccs_condition *condition,
662 const bool is_delete)
663 {
664 if (perm > 7 || !perm)
665 return -EINVAL;
666 if (filename[0] != '@' && ccs_strendswith(filename, "/"))
667 /*
668 * Only 'allow_mkdir' and 'allow_rmdir' are valid for
669 * directory permissions.
670 */
671 return 0;
672 if (perm & 4)
673 ccs_update_path_acl(CCS_TYPE_READ, filename, domain,
674 condition, is_delete);
675 if (perm & 2)
676 ccs_update_path_acl(CCS_TYPE_WRITE, filename,
677 domain, condition, is_delete);
678 if (perm & 1)
679 ccs_update_path_acl(CCS_TYPE_EXECUTE, filename,
680 domain, condition, is_delete);
681 return 0;
682 }
683
684 /**
685 * ccs_path_acl - Check permission for path operation.
686 *
687 * @r: Pointer to "struct ccs_request_info".
688 * @filename: Filename to check.
689 * @perm: Permission.
690 * @may_use_pattern: True if patterned ACL is permitted.
691 *
692 * Returns 0 on success, -EPERM otherwise.
693 *
694 * Caller holds ccs_read_lock().
695 */
696 static int ccs_path_acl(struct ccs_request_info *r,
697 const struct ccs_path_info *filename,
698 const u16 perm, const bool may_use_pattern)
699 {
700 const struct ccs_domain_info * const domain = ccs_current_domain();
701 struct ccs_acl_info *ptr;
702 int error = -EPERM;
703 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
704 struct ccs_path_acl *acl;
705 if (ptr->is_deleted || ptr->type != CCS_TYPE_PATH_ACL)
706 continue;
707 acl = container_of(ptr, struct ccs_path_acl, head);
708 if (!(acl->perm & perm) || !ccs_condition(r, ptr) ||
709 !ccs_compare_name_union_pattern(filename, &acl->name,
710 may_use_pattern))
711 continue;
712 r->cond = ptr->cond;
713 error = 0;
714 break;
715 }
716 return error;
717 }
718
719 /**
720 * ccs_path_number3_acl - Check permission for path/number/number/number operation.
721 *
722 * @r: Pointer to "struct ccs_request_info".
723 * @filename: Filename to check.
724 * @perm: Permission.
725 * @mode: Create mode.
726 * @major: Device major number.
727 * @minor: Device minor number.
728 *
729 * Returns 0 on success, -EPERM otherwise.
730 *
731 * Caller holds ccs_read_lock().
732 */
733 static int ccs_path_number3_acl(struct ccs_request_info *r,
734 const struct ccs_path_info *filename,
735 const u16 perm, const unsigned int mode,
736 const unsigned int major,
737 const unsigned int minor)
738 {
739 const struct ccs_domain_info * const domain = ccs_current_domain();
740 struct ccs_acl_info *ptr;
741 int error = -EPERM;
742 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
743 struct ccs_path_number3_acl *acl;
744 if (ptr->is_deleted || ptr->type != CCS_TYPE_PATH_NUMBER3_ACL)
745 continue;
746 acl = container_of(ptr, struct ccs_path_number3_acl, head);
747 if (!ccs_compare_number_union(mode, &acl->mode))
748 continue;
749 if (!ccs_compare_number_union(major, &acl->major))
750 continue;
751 if (!ccs_compare_number_union(minor, &acl->minor))
752 continue;
753 if (!(acl->perm & perm) || !ccs_condition(r, ptr))
754 continue;
755 if (!ccs_compare_name_union(filename, &acl->name))
756 continue;
757 r->cond = ptr->cond;
758 error = 0;
759 break;
760 }
761 return error;
762 }
763
764 /**
765 * ccs_file_perm - Check permission for opening files.
766 *
767 * @r: Pointer to "struct ccs_request_info".
768 * @filename: Filename to check.
769 * @mode: Mode ("read" or "write" or "read/write" or "execute").
770 *
771 * Returns 0 on success, 1 on retry, negative value otherwise.
772 *
773 * Caller holds ccs_read_lock().
774 */
775 static int ccs_file_perm(struct ccs_request_info *r,
776 const struct ccs_path_info *filename, const u8 mode)
777 {
778 const char *msg = "<unknown>";
779 int error = 0;
780 u16 perm = 0;
781 const struct ccs_domain_info * const domain = ccs_current_domain();
782 if (!filename)
783 return 0;
784 if (mode == 6) {
785 msg = ccs_path2keyword(CCS_TYPE_READ_WRITE);
786 perm = 1 << CCS_TYPE_READ_WRITE;
787 } else if (mode == 4) {
788 msg = ccs_path2keyword(CCS_TYPE_READ);
789 perm = 1 << CCS_TYPE_READ;
790 } else if (mode == 2) {
791 msg = ccs_path2keyword(CCS_TYPE_WRITE);
792 perm = 1 << CCS_TYPE_WRITE;
793 } else if (mode == 1) {
794 msg = ccs_path2keyword(CCS_TYPE_EXECUTE);
795 perm = 1 << CCS_TYPE_EXECUTE;
796 } else
797 BUG();
798 do {
799 error = ccs_path_acl(r, filename, perm, mode != 1);
800 if (error && mode == 4 && !domain->ignore_global_allow_read
801 && ccs_is_globally_readable_file(filename))
802 error = 0;
803 ccs_audit_path_log(r, msg, filename->name, !error);
804 if (!error)
805 break;
806 error = ccs_supervisor(r, "allow_%s %s\n", msg,
807 mode == 1 ? filename->name :
808 ccs_file_pattern(filename));
809 /*
810 * Do not retry for execute request, for aggregator may have
811 * changed.
812 */
813 } while (error == CCS_RETRY_REQUEST && !r->ee);
814 if (r->mode != CCS_CONFIG_ENFORCING)
815 error = 0;
816 return error;
817 }
818
819 /**
820 * ccs_update_execute_handler - Update "struct ccs_execute_handler_record" list.
821 *
822 * @type: Type of execute handler.
823 * @filename: Pathname to the execute handler.
824 * @domain: Pointer to "struct ccs_domain_info".
825 * @is_delete: True if it is a delete request.
826 *
827 * Returns 0 on success, negative value otherwise.
828 */
829 static inline int ccs_update_execute_handler(const u8 type,
830 const char *filename,
831 struct ccs_domain_info * const
832 domain, const bool is_delete)
833 {
834 struct ccs_acl_info *ptr;
835 struct ccs_execute_handler_record e = { .head.type = type };
836 int error = is_delete ? -ENOENT : -ENOMEM;
837 if (!domain)
838 return -EINVAL;
839 if (!ccs_is_correct_path(filename, 1, -1, -1))
840 return -EINVAL;
841 e.handler = ccs_get_name(filename);
842 if (!e.handler)
843 return -ENOMEM;
844 if (mutex_lock_interruptible(&ccs_policy_lock))
845 goto out;
846 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
847 struct ccs_execute_handler_record *acl;
848 if (ptr->type != type)
849 continue;
850 /* Condition not supported. */
851 acl = container_of(ptr, struct ccs_execute_handler_record,
852 head);
853 if (acl->handler != e.handler)
854 continue;
855 if (!is_delete) {
856 /* Only one entry can exist in a domain. */
857 struct ccs_acl_info *ptr2;
858 list_for_each_entry_rcu(ptr2, &domain->acl_info_list,
859 list) {
860 if (ptr2->type == type)
861 ptr2->is_deleted = true;
862 }
863 }
864 ptr->is_deleted = is_delete;
865 error = 0;
866 break;
867 }
868 if (!is_delete && error) {
869 struct ccs_execute_handler_record *entry =
870 ccs_commit_ok(&e, sizeof(e));
871 if (entry) {
872 /* Only one entry can exist in a domain. */
873 list_for_each_entry_rcu(ptr, &domain->acl_info_list,
874 list) {
875 if (ptr->type == type)
876 ptr->is_deleted = true;
877 }
878 ccs_add_domain_acl(domain, &entry->head);
879 error = 0;
880 }
881 }
882 mutex_unlock(&ccs_policy_lock);
883 out:
884 ccs_put_name(e.handler);
885 return error;
886 }
887
888 /**
889 * ccs_update_path_acl - Update "struct ccs_path_acl" list.
890 *
891 * @type: Type of operation.
892 * @filename: Filename.
893 * @domain: Pointer to "struct ccs_domain_info".
894 * @condition: Pointer to "struct ccs_condition". May be NULL.
895 * @is_delete: True if it is a delete request.
896 *
897 * Returns 0 on success, negative value otherwise.
898 */
899 static int ccs_update_path_acl(const u8 type, const char *filename,
900 struct ccs_domain_info * const domain,
901 struct ccs_condition *condition,
902 const bool is_delete)
903 {
904 static const u16 ccs_rw_mask =
905 (1 << CCS_TYPE_READ) | (1 << CCS_TYPE_WRITE);
906 const u16 perm = 1 << type;
907 struct ccs_acl_info *ptr;
908 struct ccs_path_acl e = {
909 .head.type = CCS_TYPE_PATH_ACL,
910 .head.cond = condition,
911 .perm = perm
912 };
913 int error = is_delete ? -ENOENT : -ENOMEM;
914 if (type == CCS_TYPE_READ_WRITE)
915 e.perm |= ccs_rw_mask;
916 if (!ccs_parse_name_union(filename, &e.name))
917 return -EINVAL;
918 if (mutex_lock_interruptible(&ccs_policy_lock))
919 goto out;
920 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
921 struct ccs_path_acl *acl =
922 container_of(ptr, struct ccs_path_acl, head);
923 if (!ccs_is_same_path_acl(acl, &e))
924 continue;
925 if (is_delete) {
926 acl->perm &= ~perm;
927 if ((acl->perm & ccs_rw_mask) != ccs_rw_mask)
928 acl->perm &= ~(1 << CCS_TYPE_READ_WRITE);
929 else if (!(acl->perm & (1 << CCS_TYPE_READ_WRITE)))
930 acl->perm &= ~ccs_rw_mask;
931 if (!acl->perm)
932 ptr->is_deleted = true;
933 } else {
934 if (ptr->is_deleted)
935 acl->perm = 0;
936 acl->perm |= perm;
937 if ((acl->perm & ccs_rw_mask) == ccs_rw_mask)
938 acl->perm |= 1 << CCS_TYPE_READ_WRITE;
939 else if (acl->perm & (1 << CCS_TYPE_READ_WRITE))
940 acl->perm |= ccs_rw_mask;
941 ptr->is_deleted = false;
942 }
943 error = 0;
944 break;
945 }
946 if (!is_delete && error) {
947 struct ccs_path_acl *entry = ccs_commit_ok(&e, sizeof(e));
948 if (entry) {
949 ccs_add_domain_acl(domain, &entry->head);
950 error = 0;
951 }
952 }
953 mutex_unlock(&ccs_policy_lock);
954 out:
955 ccs_put_name_union(&e.name);
956 return error;
957 }
958
959 /**
960 * ccs_update_path_number3_acl - Update "struct ccs_path_number3_acl" list.
961 *
962 * @type: Type of operation.
963 * @filename: Filename.
964 * @mode: Create mode.
965 * @major: Device major number.
966 * @minor: Device minor number.
967 * @domain: Pointer to "struct ccs_domain_info".
968 * @condition: Pointer to "struct ccs_condition". May be NULL.
969 * @is_delete: True if it is a delete request.
970 *
971 * Returns 0 on success, negative value otherwise.
972 */
973 static inline int ccs_update_path_number3_acl(const u8 type,
974 const char *filename, char *mode,
975 char *major, char *minor,
976 struct ccs_domain_info * const
977 domain,
978 struct ccs_condition *condition,
979 const bool is_delete)
980 {
981 const u8 perm = 1 << type;
982 struct ccs_acl_info *ptr;
983 struct ccs_path_number3_acl e = {
984 .head.type = CCS_TYPE_PATH_NUMBER3_ACL,
985 .head.cond = condition,
986 .perm = perm
987 };
988 int error = is_delete ? -ENOENT : -ENOMEM;
989 if (!ccs_parse_name_union(filename, &e.name) ||
990 !ccs_parse_number_union(mode, &e.mode) ||
991 !ccs_parse_number_union(major, &e.major) ||
992 !ccs_parse_number_union(minor, &e.minor))
993 goto out;
994 if (mutex_lock_interruptible(&ccs_policy_lock))
995 goto out;
996 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
997 struct ccs_path_number3_acl *acl =
998 container_of(ptr, struct ccs_path_number3_acl, head);
999 if (!ccs_is_same_path_number3_acl(acl, &e))
1000 continue;
1001 if (is_delete) {
1002 acl->perm &= ~perm;
1003 if (!acl->perm)
1004 ptr->is_deleted = true;
1005 } else {
1006 if (ptr->is_deleted)
1007 acl->perm = 0;
1008 acl->perm |= perm;
1009 ptr->is_deleted = false;
1010 }
1011 error = 0;
1012 break;
1013 }
1014 if (!is_delete && error) {
1015 struct ccs_path_number3_acl *entry =
1016 ccs_commit_ok(&e, sizeof(e));
1017 if (entry) {
1018 ccs_add_domain_acl(domain, &entry->head);
1019 error = 0;
1020 }
1021 }
1022 mutex_unlock(&ccs_policy_lock);
1023 out:
1024 ccs_put_name_union(&e.name);
1025 ccs_put_number_union(&e.mode);
1026 ccs_put_number_union(&e.major);
1027 ccs_put_number_union(&e.minor);
1028 return error;
1029 }
1030
1031 /**
1032 * ccs_update_path2_acl - Update "struct ccs_path2_acl" list.
1033 *
1034 * @type: Type of operation.
1035 * @filename1: First filename.
1036 * @filename2: Second filename.
1037 * @domain: Pointer to "struct ccs_domain_info".
1038 * @condition: Pointer to "struct ccs_condition". May be NULL.
1039 * @is_delete: True if it is a delete request.
1040 *
1041 * Returns 0 on success, negative value otherwise.
1042 */
1043 static inline int ccs_update_path2_acl(const u8 type, const char *filename1,
1044 const char *filename2,
1045 struct ccs_domain_info * const domain,
1046 struct ccs_condition *condition,
1047 const bool is_delete)
1048 {
1049 const u8 perm = 1 << type;
1050 struct ccs_acl_info *ptr;
1051 struct ccs_path2_acl e = {
1052 .head.type = CCS_TYPE_PATH2_ACL,
1053 .head.cond = condition,
1054 .perm = perm
1055 };
1056 int error = is_delete ? -ENOENT : -ENOMEM;
1057 if (!ccs_parse_name_union(filename1, &e.name1) ||
1058 !ccs_parse_name_union(filename2, &e.name2))
1059 goto out;
1060 if (mutex_lock_interruptible(&ccs_policy_lock))
1061 goto out;
1062 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1063 struct ccs_path2_acl *acl =
1064 container_of(ptr, struct ccs_path2_acl, head);
1065 if (!ccs_is_same_path2_acl(acl, &e))
1066 continue;
1067 if (is_delete) {
1068 acl->perm &= ~perm;
1069 if (!acl->perm)
1070 ptr->is_deleted = true;
1071 } else {
1072 if (ptr->is_deleted)
1073 acl->perm = 0;
1074 acl->perm |= perm;
1075 ptr->is_deleted = false;
1076 }
1077 error = 0;
1078 break;
1079 }
1080 if (!is_delete && error) {
1081 struct ccs_path2_acl *entry = ccs_commit_ok(&e, sizeof(e));
1082 if (entry) {
1083 ccs_add_domain_acl(domain, &entry->head);
1084 error = 0;
1085 }
1086 }
1087 mutex_unlock(&ccs_policy_lock);
1088 out:
1089 ccs_put_name_union(&e.name1);
1090 ccs_put_name_union(&e.name2);
1091 return error;
1092 }
1093
1094 /**
1095 * ccs_path2_acl - Check permission for path/path operation.
1096 *
1097 * @r: Pointer to "struct ccs_request_info".
1098 * @type: Type of operation.
1099 * @filename1: First filename to check.
1100 * @filename2: Second filename to check.
1101 *
1102 * Returns 0 on success, -EPERM otherwise.
1103 *
1104 * Caller holds ccs_read_lock().
1105 */
1106 static int ccs_path2_acl(struct ccs_request_info *r, const u8 type,
1107 const struct ccs_path_info *filename1,
1108 const struct ccs_path_info *filename2)
1109 {
1110 const struct ccs_domain_info * const domain = ccs_current_domain();
1111 struct ccs_acl_info *ptr;
1112 const u8 perm = 1 << type;
1113 int error = -EPERM;
1114 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1115 struct ccs_path2_acl *acl;
1116 if (ptr->is_deleted || ptr->type != CCS_TYPE_PATH2_ACL)
1117 continue;
1118 acl = container_of(ptr, struct ccs_path2_acl, head);
1119 if (!(acl->perm & perm) || !ccs_condition(r, ptr) ||
1120 !ccs_compare_name_union(filename1, &acl->name1) ||
1121 !ccs_compare_name_union(filename2, &acl->name2))
1122 continue;
1123 r->cond = ptr->cond;
1124 error = 0;
1125 break;
1126 }
1127 return error;
1128 }
1129
1130 /**
1131 * ccs_path_permission - Check permission for path operation.
1132 *
1133 * @r: Pointer to "struct ccs_request_info".
1134 * @operation: Type of operation.
1135 * @filename: Filename to check.
1136 *
1137 * Returns 0 on success, negative value otherwise.
1138 *
1139 * Caller holds ccs_read_lock().
1140 */
1141 int ccs_path_permission(struct ccs_request_info *r, u8 operation,
1142 const struct ccs_path_info *filename)
1143 {
1144 const char *msg;
1145 int error;
1146 repeat:
1147 r->type = ccs_p2mac[operation];
1148 r->mode = ccs_get_mode(r->profile, r->type);
1149 if (r->mode == CCS_CONFIG_DISABLED)
1150 return 0;
1151 do {
1152 error = ccs_path_acl(r, filename, 1 << operation,
1153 operation != CCS_TYPE_TRANSIT);
1154 msg = ccs_path2keyword(operation);
1155 ccs_audit_path_log(r, msg, filename->name, !error);
1156 if (!error)
1157 break;
1158 error = ccs_supervisor(r, "allow_%s %s\n", msg,
1159 ccs_file_pattern(filename));
1160 } while (error == CCS_RETRY_REQUEST);
1161 if (r->mode != CCS_CONFIG_ENFORCING)
1162 error = 0;
1163 /*
1164 * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
1165 * we need to check "allow_rewrite" permission if the filename is
1166 * specified by "deny_rewrite" keyword.
1167 */
1168 if (!error && operation == CCS_TYPE_TRUNCATE &&
1169 ccs_is_no_rewrite_file(filename)) {
1170 operation = CCS_TYPE_REWRITE;
1171 goto repeat;
1172 }
1173 return error;
1174 }
1175
1176 /**
1177 * ccs_path_number3_perm2 - Check permission for path/number/number/number operation.
1178 *
1179 * @r: Pointer to "struct ccs_request_info".
1180 * @operation: Type of operation.
1181 * @filename: Filename to check.
1182 * @mode: Create mode.
1183 * @dev: Device number.
1184 *
1185 * Returns 0 on success, negative value otherwise.
1186 *
1187 * Caller holds ccs_read_lock().
1188 */
1189 static int ccs_path_number3_perm2(struct ccs_request_info *r,
1190 const u8 operation,
1191 const struct ccs_path_info *filename,
1192 const unsigned int mode,
1193 const unsigned int dev)
1194 {
1195 int error;
1196 const char *msg = ccs_path_number32keyword(operation);
1197 const unsigned int major = MAJOR(dev);
1198 const unsigned int minor = MINOR(dev);
1199 if (!r->mode)
1200 return 0;
1201 do {
1202 error = ccs_path_number3_acl(r, filename, 1 << operation, mode,
1203 major, minor);
1204 ccs_audit_path_number3_log(r, msg, filename->name, mode, major,
1205 minor, !error);
1206 if (!error)
1207 break;
1208 error = ccs_supervisor(r, "allow_%s %s 0%o %u %u\n", msg,
1209 ccs_file_pattern(filename), mode,
1210 major, minor);
1211 } while (error == CCS_RETRY_REQUEST);
1212 if (r->mode != CCS_CONFIG_ENFORCING)
1213 error = 0;
1214 return error;
1215 }
1216
1217 /**
1218 * ccs_exec_perm - Check permission for "execute".
1219 *
1220 * @r: Pointer to "struct ccs_request_info".
1221 * @filename: Check permission for "execute".
1222 *
1223 * Returns 0 on success, 1 on retry, negative value otherwise.
1224 *
1225 * Caller holds ccs_read_lock().
1226 */
1227 int ccs_exec_perm(struct ccs_request_info *r,
1228 const struct ccs_path_info *filename)
1229 {
1230 if (r->mode == CCS_CONFIG_DISABLED)
1231 return 0;
1232 return ccs_file_perm(r, filename, 1);
1233 }
1234
1235 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
1236 /*
1237 * Save original flags passed to sys_open().
1238 *
1239 * TOMOYO does not check "allow_write" if open(path, O_TRUNC | O_RDONLY) was
1240 * requested because write() is not permitted. Instead, TOMOYO checks
1241 * "allow_truncate" if O_TRUNC is passed.
1242 *
1243 * TOMOYO does not check "allow_read/write" if open(path, 3) was requested
1244 * because read()/write() are not permitted. Instead, TOMOYO checks
1245 * "allow_ioctl" when ioctl() is requested.
1246 */
1247 static void __ccs_save_open_mode(int mode)
1248 {
1249 if ((mode & 3) == 3)
1250 current->ccs_flags |= CCS_OPEN_FOR_IOCTL_ONLY;
1251 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
1252 /* O_TRUNC passes MAY_WRITE to ccs_open_permission(). */
1253 else if (!(mode & 3) && (mode & O_TRUNC))
1254 current->ccs_flags |= CCS_OPEN_FOR_READ_TRUNCATE;
1255 #endif
1256 }
1257
1258 static void __ccs_clear_open_mode(void)
1259 {
1260 current->ccs_flags &= ~(CCS_OPEN_FOR_IOCTL_ONLY |
1261 CCS_OPEN_FOR_READ_TRUNCATE);
1262 }
1263 #endif
1264
1265 /**
1266 * ccs_open_permission - Check permission for "read" and "write".
1267 *
1268 * @dentry: Pointer to "struct dentry".
1269 * @mnt: Pointer to "struct vfsmount".
1270 * @flag: Flags for open().
1271 *
1272 * Returns 0 on success, negative value otherwise.
1273 */
1274 static int __ccs_open_permission(struct dentry *dentry, struct vfsmount *mnt,
1275 const int flag)
1276 {
1277 struct ccs_request_info r;
1278 struct ccs_obj_info obj = {
1279 .path1.dentry = dentry,
1280 .path1.mnt = mnt
1281 };
1282 struct task_struct * const task = current;
1283 const u32 ccs_flags = task->ccs_flags;
1284 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
1285 const u8 acc_mode = (flag & 3) == 3 ? 0 : ACC_MODE(flag);
1286 #else
1287 const u8 acc_mode = (ccs_flags & CCS_OPEN_FOR_IOCTL_ONLY) ? 0 :
1288 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 14)
1289 (ccs_flags & CCS_OPEN_FOR_READ_TRUNCATE) ? 4 :
1290 #endif
1291 ACC_MODE(flag);
1292 #endif
1293 int error = 0;
1294 struct ccs_path_info buf;
1295 int idx;
1296 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
1297 if (task->in_execve && !(ccs_flags & CCS_TASK_IS_IN_EXECVE))
1298 return 0;
1299 #endif
1300 if (!mnt || (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)))
1301 return 0;
1302 buf.name = NULL;
1303 r.mode = CCS_CONFIG_DISABLED;
1304 idx = ccs_read_lock();
1305 /*
1306 * If the filename is specified by "deny_rewrite" keyword,
1307 * we need to check "allow_rewrite" permission when the filename is not
1308 * opened for append mode or the filename is truncated at open time.
1309 */
1310 if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
1311 && ccs_init_request_info(&r, CCS_MAC_FILE_REWRITE)
1312 != CCS_CONFIG_DISABLED) {
1313 if (!ccs_get_realpath(&buf, dentry, mnt)) {
1314 error = -ENOMEM;
1315 goto out;
1316 }
1317 if (ccs_is_no_rewrite_file(&buf)) {
1318 r.obj = &obj;
1319 error = ccs_path_permission(&r, CCS_TYPE_REWRITE,
1320 &buf);
1321 }
1322 }
1323 if (!error && acc_mode &&
1324 ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
1325 != CCS_CONFIG_DISABLED) {
1326 if (!buf.name && !ccs_get_realpath(&buf, dentry, mnt)) {
1327 error = -ENOMEM;
1328 goto out;
1329 }
1330 r.obj = &obj;
1331 error = ccs_file_perm(&r, &buf, acc_mode);
1332 }
1333 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
1334 if (!error && (flag & O_TRUNC) &&
1335 ccs_init_request_info(&r, CCS_MAC_FILE_TRUNCATE)
1336 != CCS_CONFIG_DISABLED) {
1337 if (!buf.name && !ccs_get_realpath(&buf, dentry, mnt)) {
1338 error = -ENOMEM;
1339 goto out;
1340 }
1341 r.obj = &obj;
1342 error = ccs_path_permission(&r, CCS_TYPE_TRUNCATE, &buf);
1343 }
1344 #endif
1345 out:
1346 kfree(buf.name);
1347 ccs_read_unlock(idx);
1348 if (r.mode != CCS_CONFIG_ENFORCING)
1349 error = 0;
1350 return error;
1351 }
1352
1353 /**
1354 * ccs_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "chroot" and "unmount".
1355 *
1356 * @operation: Type of operation.
1357 * @dir: Pointer to "struct inode". May be NULL.
1358 * @dentry: Pointer to "struct dentry".
1359 * @mnt: Pointer to "struct vfsmount".
1360 * @target: Symlink's target if @operation is CCS_TYPE_SYMLINK.
1361 *
1362 * Returns 0 on success, negative value otherwise.
1363 */
1364 static int ccs_path_perm(const u8 operation, struct inode *dir,
1365 struct dentry *dentry, struct vfsmount *mnt,
1366 const char *target)
1367 {
1368 struct ccs_request_info r;
1369 struct ccs_obj_info obj = {
1370 .path1.dentry = dentry,
1371 .path1.mnt = mnt
1372 };
1373 int error = 0;
1374 struct ccs_path_info buf;
1375 bool is_enforce = false;
1376 struct ccs_path_info symlink_target;
1377 int idx;
1378 if (!mnt)
1379 return 0;
1380 buf.name = NULL;
1381 symlink_target.name = NULL;
1382 idx = ccs_read_lock();
1383 if (ccs_init_request_info(&r, ccs_p2mac[operation])
1384 == CCS_CONFIG_DISABLED)
1385 goto out;
1386 is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
1387 error = -ENOMEM;
1388 if (!ccs_get_realpath(&buf, dentry, mnt))
1389 goto out;
1390 r.obj = &obj;
1391 switch (operation) {
1392 case CCS_TYPE_RMDIR:
1393 case CCS_TYPE_CHROOT:
1394 ccs_add_slash(&buf);
1395 break;
1396 case CCS_TYPE_SYMLINK:
1397 symlink_target.name = ccs_encode(target);
1398 if (!symlink_target.name)
1399 goto out;
1400 ccs_fill_path_info(&symlink_target);
1401 obj.symlink_target = &symlink_target;
1402 break;
1403 }
1404 error = ccs_path_permission(&r, operation, &buf);
1405 if (operation == CCS_TYPE_SYMLINK)
1406 kfree(symlink_target.name);
1407 out:
1408 kfree(buf.name);
1409 ccs_read_unlock(idx);
1410 if (!is_enforce)
1411 error = 0;
1412 return error;
1413 }
1414
1415 /**
1416 * ccs_path_number3_perm - Check permission for "mkblock" and "mkchar".
1417 *
1418 * @operation: Type of operation. (CCS_TYPE_MKCHAR or CCS_TYPE_MKBLOCK)
1419 * @dir: Pointer to "struct inode".
1420 * @dentry: Pointer to "struct dentry".
1421 * @mnt: Pointer to "struct vfsmount".
1422 * @mode: Create mode.
1423 * @dev: Device number.
1424 *
1425 * Returns 0 on success, negative value otherwise.
1426 */
1427 static int ccs_path_number3_perm(const u8 operation, struct inode *dir,
1428 struct dentry *dentry, struct vfsmount *mnt,
1429 const unsigned int mode, unsigned int dev)
1430 {
1431 struct ccs_request_info r;
1432 struct ccs_obj_info obj = {
1433 .path1.dentry = dentry,
1434 .path1.mnt = mnt,
1435 .dev = dev
1436 };
1437 int error = 0;
1438 struct ccs_path_info buf;
1439 bool is_enforce = false;
1440 int idx;
1441 if (!mnt)
1442 return 0;
1443 buf.name = NULL;
1444 idx = ccs_read_lock();
1445 if (ccs_init_request_info(&r, ccs_pnnn2mac[operation])
1446 == CCS_CONFIG_DISABLED)
1447 goto out;
1448 is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
1449 error = -EPERM;
1450 if (!capable(CAP_MKNOD))
1451 goto out;
1452 error = -ENOMEM;
1453 if (!ccs_get_realpath(&buf, dentry, mnt))
1454 goto out;
1455 r.obj = &obj;
1456 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1457 dev = new_decode_dev(dev);
1458 #endif
1459 error = ccs_path_number3_perm2(&r, operation, &buf, mode, dev);
1460 out:
1461 kfree(buf.name);
1462 ccs_read_unlock(idx);
1463 if (!is_enforce)
1464 error = 0;
1465 return error;
1466 }
1467
1468 /**
1469 * ccs_rewrite_permission - Check permission for "rewrite".
1470 *
1471 * @filp: Pointer to "struct file".
1472 *
1473 * Returns 0 on success, negative value otherwise.
1474 */
1475 static int __ccs_rewrite_permission(struct file *filp)
1476 {
1477 struct ccs_request_info r;
1478 struct ccs_obj_info obj = {
1479 .path1.dentry = filp->f_dentry,
1480 .path1.mnt = filp->f_vfsmnt
1481 };
1482 int error = 0;
1483 bool is_enforce = false;
1484 struct ccs_path_info buf;
1485 int idx;
1486 if (!filp->f_vfsmnt)
1487 return 0;
1488 buf.name = NULL;
1489 idx = ccs_read_lock();
1490 if (ccs_init_request_info(&r, CCS_MAC_FILE_REWRITE)
1491 == CCS_CONFIG_DISABLED)
1492 goto out;
1493 is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
1494 r.obj = &obj;
1495 error = -ENOMEM;
1496 if (!ccs_get_realpath(&buf, filp->f_dentry, filp->f_vfsmnt))
1497 goto out;
1498 error = 0;
1499 if (ccs_is_no_rewrite_file(&buf))
1500 error = ccs_path_permission(&r, CCS_TYPE_REWRITE, &buf);
1501 out:
1502 kfree(buf.name);
1503 ccs_read_unlock(idx);
1504 if (!is_enforce)
1505 error = 0;
1506 return error;
1507 }
1508
1509 /**
1510 * ccs_path2_perm - Check permission for "rename", "link" and "pivot_root".
1511 *
1512 * @operation: Type of operation.
1513 * @dir1: Pointer to "struct inode". May be NULL.
1514 * @dentry1: Pointer to "struct dentry".
1515 * @mnt1: Pointer to "struct vfsmount".
1516 * @dir2: Pointer to "struct inode". May be NULL.
1517 * @dentry2: Pointer to "struct dentry".
1518 * @mnt2: Pointer to "struct vfsmount".
1519 *
1520 * Returns 0 on success, negative value otherwise.
1521 */
1522 static int ccs_path2_perm(const u8 operation, struct inode *dir1,
1523 struct dentry *dentry1, struct vfsmount *mnt1,
1524 struct inode *dir2, struct dentry *dentry2,
1525 struct vfsmount *mnt2)
1526 {
1527 struct ccs_request_info r;
1528 int error = 0;
1529 const char *msg = ccs_path22keyword(operation);
1530 struct ccs_path_info buf1;
1531 struct ccs_path_info buf2;
1532 bool is_enforce = false;
1533 struct ccs_obj_info obj = {
1534 .path1.dentry = dentry1,
1535 .path1.mnt = mnt1,
1536 .path2.dentry = dentry2,
1537 .path2.mnt = mnt2
1538 };
1539 int idx;
1540 if (!mnt1 || !mnt2)
1541 return 0;
1542 buf1.name = NULL;
1543 buf2.name = NULL;
1544 idx = ccs_read_lock();
1545 if (ccs_init_request_info(&r, ccs_pp2mac[operation])
1546 == CCS_CONFIG_DISABLED)
1547 goto out;
1548 is_enforce = (r.mode == CCS_CONFIG_ENFORCING);
1549 error = -ENOMEM;
1550 if (!ccs_get_realpath(&buf1, dentry1, mnt1) ||
1551 !ccs_get_realpath(&buf2, dentry2, mnt2))
1552 goto out;
1553 switch (operation) {
1554 case CCS_TYPE_RENAME:
1555 case CCS_TYPE_LINK:
1556 if (!dentry1->d_inode || !S_ISDIR(dentry1->d_inode->i_mode))
1557 break;
1558 /* fall through */
1559 case CCS_TYPE_PIVOT_ROOT:
1560 ccs_add_slash(&buf1);
1561 ccs_add_slash(&buf2);
1562 break;
1563 }
1564 r.obj = &obj;
1565 do {
1566 error = ccs_path2_acl(&r, operation, &buf1, &buf2);
1567 ccs_audit_path2_log(&r, msg, buf1.name, buf2.name, !error);
1568 if (!error)
1569 break;
1570 error = ccs_supervisor(&r, "allow_%s %s %s\n", msg,
1571 ccs_file_pattern(&buf1),
1572 ccs_file_pattern(&buf2));
1573 } while (error == CCS_RETRY_REQUEST);
1574 out:
1575 kfree(buf1.name);
1576 kfree(buf2.name);
1577 ccs_read_unlock(idx);
1578 if (!is_enforce)
1579 error = 0;
1580 return error;
1581 }
1582
1583 /**
1584 * ccs_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
1585 *
1586 * @type: Type of operation.
1587 * @filename: Filename.
1588 * @number: Number.
1589 * @domain: Pointer to "struct ccs_domain_info".
1590 * @condition: Pointer to "struct ccs_condition". May be NULL.
1591 * @is_delete: True if it is a delete request.
1592 *
1593 * Returns 0 on success, negative value otherwise.
1594 */
1595 static inline int ccs_update_path_number_acl(const u8 type,
1596 const char *filename,
1597 char *number,
1598 struct ccs_domain_info * const
1599 domain,
1600 struct ccs_condition *condition,
1601 const bool is_delete)
1602 {
1603 const u8 perm = 1 << type;
1604 struct ccs_acl_info *ptr;
1605 struct ccs_path_number_acl e = {
1606 .head.type = CCS_TYPE_PATH_NUMBER_ACL,
1607 .head.cond = condition,
1608 .perm = perm
1609 };
1610 int error = is_delete ? -ENOENT : -ENOMEM;
1611 if (!domain)
1612 return -EINVAL;
1613 if (!ccs_parse_name_union(filename, &e.name))
1614 return -EINVAL;
1615 if (!ccs_parse_number_union(number, &e.number))
1616 goto out;
1617 if (mutex_lock_interruptible(&ccs_policy_lock))
1618 goto out;
1619 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1620 struct ccs_path_number_acl *acl =
1621 container_of(ptr, struct ccs_path_number_acl, head);
1622 if (!ccs_is_same_path_number_acl(acl, &e))
1623 continue;
1624 if (is_delete) {
1625 acl->perm &= ~perm;
1626 if (!acl->perm)
1627 ptr->is_deleted = true;
1628 } else {
1629 if (ptr->is_deleted)
1630 acl->perm = 0;
1631 acl->perm |= perm;
1632 ptr->is_deleted = false;
1633 }
1634 error = 0;
1635 break;
1636 }
1637 if (!is_delete && error) {
1638 struct ccs_path_number_acl *entry =
1639 ccs_commit_ok(&e, sizeof(e));
1640 if (entry) {
1641 ccs_add_domain_acl(domain, &entry->head);
1642 error = 0;
1643 }
1644 }
1645 mutex_unlock(&ccs_policy_lock);
1646 out:
1647 ccs_put_name_union(&e.name);
1648 ccs_put_number_union(&e.number);
1649 return error;
1650 }
1651
1652 /**
1653 * ccs_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation.
1654 *
1655 * @r: Pointer to "struct ccs_request_info".
1656 * @type: Operation.
1657 * @filename: Filename to check.
1658 * @number: Number.
1659 *
1660 * Returns 0 on success, -EPERM otherwise.
1661 *
1662 * Caller holds ccs_read_lock().
1663 */
1664 static int ccs_path_number_acl(struct ccs_request_info *r, const u8 type,
1665 const struct ccs_path_info *filename,
1666 const unsigned long number)
1667 {
1668 const struct ccs_domain_info * const domain = ccs_current_domain();
1669 struct ccs_acl_info *ptr;
1670 const u8 perm = 1 << type;
1671 int error = -EPERM;
1672 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1673 struct ccs_path_number_acl *acl;
1674 if (ptr->is_deleted || ptr->type != CCS_TYPE_PATH_NUMBER_ACL)
1675 continue;
1676 acl = container_of(ptr, struct ccs_path_number_acl, head);
1677 if (!(acl->perm & perm) || !ccs_condition(r, ptr) ||
1678 !ccs_compare_number_union(number, &acl->number) ||
1679 !ccs_compare_name_union(filename, &acl->name))
1680 continue;
1681 r->cond = ptr->cond;
1682 error = 0;
1683 break;
1684 }
1685 return error;
1686 }
1687
1688 /**
1689 * ccs_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
1690 *
1691 * @r: Pointer to "struct ccs_request_info".
1692 * @type: One of values in "enum ccs_path_number_acl_index".
1693 * @filename: Filename to check.
1694 * @number: Number.
1695 *
1696 * Returns 0 on success, 1 on retry, negative value otherwise.
1697 *
1698 * Caller holds ccs_read_lock().
1699 */
1700 static int ccs_path_number_perm2(struct ccs_request_info *r, const u8 type,
1701 const struct ccs_path_info *filename,
1702 const unsigned long number)
1703 {
1704 char buffer[64];
1705 int error;
1706 u8 radix;
1707 const char *msg = ccs_path_number2keyword(type);
1708 if (!filename)
1709 return 0;
1710 switch (type) {
1711 case CCS_TYPE_CREATE:
1712 case CCS_TYPE_MKDIR:
1713 case CCS_TYPE_MKFIFO:
1714 case CCS_TYPE_MKSOCK:
1715 case CCS_TYPE_CHMOD:
1716 radix = CCS_VALUE_TYPE_OCTAL;
1717 break;
1718 case CCS_TYPE_IOCTL:
1719 radix = CCS_VALUE_TYPE_HEXADECIMAL;
1720 break;
1721 default:
1722 radix = CCS_VALUE_TYPE_DECIMAL;
1723 break;
1724 }
1725 ccs_print_ulong(buffer, sizeof(buffer), number, radix);
1726 do {
1727 error = ccs_path_number_acl(r, type, filename, number);
1728 ccs_audit_path_number_log(r, msg, filename->name, buffer,
1729 !error);
1730 if (!error)
1731 return 0;
1732 error = ccs_supervisor(r, "allow_%s %s %s\n", msg,
1733 ccs_file_pattern(filename), buffer);
1734 } while (error == CCS_RETRY_REQUEST);
1735 if (r->mode != CCS_CONFIG_ENFORCING)
1736 error = 0;
1737 return error;
1738 }
1739
1740 /**
1741 * ccs_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
1742 *
1743 * @type: Type of operation.
1744 * @dir: Pointer to "struct inode". May be NULL.
1745 * @dentry: Pointer to "struct dentry".
1746 * @vfsmnt: Pointer to "struct vfsmount".
1747 * @number: Number.
1748 *
1749 * Returns 0 on success, negative value otherwise.
1750 */
1751 static int ccs_path_number_perm(const u8 type, struct inode *dir,
1752 struct dentry *dentry, struct vfsmount *vfsmnt,
1753 unsigned long number)
1754 {
1755 struct ccs_request_info r;
1756 struct ccs_obj_info obj = {
1757 .path1.dentry = dentry,
1758 .path1.mnt = vfsmnt
1759 };
1760 int error = 0;
1761 struct ccs_path_info buf;
1762 int idx;
1763 if (!vfsmnt || !dentry)
1764 return 0;
1765 buf.name = NULL;
1766 idx = ccs_read_lock();
1767 if (ccs_init_request_info(&r, ccs_pn2mac[type]) == CCS_CONFIG_DISABLED)
1768 goto out;
1769 error = -ENOMEM;
1770 if (!ccs_get_realpath(&buf, dentry, vfsmnt))
1771 goto out;
1772 r.obj = &obj;
1773 if (type == CCS_TYPE_MKDIR)
1774 ccs_add_slash(&buf);
1775 error = ccs_path_number_perm2(&r, type, &buf, number);
1776 out:
1777 kfree(buf.name);
1778 ccs_read_unlock(idx);
1779 if (r.mode != CCS_CONFIG_ENFORCING)
1780 error = 0;
1781 return error;
1782 }
1783
1784 /**
1785 * ccs_ioctl_permission - Check permission for "ioctl".
1786 *
1787 * @filp: Pointer to "struct file".
1788 * @cmd: Ioctl command number.
1789 * @arg: Param for @cmd .
1790 *
1791 * Returns 0 on success, negative value otherwise.
1792 */
1793 static int __ccs_ioctl_permission(struct file *filp, unsigned int cmd,
1794 unsigned long arg)
1795 {
1796 return ccs_path_number_perm(CCS_TYPE_IOCTL, NULL, filp->f_dentry,
1797 filp->f_vfsmnt, cmd);
1798 }
1799
1800 /**
1801 * ccs_chmod_permission - Check permission for "chmod".
1802 *
1803 * @dentry: Pointer to "struct dentry".
1804 * @vfsmnt: Pointer to "struct vfsmount".
1805 * @mode: Mode.
1806 *
1807 * Returns 0 on success, negative value otherwise.
1808 */
1809 static int __ccs_chmod_permission(struct dentry *dentry,
1810 struct vfsmount *vfsmnt, mode_t mode)
1811 {
1812 if (mode == (mode_t) -1)
1813 return 0;
1814 if (!ccs_capable(CCS_SYS_CHMOD))
1815 return -EPERM;
1816 return ccs_path_number_perm(CCS_TYPE_CHMOD, NULL, dentry, vfsmnt,
1817 mode & S_IALLUGO);
1818 }
1819
1820 /**
1821 * ccs_chown_permission - Check permission for "chown/chgrp".
1822 *
1823 * @dentry: Pointer to "struct dentry".
1824 * @vfsmnt: Pointer to "struct vfsmount".
1825 * @user: User ID.
1826 * @group: Group ID.
1827 *
1828 * Returns 0 on success, negative value otherwise.
1829 */
1830 static int __ccs_chown_permission(struct dentry *dentry,
1831 struct vfsmount *vfsmnt, uid_t user,
1832 gid_t group)
1833 {
1834 int error = 0;
1835 if (user == (uid_t) -1 && group == (gid_t) -1)
1836 return 0;
1837 if (!ccs_capable(CCS_SYS_CHOWN))
1838 return -EPERM;
1839 if (user != (uid_t) -1)
1840 error = ccs_path_number_perm(CCS_TYPE_CHOWN, NULL, dentry,
1841 vfsmnt, user);
1842 if (!error && group != (gid_t) -1)
1843 error = ccs_path_number_perm(CCS_TYPE_CHGRP, NULL, dentry,
1844 vfsmnt, group);
1845 return error;
1846 }
1847
1848 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
1849 static int __ccs_fcntl_permission(struct file *file, unsigned int cmd,
1850 unsigned long arg)
1851 {
1852 if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND) &&
1853 __ccs_rewrite_permission(file))
1854 return -EPERM;
1855 return 0;
1856 }
1857 #endif
1858
1859 /**
1860 * ccs_pivot_root_permission - Check permission for pivot_root().
1861 *
1862 * @old_path: Pointer to "struct path".
1863 * @new_path: Pointer to "struct path".
1864 *
1865 * Returns 0 on success, negative value otherwise.
1866 */
1867 static int __ccs_pivot_root_permission(struct path *old_path,
1868 struct path *new_path)
1869 {
1870 if (!ccs_capable(CCS_SYS_PIVOT_ROOT))
1871 return -EPERM;
1872 return ccs_path2_perm(CCS_TYPE_PIVOT_ROOT, NULL, new_path->dentry,
1873 new_path->mnt, NULL, old_path->dentry,
1874 old_path->mnt);
1875 }
1876
1877 /**
1878 * ccs_chroot_permission - Check permission for chroot().
1879 *
1880 * @path: Pointer to "struct path".
1881 *
1882 * Returns 0 on success, negative value otherwise.
1883 */
1884 static int __ccs_chroot_permission(struct path *path)
1885 {
1886 if (!ccs_capable(CCS_SYS_CHROOT))
1887 return -EPERM;
1888 return ccs_path_perm(CCS_TYPE_CHROOT, NULL, path->dentry, path->mnt,
1889 NULL);
1890 }
1891
1892 /**
1893 * ccs_umount_permission - Check permission for unmount.
1894 *
1895 * @mnt: Pointer to "struct vfsmount".
1896 * @flags: Umount flags.
1897 *
1898 * Returns 0 on success, negative value otherwise.
1899 */
1900 static int __ccs_umount_permission(struct vfsmount *mnt, int flags)
1901 {
1902 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
1903 if (!ccs_capable(CCS_SYS_UMOUNT))
1904 return -EPERM;
1905 #endif
1906 return ccs_path_perm(CCS_TYPE_UMOUNT, NULL, mnt->mnt_root, mnt, NULL);
1907 }
1908
1909 /**
1910 * ccs_write_file_policy - Update file related list.
1911 *
1912 * @data: String to parse.
1913 * @domain: Pointer to "struct ccs_domain_info".
1914 * @condition: Pointer to "struct ccs_condition". May be NULL.
1915 * @is_delete: True if it is a delete request.
1916 *
1917 * Returns 0 on success, negative value otherwise.
1918 */
1919 int ccs_write_file_policy(char *data, struct ccs_domain_info *domain,
1920 struct ccs_condition *condition,
1921 const bool is_delete)
1922 {
1923 char *w[5];
1924 u8 type;
1925 if (!ccs_tokenize(data, w, sizeof(w)) || !w[1][0])
1926 return -EINVAL;
1927 if (strncmp(w[0], "allow_", 6)) {
1928 unsigned int perm;
1929 if (sscanf(w[0], "%u", &perm) == 1)
1930 return ccs_update_file_acl((u8) perm, w[1], domain,
1931 condition, is_delete);
1932 if (!strcmp(w[0], CCS_KEYWORD_EXECUTE_HANDLER))
1933 type = CCS_TYPE_EXECUTE_HANDLER;
1934 else if (!strcmp(w[0], CCS_KEYWORD_DENIED_EXECUTE_HANDLER))
1935 type = CCS_TYPE_DENIED_EXECUTE_HANDLER;
1936 else
1937 goto out;
1938 return ccs_update_execute_handler(type, w[1], domain,
1939 is_delete);
1940 }
1941 w[0] += 6;
1942 for (type = 0; type < CCS_MAX_PATH_OPERATION; type++) {
1943 if (strcmp(w[0], ccs_path_keyword[type]))
1944 continue;
1945 return ccs_update_path_acl(type, w[1], domain, condition,
1946 is_delete);
1947 }
1948 if (!w[2][0])
1949 goto out;
1950 for (type = 0; type < CCS_MAX_PATH2_OPERATION; type++) {
1951 if (strcmp(w[0], ccs_path2_keyword[type]))
1952 continue;
1953 return ccs_update_path2_acl(type, w[1], w[2], domain,
1954 condition, is_delete);
1955 }
1956 for (type = 0; type < CCS_MAX_PATH_NUMBER_OPERATION; type++) {
1957 if (strcmp(w[0], ccs_path_number_keyword[type]))
1958 continue;
1959 return ccs_update_path_number_acl(type, w[1], w[2], domain,
1960 condition, is_delete);
1961 }
1962 if (!w[3][0] || !w[4][0])
1963 goto out;
1964 for (type = 0; type < CCS_MAX_PATH_NUMBER3_OPERATION; type++) {
1965 if (strcmp(w[0], ccs_path_number3_keyword[type]))
1966 continue;
1967 return ccs_update_path_number3_acl(type, w[1], w[2], w[3],
1968 w[4], domain, condition,
1969 is_delete);
1970 }
1971 out:
1972 return -EINVAL;
1973 }
1974
1975 /*
1976 * Permission checks from vfs_mknod().
1977 *
1978 * This function is exported because
1979 * vfs_mknod() is called from net/unix/af_unix.c.
1980 */
1981 static int __ccs_mknod_permission(struct inode *dir, struct dentry *dentry,
1982 struct vfsmount *mnt,
1983 const unsigned int mode, unsigned int dev)
1984 {
1985 int error = 0;
1986 const unsigned int perm = mode & S_IALLUGO;
1987 switch (mode & S_IFMT) {
1988 case S_IFCHR:
1989 if (!ccs_capable(CCS_CREATE_CHAR_DEV))
1990 error = -EPERM;
1991 else
1992 error = ccs_path_number3_perm(CCS_TYPE_MKCHAR, dir,
1993 dentry, mnt, perm, dev);
1994 break;
1995 case S_IFBLK:
1996 if (!ccs_capable(CCS_CREATE_BLOCK_DEV))
1997 error = -EPERM;
1998 else
1999 error = ccs_path_number3_perm(CCS_TYPE_MKBLOCK, dir,
2000 dentry, mnt, perm, dev);
2001 break;
2002 case S_IFIFO:
2003 if (!ccs_capable(CCS_CREATE_FIFO))
2004 error = -EPERM;
2005 else
2006 error = ccs_path_number_perm(CCS_TYPE_MKFIFO, dir,
2007 dentry, mnt, perm);
2008 break;
2009 case S_IFSOCK:
2010 if (!ccs_capable(CCS_CREATE_UNIX_SOCKET))
2011 error = -EPERM;
2012 else
2013 error = ccs_path_number_perm(CCS_TYPE_MKSOCK, dir,
2014 dentry, mnt, perm);
2015 break;
2016 case 0:
2017 case S_IFREG:
2018 error = ccs_path_number_perm(CCS_TYPE_CREATE, dir, dentry, mnt,
2019 perm);
2020 break;
2021 }
2022 return error;
2023 }
2024
2025 /* Permission checks for vfs_mkdir(). */
2026 static int __ccs_mkdir_permission(struct inode *dir, struct dentry *dentry,
2027 struct vfsmount *mnt, unsigned int mode)
2028 {
2029 return ccs_path_number_perm(CCS_TYPE_MKDIR, dir, dentry, mnt, mode);
2030 }
2031
2032 /* Permission checks for vfs_rmdir(). */
2033 static int __ccs_rmdir_permission(struct inode *dir, struct dentry *dentry,
2034 struct vfsmount *mnt)
2035 {
2036 return ccs_path_perm(CCS_TYPE_RMDIR, dir, dentry, mnt, NULL);
2037 }
2038
2039 /* Permission checks for vfs_unlink(). */
2040 static int __ccs_unlink_permission(struct inode *dir, struct dentry *dentry,
2041 struct vfsmount *mnt)
2042 {
2043 if (!ccs_capable(CCS_SYS_UNLINK))
2044 return -EPERM;
2045 return ccs_path_perm(CCS_TYPE_UNLINK, dir, dentry, mnt, NULL);
2046 }
2047
2048 /* Permission checks for vfs_symlink(). */
2049 static int __ccs_symlink_permission(struct inode *dir, struct dentry *dentry,
2050 struct vfsmount *mnt, const char *from)
2051 {
2052 if (!ccs_capable(CCS_SYS_SYMLINK))
2053 return -EPERM;
2054 return ccs_path_perm(CCS_TYPE_SYMLINK, dir, dentry, mnt, from);
2055 }
2056
2057 /* Permission checks for notify_change(). */
2058 static int __ccs_truncate_permission(struct dentry *dentry,
2059 struct vfsmount *mnt)
2060 {
2061 return ccs_path_perm(CCS_TYPE_TRUNCATE, NULL, dentry, mnt, NULL);
2062 }
2063
2064 /* Permission checks for vfs_rename(). */
2065 static int __ccs_rename_permission(struct inode *old_dir,
2066 struct dentry *old_dentry,
2067 struct inode *new_dir,
2068 struct dentry *new_dentry,
2069 struct vfsmount *mnt)
2070 {
2071 if (!ccs_capable(CCS_SYS_RENAME))
2072 return -EPERM;
2073 return ccs_path2_perm(CCS_TYPE_RENAME, old_dir, old_dentry, mnt,
2074 new_dir, new_dentry, mnt);
2075 }
2076
2077 /* Permission checks for vfs_link(). */
2078 static int __ccs_link_permission(struct dentry *old_dentry,
2079 struct inode *new_dir,
2080 struct dentry *new_dentry,
2081 struct vfsmount *mnt)
2082 {
2083 if (!ccs_capable(CCS_SYS_LINK))
2084 return -EPERM;
2085 return ccs_path2_perm(CCS_TYPE_LINK, NULL, old_dentry, mnt,
2086 new_dir, new_dentry, mnt);
2087 }
2088
2089 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
2090 /* Permission checks for open_exec(). */
2091 static int __ccs_open_exec_permission(struct dentry *dentry,
2092 struct vfsmount *mnt)
2093 {
2094 return (current->ccs_flags & CCS_TASK_IS_IN_EXECVE) ?
2095 /* 01 means "read". */
2096 ccs_open_permission(dentry, mnt, 01) : 0;
2097 }
2098
2099 /* Permission checks for sys_uselib(). */
2100 static int __ccs_uselib_permission(struct dentry *dentry, struct vfsmount *mnt)
2101 {
2102 /* 01 means "read". */
2103 return ccs_open_permission(dentry, mnt, 01);
2104 }
2105 #endif
2106
2107 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
2108 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || defined(CONFIG_SYSCTL_SYSCALL)
2109
2110 #include <linux/sysctl.h>
2111
2112 /* Permission checks for parse_table(). */
2113 static int __ccs_parse_table(int __user *name, int nlen, void __user *oldval,
2114 void __user *newval, struct ctl_table *table)
2115 {
2116 int n;
2117 int error = -ENOMEM;
2118 int op = 0;
2119 struct ccs_path_info buf;
2120 char *buffer = NULL;
2121 struct ccs_request_info r;
2122 int idx;
2123 if (oldval)
2124 op |= 004;
2125 if (newval)
2126 op |= 002;
2127 if (!op) /* Neither read nor write */
2128 return 0;
2129 idx = ccs_read_lock();
2130 if (ccs_init_request_info(&r, CCS_MAC_FILE_OPEN)
2131 == CCS_CONFIG_DISABLED) {
2132 error = 0;
2133 goto out;
2134 }
2135 buffer = kmalloc(PAGE_SIZE, CCS_GFP_FLAGS);
2136 if (!buffer)
2137 goto out;
2138 snprintf(buffer, PAGE_SIZE - 1, "/proc/sys");
2139 repeat:
2140 if (!nlen) {
2141 error = -ENOTDIR;
2142 goto out;
2143 }
2144 if (get_user(n, name)) {
2145 error = -EFAULT;
2146 goto out;
2147 }
2148 for ( ; table->ctl_name
2149 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
2150 || table->procname
2151 #endif
2152 ; table++) {
2153 int pos;
2154 const char *cp;
2155 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
2156 if (n != table->ctl_name && table->ctl_name != CTL_ANY)
2157 continue;
2158 #else
2159 if (!n || n != table->ctl_name)
2160 continue;
2161 #endif
2162 pos = strlen(buffer);
2163 cp = table->procname;
2164 error = -ENOMEM;
2165 if (cp) {
2166 int len = strlen(cp);
2167 if (len + 2 > PAGE_SIZE - 1)
2168 goto out;
2169 buffer[pos++] = '/';
2170 memmove(buffer + pos, cp, len + 1);
2171 } else {
2172 /* Assume nobody assigns "=\$=" for procname. */
2173 snprintf(buffer + pos, PAGE_SIZE - pos - 1,
2174 "/=%d=", table->ctl_name);
2175 if (!memchr(buffer, '\0', PAGE_SIZE - 2))
2176 goto out;
2177 }
2178 if (table->child) {
2179 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
2180 if (table->strategy) {
2181 /* printk("sysctl='%s'\n", buffer); */
2182 buf.name = ccs_encode(buffer);
2183 if (buf.name) {
2184 ccs_fill_path_info(&buf);
2185 error = ccs_file_perm(&r, &buf, op);
2186 kfree(buf.name);
2187 }
2188 if (error)
2189 goto out;
2190 }
2191 #endif
2192 name++;
2193 nlen--;
2194 table = table->child;
2195 goto repeat;
2196 }
2197 /* printk("sysctl='%s'\n", buffer); */
2198 buf.name = ccs_encode(buffer);
2199 if (buf.name) {
2200 ccs_fill_path_info(&buf);
2201 error = ccs_file_perm(&r, &buf, op);
2202 kfree(buf.name);
2203 }
2204 goto out;
2205 }
2206 error = -ENOTDIR;
2207 out:
2208 ccs_read_unlock(idx);
2209 kfree(buffer);
2210 return error;
2211 }
2212 #endif
2213 #endif
2214
2215 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
2216 static int ccs_old_pivot_root_permission(struct nameidata *old_nd,
2217 struct nameidata *new_nd)
2218 {
2219 struct path old_path = { old_nd->mnt, old_nd->dentry };
2220 struct path new_path = { new_nd->mnt, new_nd->dentry };
2221 return __ccs_pivot_root_permission(&old_path, &new_path);
2222 }
2223
2224 static int ccs_old_chroot_permission(struct nameidata *nd)
2225 {
2226 struct path path = { nd->mnt, nd->dentry };
2227 return __ccs_chroot_permission(&path);
2228 }
2229 #endif
2230
2231 void __init ccs_file_init(void)
2232 {
2233 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
2234 ccsecurity_ops.save_open_mode = __ccs_save_open_mode;
2235 ccsecurity_ops.clear_open_mode = __ccs_clear_open_mode;
2236 #endif
2237 ccsecurity_ops.open_permission = __ccs_open_permission;
2238 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
2239 ccsecurity_ops.fcntl_permission = __ccs_fcntl_permission;
2240 #else
2241 ccsecurity_ops.rewrite_permission = __ccs_rewrite_permission;
2242 #endif
2243 ccsecurity_ops.ioctl_permission = __ccs_ioctl_permission;
2244 ccsecurity_ops.chmod_permission = __ccs_chmod_permission;
2245 ccsecurity_ops.chown_permission = __ccs_chown_permission;
2246 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
2247 ccsecurity_ops.pivot_root_permission = __ccs_pivot_root_permission;
2248 ccsecurity_ops.chroot_permission = __ccs_chroot_permission;
2249 #else
2250 ccsecurity_ops.pivot_root_permission = ccs_old_pivot_root_permission;
2251 ccsecurity_ops.chroot_permission = ccs_old_chroot_permission;
2252 #endif
2253 ccsecurity_ops.umount_permission = __ccs_umount_permission;
2254 ccsecurity_ops.mknod_permission = __ccs_mknod_permission;
2255 ccsecurity_ops.mkdir_permission = __ccs_mkdir_permission;
2256 ccsecurity_ops.rmdir_permission = __ccs_rmdir_permission;
2257 ccsecurity_ops.unlink_permission = __ccs_unlink_permission;
2258 ccsecurity_ops.symlink_permission = __ccs_symlink_permission;
2259 ccsecurity_ops.truncate_permission = __ccs_truncate_permission;
2260 ccsecurity_ops.rename_permission = __ccs_rename_permission;
2261 ccsecurity_ops.link_permission = __ccs_link_permission;
2262 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
2263 ccsecurity_ops.open_exec_permission = __ccs_open_exec_permission;
2264 ccsecurity_ops.uselib_permission = __ccs_uselib_permission;
2265 #endif
2266 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
2267 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) || defined(CONFIG_SYSCTL_SYSCALL)
2268 ccsecurity_ops.parse_table = __ccs_parse_table;
2269 #endif
2270 #endif
2271 };

SourceForge.JP is a Japanese version of SourceForge.net. For developments that are not related to Japan, we recommend you to use SourceForge.net.