aboutsummaryrefslogtreecommitdiffstats
path: root/security/tomoyo/common.c
diff options
context:
space:
mode:
authorKentaro Takeda <takedakn@nttdata.co.jp>2009-02-05 03:18:13 -0500
committerJames Morris <jmorris@namei.org>2009-02-11 23:15:04 -0500
commit9590837b89aaa4523209ac91c52db5ea0d9142fd (patch)
tree0e7e3febb1f6106be0e45c281309078f6c1cd7e6 /security/tomoyo/common.c
parentc73bd6d473ceb5d643d3afd7e75b7dc2e6918558 (diff)
Common functions for TOMOYO Linux.
This file contains common functions (e.g. policy I/O, pattern matching). -------------------- About pattern matching -------------------- Since TOMOYO Linux is a name based access control, TOMOYO Linux seriously considers "safe" string representation. TOMOYO Linux's string manipulation functions make reviewers feel crazy, but there are reasons why TOMOYO Linux needs its own string manipulation functions. ----- Part 1 : preconditions ----- People definitely want to use wild card. To support pattern matching, we have to support wild card characters. In a typical Linux system, filenames are likely consists of only alphabets, numbers, and some characters (e.g. + - ~ . / ). But theoretically, the Linux kernel accepts all characters but NUL character (which is used as a terminator of a string). Some Linux systems can have filenames which contain * ? ** etc. Therefore, we have to somehow modify string so that we can distinguish wild card characters and normal characters. It might be possible for some application's configuration files to restrict acceptable characters. It is impossible for kernel to restrict acceptable characters. We can't accept approaches which will cause troubles for applications. ----- Part 2 : commonly used approaches ----- Text formatted strings separated by space character (0x20) and new line character (0x0A) is more preferable for users over array of NUL-terminated string. Thus, people use text formatted configuration files separated by space character and new line. We sometimes need to handle non-printable characters. Thus, people use \ character (0x5C) as escape character and represent non-printable characters using octal or hexadecimal format. At this point, we remind (at least) 3 approaches. (1) Shell glob style expression (2) POSIX regular expression (UNIX style regular expression) (3) Maverick wild card expression On the surface, (1) and (2) sound good choices. But they have a big pitfall. All meta-characters in (1) and (2) are legal characters for representing a pathname, and users easily write incorrect expression. What is worse, users unlikely notice incorrect expressions because characters used for regular pathnames unlikely contain meta-characters. This incorrect use of meta-characters in pathname representation reveals vulnerability (e.g. unexpected results) only when irregular pathname is specified. The authors of TOMOYO Linux think that approaches which adds some character for interpreting meta-characters as normal characters (i.e. (1) and (2)) are not suitable for security use. Therefore, the authors of TOMOYO Linux propose (3). ----- Part 3: consideration points ----- We need to solve encoding problem. A single character can be represented in several ways using encodings. For Japanese language, there are "ShiftJIS", "ISO-2022-JP", "EUC-JP", "UTF-8" and more. Some languages (e.g. Japanese language) supports multi-byte characters (where a single character is represented using several bytes). Some multi-byte characters may match the escape character. For Japanese language, some characters in "ShiftJIS" encoding match \ character, and bothering Web's CGI developers. It is important that the kernel string is not bothered by encoding problem. Linus said, "I really would expect that kernel strings don't have an encoding. They're just C strings: a NUL-terminated stream of bytes." http://lkml.org/lkml/2007/11/6/142 Yes. The kernel strings are just C strings. We are talking about how to store and carry "kernel strings" safely. If we store "kernel string" into policy file as-is, the "kernel string" will be interpreted differently depending on application's encoding settings. One application may interpret "kernel string" as "UTF-8", another application may interpret "kernel string" as "ShiftJIS". Therefore, we propose to represent strings using ASCII encoding. In this way, we are no longer bothered by encoding problems. We need to avoid information loss caused by display. It is difficult to input and display non-printable characters, but we have to be able to handle such characters because the kernel string is a C string. If we use only ASCII printable characters (from 0x21 to 0x7E) and space character (0x20) and new line character (0x0A), it is easy to input from keyboard and display on all terminals which is running Linux. Therefore, we propose to represent strings using only characters which value is one of "from 0x21 to 0x7E", "0x20", "0x0A". We need to consider ease of splitting strings from a line. If we use an approach which uses "\ " for representing a space character within a string, we have to count the string from the beginning to check whether this space character is accompanied with \ character or not. As a result, we cannot monotonically split a line using space character. If we use an approach which uses "\040" for representing a space character within a string, we can monotonically split a line using space character. If we use an approach which uses NUL character as a delimiter, we cannot use string manipulation functions for splitting strings from a line. Therefore, we propose that we represent space character as "\040". We need to avoid wrong designations (incorrect use of special characters). Not all users can understand and utilize POSIX's regular expressions correctly and perfectly. If a character acts as a wild card by default, the user will get unexpected result if that user didn't know the meaning of that character. Therefore, we propose that all characters but \ character act as a normal character and let the user add \ character to make a character act as a wild card. In this way, users needn't to know all wild card characters beforehand. They can learn when they encountered an unseen wild card character for their first time. ----- Part 4: supported wild card expressions ----- At this point, we have wild card expressions listed below. +-----------+--------------------------------------------------------------+ | Wild card | Meaning and example | +-----------+--------------------------------------------------------------+ | \* | More than or equals to 0 character other than '/'. | | | /var/log/samba/\* | +-----------+--------------------------------------------------------------+ | \@ | More than or equals to 0 character other than '/' or '.'. | | | /var/www/html/\@.html | +-----------+--------------------------------------------------------------+ | \? | 1 byte character other than '/'. | | | /tmp/mail.\?\?\?\?\?\? | +-----------+--------------------------------------------------------------+ | \$ | More than or equals to 1 decimal digit. | | | /proc/\$/cmdline | +-----------+--------------------------------------------------------------+ | \+ | 1 decimal digit. | | | /var/tmp/my_work.\+ | +-----------+--------------------------------------------------------------+ | \X | More than or equals to 1 hexadecimal digit. | | | /var/tmp/my-work.\X | +-----------+--------------------------------------------------------------+ | \x | 1 hexadecimal digit. | | | /tmp/my-work.\x | +-----------+--------------------------------------------------------------+ | \A | More than or equals to 1 alphabet character. | | | /var/log/my-work/\$-\A-\$.log | +-----------+--------------------------------------------------------------+ | \a | 1 alphabet character. | | | /home/users/\a/\*/public_html/\*.html | +-----------+--------------------------------------------------------------+ | \- | Pathname subtraction operator. | | | +---------------------+------------------------------------+ | | | | Example | Meaning | | | | +---------------------+------------------------------------+ | | | | /etc/\* | All files in /etc/ directory. | | | | +---------------------+------------------------------------+ | | | | /etc/\*\-\*shadow\* | /etc/\* other than /etc/\*shadow\* | | | | +---------------------+------------------------------------+ | | | | /\*\-proc\-sys/ | /\*/ other than /proc/ /sys/ | | | | +---------------------+------------------------------------+ | +-----------+--------------------------------------------------------------+ +----------------+---------------------------------------------------------+ | Representation | Meaning and example | +----------------+---------------------------------------------------------+ | \\ | backslash character itself. | +----------------+---------------------------------------------------------+ | \ooo | 1 byte character. | | | ooo is 001 <= ooo <= 040 || 177 <= ooo <= 377. | | | | | | \040 for space character. | | | \177 for del character. | | | | +----------------+---------------------------------------------------------+ ----- Part 5: Advantages ----- We can obtain extensibility. Since our proposed approach adds \ to a character to interpret as a wild card, we can introduce new wild card in future while maintaining backward compatibility. We can process monotonically. Since our proposed approach separates strings using a space character, we can split strings using existing string manipulation functions. We can reliably analyze access logs. It is guaranteed that a string doesn't contain space character (0x20) and new line character (0x0A). It is guaranteed that a string won't be converted by FTP and won't be damaged by a terminal's settings. It is guaranteed that a string won't be affected by encoding converters (except encodings which insert NUL character (e.g. UTF-16)). ----- Part 6: conclusion ----- TOMOYO Linux is using its own encoding with reasons described above. There is a disadvantage that we need to introduce a series of new string manipulation functions. But TOMOYO Linux's encoding is useful for all users (including audit and AppArmor) who want to perform pattern matching and safely exchange string information between the kernel and the userspace. -------------------- About policy interface -------------------- TOMOYO Linux creates the following files on securityfs (normally mounted on /sys/kernel/security) as interfaces between kernel and userspace. These files are for TOMOYO Linux management tools *only*, not for general programs. * profile * exception_policy * domain_policy * manager * meminfo * self_domain * version * .domain_status * .process_status ** /sys/kernel/security/tomoyo/profile ** This file is used to read or write profiles. "profile" means a running mode of process. A profile lists up functions and their modes in "$number-$variable=$value" format. The $number is profile number between 0 and 255. Each domain is assigned one profile. To assign profile to domains, use "ccs-setprofile" or "ccs-editpolicy" or "ccs-loadpolicy" commands. (Example) [root@tomoyo]# cat /sys/kernel/security/tomoyo/profile 0-COMMENT=-----Disabled Mode----- 0-MAC_FOR_FILE=disabled 0-MAX_ACCEPT_ENTRY=2048 0-TOMOYO_VERBOSE=disabled 1-COMMENT=-----Learning Mode----- 1-MAC_FOR_FILE=learning 1-MAX_ACCEPT_ENTRY=2048 1-TOMOYO_VERBOSE=disabled 2-COMMENT=-----Permissive Mode----- 2-MAC_FOR_FILE=permissive 2-MAX_ACCEPT_ENTRY=2048 2-TOMOYO_VERBOSE=enabled 3-COMMENT=-----Enforcing Mode----- 3-MAC_FOR_FILE=enforcing 3-MAX_ACCEPT_ENTRY=2048 3-TOMOYO_VERBOSE=enabled - MAC_FOR_FILE: Specifies access control level regarding file access requests. - MAX_ACCEPT_ENTRY: Limits the max number of ACL entries that are automatically appended during learning mode. Default is 2048. - TOMOYO_VERBOSE: Specifies whether to print domain policy violation messages or not. ** /sys/kernel/security/tomoyo/manager ** This file is used to read or append the list of programs or domains that can write to /sys/kernel/security/tomoyo interface. By default, only processes with both UID = 0 and EUID = 0 can modify policy via /sys/kernel/security/tomoyo interface. You can use keyword "manage_by_non_root" to allow policy modification by non root user. (Example) [root@tomoyo]# cat /sys/kernel/security/tomoyo/manager /usr/lib/ccs/loadpolicy /usr/lib/ccs/editpolicy /usr/lib/ccs/setlevel /usr/lib/ccs/setprofile /usr/lib/ccs/ld-watch /usr/lib/ccs/ccs-queryd ** /sys/kernel/security/tomoyo/exception_policy ** This file is used to read and write system global settings. Each line has a directive and operand pair. Directives are listed below. - initialize_domain: To initialize domain transition when specific program is executed, use initialize_domain directive. * initialize_domain "program" from "domain" * initialize_domain "program" from "the last program part of domain" * initialize_domain "program" If the part "from" and after is not given, the entry is applied to all domain. If the "domain" doesn't start with "<kernel>", the entry is applied to all domain whose domainname ends with "the last program part of domain". This directive is intended to aggregate domain transitions for daemon program and program that are invoked by the kernel on demand, by transiting to different domain. - keep_domain To prevent domain transition when program is executed from specific domain, use keep_domain directive. * keep_domain "program" from "domain" * keep_domain "program" from "the last program part of domain" * keep_domain "domain" * keep_domain "the last program part of domain" If the part "from" and before is not given, this entry is applied to all program. If the "domain" doesn't start with "<kernel>", the entry is applied to all domain whose domainname ends with "the last program part of domain". This directive is intended to reduce total number of domains and memory usage by suppressing unneeded domain transitions. To declare domain keepers, use keep_domain directive followed by domain definition. Any process that belongs to any domain declared with this directive, the process stays at the same domain unless any program registered with initialize_domain directive is executed. In order to control domain transition in detail, you can use no_keep_domain/no_initialize_domain keywrods. - alias: To allow executing programs using the name of symbolic links, use alias keyword followed by dereferenced pathname and reference pathname. For example, /sbin/pidof is a symbolic link to /sbin/killall5 . In normal case, if /sbin/pidof is executed, the domain is defined as if /sbin/killall5 is executed. By specifying "alias /sbin/killall5 /sbin/pidof", you can run /sbin/pidof in the domain for /sbin/pidof . (Example) alias /sbin/killall5 /sbin/pidof - allow_read: To grant unconditionally readable permissions, use allow_read keyword followed by canonicalized file. This keyword is intended to reduce size of domain policy by granting read access to library files such as GLIBC and locale files. Exception is, if ignore_global_allow_read keyword is given to a domain, entries specified by this keyword are ignored. (Example) allow_read /lib/libc-2.5.so - file_pattern: To declare pathname pattern, use file_pattern keyword followed by pathname pattern. The pathname pattern must be a canonicalized Pathname. This keyword is not applicable to neither granting execute permissions nor domain definitions. For example, canonicalized pathname that contains a process ID (i.e. /proc/PID/ files) needs to be grouped in order to make access control work well. (Example) file_pattern /proc/\$/cmdline - path_group To declare pathname group, use path_group keyword followed by name of the group and pathname pattern. For example, if you want to group all files under home directory, you can define path_group HOME-DIR-FILE /home/\*/\* path_group HOME-DIR-FILE /home/\*/\*/\* path_group HOME-DIR-FILE /home/\*/\*/\*/\* in the exception policy and use like allow_read @HOME-DIR-FILE to grant file access permission. - deny_rewrite: To deny overwriting already written contents of file (such as log files) by default, use deny_rewrite keyword followed by pathname pattern. Files whose pathname match the patterns are not permitted to open for writing without append mode or truncate unless the pathnames are explicitly granted using allow_rewrite keyword in domain policy. (Example) deny_rewrite /var/log/\* - aggregator To deal multiple programs as a single program, use aggregator keyword followed by name of original program and aggregated program. This keyword is intended to aggregate similar programs. For example, /usr/bin/tac and /bin/cat are similar. By specifying "aggregator /usr/bin/tac /bin/cat", you can run /usr/bin/tac in the domain for /bin/cat . For example, /usr/sbin/logrotate for Fedora Core 3 generates programs like /tmp/logrotate.\?\?\?\?\?\? and run them, but TOMOYO Linux doesn't allow using patterns for granting execute permission and defining domains. By specifying "aggregator /tmp/logrotate.\?\?\?\?\?\? /tmp/logrotate.tmp", you can run /tmp/logrotate.\?\?\?\?\?\? as if /tmp/logrotate.tmp is running. ** /sys/kernel/security/tomoyo/domain_policy ** This file contains definition of all domains and permissions that are granted to each domain. Lines from the next line to a domain definition ( any lines starting with "<kernel>") to the previous line to the next domain definitions are interpreted as access permissions for that domain. ** /sys/kernel/security/tomoyo/meminfo ** This file is to show the total RAM used to keep policy in the kernel by TOMOYO Linux in bytes. (Example) [root@tomoyo]# cat /sys/kernel/security/tomoyo/meminfo Shared: 61440 Private: 69632 Dynamic: 768 Total: 131840 You can set memory quota by writing to this file. (Example) [root@tomoyo]# echo Shared: 2097152 > /sys/kernel/security/tomoyo/meminfo [root@tomoyo]# echo Private: 2097152 > /sys/kernel/security/tomoyo/meminfo ** /sys/kernel/security/tomoyo/self_domain ** This file is to show the name of domain the caller process belongs to. (Example) [root@etch]# cat /sys/kernel/security/tomoyo/self_domain <kernel> /usr/sbin/sshd /bin/zsh /bin/cat ** /sys/kernel/security/tomoyo/version ** This file is used for getting TOMOYO Linux's version. (Example) [root@etch]# cat /sys/kernel/security/tomoyo/version 2.2.0-pre ** /sys/kernel/security/tomoyo/.domain_status ** This is a view (of a DBMS) that contains only profile number and domainnames of domain so that "ccs-setprofile" command can do line-oriented processing easily. ** /sys/kernel/security/tomoyo/.process_status ** This file is used by "ccs-ccstree" command to show "list of processes currently running" and "domains which each process belongs to" and "profile number which the domain is currently assigned" like "pstree" command. This file is writable by programs that aren't registered as policy manager. Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: Toshiharu Harada <haradats@nttdata.co.jp> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/common.c')
-rw-r--r--security/tomoyo/common.c2202
1 files changed, 2202 insertions, 0 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
new file mode 100644
index 000000000000..8bedfb1992e5
--- /dev/null
+++ b/security/tomoyo/common.c
@@ -0,0 +1,2202 @@
1/*
2 * security/tomoyo/common.c
3 *
4 * Common functions for TOMOYO.
5 *
6 * Copyright (C) 2005-2009 NTT DATA CORPORATION
7 *
8 * Version: 2.2.0-pre 2009/02/01
9 *
10 */
11
12#include <linux/uaccess.h>
13#include <linux/security.h>
14#include <linux/hardirq.h>
15#include "realpath.h"
16#include "common.h"
17#include "tomoyo.h"
18
19/* Has loading policy done? */
20bool tomoyo_policy_loaded;
21
22/* String table for functionality that takes 4 modes. */
23static const char *tomoyo_mode_4[4] = {
24 "disabled", "learning", "permissive", "enforcing"
25};
26/* String table for functionality that takes 2 modes. */
27static const char *tomoyo_mode_2[4] = {
28 "disabled", "enabled", "enabled", "enabled"
29};
30
31/* Table for profile. */
32static struct {
33 const char *keyword;
34 unsigned int current_value;
35 const unsigned int max_value;
36} tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = {
37 [TOMOYO_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 },
38 [TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX },
39 [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 },
40};
41
42/* Profile table. Memory is allocated as needed. */
43static struct tomoyo_profile {
44 unsigned int value[TOMOYO_MAX_CONTROL_INDEX];
45 const struct tomoyo_path_info *comment;
46} *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
47
48/* Permit policy management by non-root user? */
49static bool tomoyo_manage_by_non_root;
50
51/* Utility functions. */
52
53/* Open operation for /sys/kernel/security/tomoyo/ interface. */
54static int tomoyo_open_control(const u8 type, struct file *file);
55/* Close /sys/kernel/security/tomoyo/ interface. */
56static int tomoyo_close_control(struct file *file);
57/* Read operation for /sys/kernel/security/tomoyo/ interface. */
58static int tomoyo_read_control(struct file *file, char __user *buffer,
59 const int buffer_len);
60/* Write operation for /sys/kernel/security/tomoyo/ interface. */
61static int tomoyo_write_control(struct file *file, const char __user *buffer,
62 const int buffer_len);
63
64/**
65 * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value.
66 *
67 * @str: Pointer to the string.
68 *
69 * Returns true if @str is a \ooo style octal value, false otherwise.
70 *
71 * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
72 * This function verifies that \ooo is in valid range.
73 */
74static inline bool tomoyo_is_byte_range(const char *str)
75{
76 return *str >= '0' && *str++ <= '3' &&
77 *str >= '0' && *str++ <= '7' &&
78 *str >= '0' && *str <= '7';
79}
80
81/**
82 * tomoyo_is_alphabet_char - Check whether the character is an alphabet.
83 *
84 * @c: The character to check.
85 *
86 * Returns true if @c is an alphabet character, false otherwise.
87 */
88static inline bool tomoyo_is_alphabet_char(const char c)
89{
90 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
91}
92
93/**
94 * tomoyo_make_byte - Make byte value from three octal characters.
95 *
96 * @c1: The first character.
97 * @c2: The second character.
98 * @c3: The third character.
99 *
100 * Returns byte value.
101 */
102static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
103{
104 return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
105}
106
107/**
108 * tomoyo_str_starts - Check whether the given string starts with the given keyword.
109 *
110 * @src: Pointer to pointer to the string.
111 * @find: Pointer to the keyword.
112 *
113 * Returns true if @src starts with @find, false otherwise.
114 *
115 * The @src is updated to point the first character after the @find
116 * if @src starts with @find.
117 */
118static bool tomoyo_str_starts(char **src, const char *find)
119{
120 const int len = strlen(find);
121 char *tmp = *src;
122
123 if (strncmp(tmp, find, len))
124 return false;
125 tmp += len;
126 *src = tmp;
127 return true;
128}
129
130/**
131 * tomoyo_normalize_line - Format string.
132 *
133 * @buffer: The line to normalize.
134 *
135 * Leading and trailing whitespaces are removed.
136 * Multiple whitespaces are packed into single space.
137 *
138 * Returns nothing.
139 */
140static void tomoyo_normalize_line(unsigned char *buffer)
141{
142 unsigned char *sp = buffer;
143 unsigned char *dp = buffer;
144 bool first = true;
145
146 while (tomoyo_is_invalid(*sp))
147 sp++;
148 while (*sp) {
149 if (!first)
150 *dp++ = ' ';
151 first = false;
152 while (tomoyo_is_valid(*sp))
153 *dp++ = *sp++;
154 while (tomoyo_is_invalid(*sp))
155 sp++;
156 }
157 *dp = '\0';
158}
159
160/**
161 * tomoyo_is_correct_path - Validate a pathname.
162 * @filename: The pathname to check.
163 * @start_type: Should the pathname start with '/'?
164 * 1 = must / -1 = must not / 0 = don't care
165 * @pattern_type: Can the pathname contain a wildcard?
166 * 1 = must / -1 = must not / 0 = don't care
167 * @end_type: Should the pathname end with '/'?
168 * 1 = must / -1 = must not / 0 = don't care
169 * @function: The name of function calling me.
170 *
171 * Check whether the given filename follows the naming rules.
172 * Returns true if @filename follows the naming rules, false otherwise.
173 */
174bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
175 const s8 pattern_type, const s8 end_type,
176 const char *function)
177{
178 bool contains_pattern = false;
179 unsigned char c;
180 unsigned char d;
181 unsigned char e;
182 const char *original_filename = filename;
183
184 if (!filename)
185 goto out;
186 c = *filename;
187 if (start_type == 1) { /* Must start with '/' */
188 if (c != '/')
189 goto out;
190 } else if (start_type == -1) { /* Must not start with '/' */
191 if (c == '/')
192 goto out;
193 }
194 if (c)
195 c = *(filename + strlen(filename) - 1);
196 if (end_type == 1) { /* Must end with '/' */
197 if (c != '/')
198 goto out;
199 } else if (end_type == -1) { /* Must not end with '/' */
200 if (c == '/')
201 goto out;
202 }
203 while ((c = *filename++) != '\0') {
204 if (c == '\\') {
205 switch ((c = *filename++)) {
206 case '\\': /* "\\" */
207 continue;
208 case '$': /* "\$" */
209 case '+': /* "\+" */
210 case '?': /* "\?" */
211 case '*': /* "\*" */
212 case '@': /* "\@" */
213 case 'x': /* "\x" */
214 case 'X': /* "\X" */
215 case 'a': /* "\a" */
216 case 'A': /* "\A" */
217 case '-': /* "\-" */
218 if (pattern_type == -1)
219 break; /* Must not contain pattern */
220 contains_pattern = true;
221 continue;
222 case '0': /* "\ooo" */
223 case '1':
224 case '2':
225 case '3':
226 d = *filename++;
227 if (d < '0' || d > '7')
228 break;
229 e = *filename++;
230 if (e < '0' || e > '7')
231 break;
232 c = tomoyo_make_byte(c, d, e);
233 if (tomoyo_is_invalid(c))
234 continue; /* pattern is not \000 */
235 }
236 goto out;
237 } else if (tomoyo_is_invalid(c)) {
238 goto out;
239 }
240 }
241 if (pattern_type == 1) { /* Must contain pattern */
242 if (!contains_pattern)
243 goto out;
244 }
245 return true;
246 out:
247 printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function,
248 original_filename);
249 return false;
250}
251
252/**
253 * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules.
254 * @domainname: The domainname to check.
255 * @function: The name of function calling me.
256 *
257 * Returns true if @domainname follows the naming rules, false otherwise.
258 */
259bool tomoyo_is_correct_domain(const unsigned char *domainname,
260 const char *function)
261{
262 unsigned char c;
263 unsigned char d;
264 unsigned char e;
265 const char *org_domainname = domainname;
266
267 if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
268 TOMOYO_ROOT_NAME_LEN))
269 goto out;
270 domainname += TOMOYO_ROOT_NAME_LEN;
271 if (!*domainname)
272 return true;
273 do {
274 if (*domainname++ != ' ')
275 goto out;
276 if (*domainname++ != '/')
277 goto out;
278 while ((c = *domainname) != '\0' && c != ' ') {
279 domainname++;
280 if (c == '\\') {
281 c = *domainname++;
282 switch ((c)) {
283 case '\\': /* "\\" */
284 continue;
285 case '0': /* "\ooo" */
286 case '1':
287 case '2':
288 case '3':
289 d = *domainname++;
290 if (d < '0' || d > '7')
291 break;
292 e = *domainname++;
293 if (e < '0' || e > '7')
294 break;
295 c = tomoyo_make_byte(c, d, e);
296 if (tomoyo_is_invalid(c))
297 /* pattern is not \000 */
298 continue;
299 }
300 goto out;
301 } else if (tomoyo_is_invalid(c)) {
302 goto out;
303 }
304 }
305 } while (*domainname);
306 return true;
307 out:
308 printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function,
309 org_domainname);
310 return false;
311}
312
313/**
314 * tomoyo_is_domain_def - Check whether the given token can be a domainname.
315 *
316 * @buffer: The token to check.
317 *
318 * Returns true if @buffer possibly be a domainname, false otherwise.
319 */
320bool tomoyo_is_domain_def(const unsigned char *buffer)
321{
322 return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
323}
324
325/**
326 * tomoyo_find_domain - Find a domain by the given name.
327 *
328 * @domainname: The domainname to find.
329 *
330 * Caller must call down_read(&tomoyo_domain_list_lock); or
331 * down_write(&tomoyo_domain_list_lock); .
332 *
333 * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
334 */
335struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
336{
337 struct tomoyo_domain_info *domain;
338 struct tomoyo_path_info name;
339
340 name.name = domainname;
341 tomoyo_fill_path_info(&name);
342 list_for_each_entry(domain, &tomoyo_domain_list, list) {
343 if (!domain->is_deleted &&
344 !tomoyo_pathcmp(&name, domain->domainname))
345 return domain;
346 }
347 return NULL;
348}
349
350/**
351 * tomoyo_path_depth - Evaluate the number of '/' in a string.
352 *
353 * @pathname: The string to evaluate.
354 *
355 * Returns path depth of the string.
356 *
357 * I score 2 for each of the '/' in the @pathname
358 * and score 1 if the @pathname ends with '/'.
359 */
360static int tomoyo_path_depth(const char *pathname)
361{
362 int i = 0;
363
364 if (pathname) {
365 const char *ep = pathname + strlen(pathname);
366 if (pathname < ep--) {
367 if (*ep != '/')
368 i++;
369 while (pathname <= ep)
370 if (*ep-- == '/')
371 i += 2;
372 }
373 }
374 return i;
375}
376
377/**
378 * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
379 *
380 * @filename: The string to evaluate.
381 *
382 * Returns the initial length without a pattern in @filename.
383 */
384static int tomoyo_const_part_length(const char *filename)
385{
386 char c;
387 int len = 0;
388
389 if (!filename)
390 return 0;
391 while ((c = *filename++) != '\0') {
392 if (c != '\\') {
393 len++;
394 continue;
395 }
396 c = *filename++;
397 switch (c) {
398 case '\\': /* "\\" */
399 len += 2;
400 continue;
401 case '0': /* "\ooo" */
402 case '1':
403 case '2':
404 case '3':
405 c = *filename++;
406 if (c < '0' || c > '7')
407 break;
408 c = *filename++;
409 if (c < '0' || c > '7')
410 break;
411 len += 4;
412 continue;
413 }
414 break;
415 }
416 return len;
417}
418
419/**
420 * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
421 *
422 * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
423 *
424 * The caller sets "struct tomoyo_path_info"->name.
425 */
426void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
427{
428 const char *name = ptr->name;
429 const int len = strlen(name);
430
431 ptr->total_len = len;
432 ptr->const_len = tomoyo_const_part_length(name);
433 ptr->is_dir = len && (name[len - 1] == '/');
434 ptr->is_patterned = (ptr->const_len < len);
435 ptr->hash = full_name_hash(name, len);
436 ptr->depth = tomoyo_path_depth(name);
437}
438
439/**
440 * tomoyo_file_matches_to_pattern2 - Pattern matching without '/' character
441 * and "\-" pattern.
442 *
443 * @filename: The start of string to check.
444 * @filename_end: The end of string to check.
445 * @pattern: The start of pattern to compare.
446 * @pattern_end: The end of pattern to compare.
447 *
448 * Returns true if @filename matches @pattern, false otherwise.
449 */
450static bool tomoyo_file_matches_to_pattern2(const char *filename,
451 const char *filename_end,
452 const char *pattern,
453 const char *pattern_end)
454{
455 while (filename < filename_end && pattern < pattern_end) {
456 char c;
457 if (*pattern != '\\') {
458 if (*filename++ != *pattern++)
459 return false;
460 continue;
461 }
462 c = *filename;
463 pattern++;
464 switch (*pattern) {
465 int i;
466 int j;
467 case '?':
468 if (c == '/') {
469 return false;
470 } else if (c == '\\') {
471 if (filename[1] == '\\')
472 filename++;
473 else if (tomoyo_is_byte_range(filename + 1))
474 filename += 3;
475 else
476 return false;
477 }
478 break;
479 case '\\':
480 if (c != '\\')
481 return false;
482 if (*++filename != '\\')
483 return false;
484 break;
485 case '+':
486 if (!isdigit(c))
487 return false;
488 break;
489 case 'x':
490 if (!isxdigit(c))
491 return false;
492 break;
493 case 'a':
494 if (!tomoyo_is_alphabet_char(c))
495 return false;
496 break;
497 case '0':
498 case '1':
499 case '2':
500 case '3':
501 if (c == '\\' && tomoyo_is_byte_range(filename + 1)
502 && strncmp(filename + 1, pattern, 3) == 0) {
503 filename += 3;
504 pattern += 2;
505 break;
506 }
507 return false; /* Not matched. */
508 case '*':
509 case '@':
510 for (i = 0; i <= filename_end - filename; i++) {
511 if (tomoyo_file_matches_to_pattern2(
512 filename + i, filename_end,
513 pattern + 1, pattern_end))
514 return true;
515 c = filename[i];
516 if (c == '.' && *pattern == '@')
517 break;
518 if (c != '\\')
519 continue;
520 if (filename[i + 1] == '\\')
521 i++;
522 else if (tomoyo_is_byte_range(filename + i + 1))
523 i += 3;
524 else
525 break; /* Bad pattern. */
526 }
527 return false; /* Not matched. */
528 default:
529 j = 0;
530 c = *pattern;
531 if (c == '$') {
532 while (isdigit(filename[j]))
533 j++;
534 } else if (c == 'X') {
535 while (isxdigit(filename[j]))
536 j++;
537 } else if (c == 'A') {
538 while (tomoyo_is_alphabet_char(filename[j]))
539 j++;
540 }
541 for (i = 1; i <= j; i++) {
542 if (tomoyo_file_matches_to_pattern2(
543 filename + i, filename_end,
544 pattern + 1, pattern_end))
545 return true;
546 }
547 return false; /* Not matched or bad pattern. */
548 }
549 filename++;
550 pattern++;
551 }
552 while (*pattern == '\\' &&
553 (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
554 pattern += 2;
555 return filename == filename_end && pattern == pattern_end;
556}
557
558/**
559 * tomoyo_file_matches_to_pattern - Pattern matching without without '/' character.
560 *
561 * @filename: The start of string to check.
562 * @filename_end: The end of string to check.
563 * @pattern: The start of pattern to compare.
564 * @pattern_end: The end of pattern to compare.
565 *
566 * Returns true if @filename matches @pattern, false otherwise.
567 */
568static bool tomoyo_file_matches_to_pattern(const char *filename,
569 const char *filename_end,
570 const char *pattern,
571 const char *pattern_end)
572{
573 const char *pattern_start = pattern;
574 bool first = true;
575 bool result;
576
577 while (pattern < pattern_end - 1) {
578 /* Split at "\-" pattern. */
579 if (*pattern++ != '\\' || *pattern++ != '-')
580 continue;
581 result = tomoyo_file_matches_to_pattern2(filename,
582 filename_end,
583 pattern_start,
584 pattern - 2);
585 if (first)
586 result = !result;
587 if (result)
588 return false;
589 first = false;
590 pattern_start = pattern;
591 }
592 result = tomoyo_file_matches_to_pattern2(filename, filename_end,
593 pattern_start, pattern_end);
594 return first ? result : !result;
595}
596
597/**
598 * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
599 * @filename: The filename to check.
600 * @pattern: The pattern to compare.
601 *
602 * Returns true if matches, false otherwise.
603 *
604 * The following patterns are available.
605 * \\ \ itself.
606 * \ooo Octal representation of a byte.
607 * \* More than or equals to 0 character other than '/'.
608 * \@ More than or equals to 0 character other than '/' or '.'.
609 * \? 1 byte character other than '/'.
610 * \$ More than or equals to 1 decimal digit.
611 * \+ 1 decimal digit.
612 * \X More than or equals to 1 hexadecimal digit.
613 * \x 1 hexadecimal digit.
614 * \A More than or equals to 1 alphabet character.
615 * \a 1 alphabet character.
616 * \- Subtraction operator.
617 */
618bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
619 const struct tomoyo_path_info *pattern)
620{
621 /*
622 if (!filename || !pattern)
623 return false;
624 */
625 const char *f = filename->name;
626 const char *p = pattern->name;
627 const int len = pattern->const_len;
628
629 /* If @pattern doesn't contain pattern, I can use strcmp(). */
630 if (!pattern->is_patterned)
631 return !tomoyo_pathcmp(filename, pattern);
632 /* Dont compare if the number of '/' differs. */
633 if (filename->depth != pattern->depth)
634 return false;
635 /* Compare the initial length without patterns. */
636 if (strncmp(f, p, len))
637 return false;
638 f += len;
639 p += len;
640 /* Main loop. Compare each directory component. */
641 while (*f && *p) {
642 const char *f_delimiter = strchr(f, '/');
643 const char *p_delimiter = strchr(p, '/');
644 if (!f_delimiter)
645 f_delimiter = f + strlen(f);
646 if (!p_delimiter)
647 p_delimiter = p + strlen(p);
648 if (!tomoyo_file_matches_to_pattern(f, f_delimiter,
649 p, p_delimiter))
650 return false;
651 f = f_delimiter;
652 if (*f)
653 f++;
654 p = p_delimiter;
655 if (*p)
656 p++;
657 }
658 /* Ignore trailing "\*" and "\@" in @pattern. */
659 while (*p == '\\' &&
660 (*(p + 1) == '*' || *(p + 1) == '@'))
661 p += 2;
662 return !*f && !*p;
663}
664
665/**
666 * tomoyo_io_printf - Transactional printf() to "struct tomoyo_io_buffer" structure.
667 *
668 * @head: Pointer to "struct tomoyo_io_buffer".
669 * @fmt: The printf()'s format string, followed by parameters.
670 *
671 * Returns true if output was written, false otherwise.
672 *
673 * The snprintf() will truncate, but tomoyo_io_printf() won't.
674 */
675bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
676{
677 va_list args;
678 int len;
679 int pos = head->read_avail;
680 int size = head->readbuf_size - pos;
681
682 if (size <= 0)
683 return false;
684 va_start(args, fmt);
685 len = vsnprintf(head->read_buf + pos, size, fmt, args);
686 va_end(args);
687 if (pos + len >= head->readbuf_size)
688 return false;
689 head->read_avail += len;
690 return true;
691}
692
693/**
694 * tomoyo_get_exe - Get tomoyo_realpath() of current process.
695 *
696 * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
697 *
698 * This function uses tomoyo_alloc(), so the caller must call tomoyo_free()
699 * if this function didn't return NULL.
700 */
701static const char *tomoyo_get_exe(void)
702{
703 struct mm_struct *mm = current->mm;
704 struct vm_area_struct *vma;
705 const char *cp = NULL;
706
707 if (!mm)
708 return NULL;
709 down_read(&mm->mmap_sem);
710 for (vma = mm->mmap; vma; vma = vma->vm_next) {
711 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
712 cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
713 break;
714 }
715 }
716 up_read(&mm->mmap_sem);
717 return cp;
718}
719
720/**
721 * tomoyo_get_msg - Get warning message.
722 *
723 * @is_enforce: Is it enforcing mode?
724 *
725 * Returns "ERROR" or "WARNING".
726 */
727const char *tomoyo_get_msg(const bool is_enforce)
728{
729 if (is_enforce)
730 return "ERROR";
731 else
732 return "WARNING";
733}
734
735/**
736 * tomoyo_check_flags - Check mode for specified functionality.
737 *
738 * @domain: Pointer to "struct tomoyo_domain_info".
739 * @index: The functionality to check mode.
740 *
741 * TOMOYO checks only process context.
742 * This code disables TOMOYO's enforcement in case the function is called from
743 * interrupt context.
744 */
745unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
746 const u8 index)
747{
748 const u8 profile = domain->profile;
749
750 if (WARN_ON(in_interrupt()))
751 return 0;
752 return tomoyo_policy_loaded && index < TOMOYO_MAX_CONTROL_INDEX
753#if TOMOYO_MAX_PROFILES != 256
754 && profile < TOMOYO_MAX_PROFILES
755#endif
756 && tomoyo_profile_ptr[profile] ?
757 tomoyo_profile_ptr[profile]->value[index] : 0;
758}
759
760/**
761 * tomoyo_verbose_mode - Check whether TOMOYO is verbose mode.
762 *
763 * @domain: Pointer to "struct tomoyo_domain_info".
764 *
765 * Returns true if domain policy violation warning should be printed to
766 * console.
767 */
768bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
769{
770 return tomoyo_check_flags(domain, TOMOYO_VERBOSE) != 0;
771}
772
773/**
774 * tomoyo_domain_quota_is_ok - Check for domain's quota.
775 *
776 * @domain: Pointer to "struct tomoyo_domain_info".
777 *
778 * Returns true if the domain is not exceeded quota, false otherwise.
779 */
780bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
781{
782 unsigned int count = 0;
783 struct tomoyo_acl_info *ptr;
784
785 if (!domain)
786 return true;
787 down_read(&tomoyo_domain_acl_info_list_lock);
788 list_for_each_entry(ptr, &domain->acl_info_list, list) {
789 if (ptr->type & TOMOYO_ACL_DELETED)
790 continue;
791 switch (tomoyo_acl_type2(ptr)) {
792 struct tomoyo_single_path_acl_record *acl1;
793 struct tomoyo_double_path_acl_record *acl2;
794 u16 perm;
795 case TOMOYO_TYPE_SINGLE_PATH_ACL:
796 acl1 = container_of(ptr,
797 struct tomoyo_single_path_acl_record,
798 head);
799 perm = acl1->perm;
800 if (perm & (1 << TOMOYO_TYPE_EXECUTE_ACL))
801 count++;
802 if (perm &
803 ((1 << TOMOYO_TYPE_READ_ACL) |
804 (1 << TOMOYO_TYPE_WRITE_ACL)))
805 count++;
806 if (perm & (1 << TOMOYO_TYPE_CREATE_ACL))
807 count++;
808 if (perm & (1 << TOMOYO_TYPE_UNLINK_ACL))
809 count++;
810 if (perm & (1 << TOMOYO_TYPE_MKDIR_ACL))
811 count++;
812 if (perm & (1 << TOMOYO_TYPE_RMDIR_ACL))
813 count++;
814 if (perm & (1 << TOMOYO_TYPE_MKFIFO_ACL))
815 count++;
816 if (perm & (1 << TOMOYO_TYPE_MKSOCK_ACL))
817 count++;
818 if (perm & (1 << TOMOYO_TYPE_MKBLOCK_ACL))
819 count++;
820 if (perm & (1 << TOMOYO_TYPE_MKCHAR_ACL))
821 count++;
822 if (perm & (1 << TOMOYO_TYPE_TRUNCATE_ACL))
823 count++;
824 if (perm & (1 << TOMOYO_TYPE_SYMLINK_ACL))
825 count++;
826 if (perm & (1 << TOMOYO_TYPE_REWRITE_ACL))
827 count++;
828 break;
829 case TOMOYO_TYPE_DOUBLE_PATH_ACL:
830 acl2 = container_of(ptr,
831 struct tomoyo_double_path_acl_record,
832 head);
833 perm = acl2->perm;
834 if (perm & (1 << TOMOYO_TYPE_LINK_ACL))
835 count++;
836 if (perm & (1 << TOMOYO_TYPE_RENAME_ACL))
837 count++;
838 break;
839 }
840 }
841 up_read(&tomoyo_domain_acl_info_list_lock);
842 if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
843 return true;
844 if (!domain->quota_warned) {
845 domain->quota_warned = true;
846 printk(KERN_WARNING "TOMOYO-WARNING: "
847 "Domain '%s' has so many ACLs to hold. "
848 "Stopped learning mode.\n", domain->domainname->name);
849 }
850 return false;
851}
852
853/**
854 * tomoyo_find_or_assign_new_profile - Create a new profile.
855 *
856 * @profile: Profile number to create.
857 *
858 * Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
859 */
860static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
861 int profile)
862{
863 static DEFINE_MUTEX(lock);
864 struct tomoyo_profile *ptr = NULL;
865 int i;
866
867 if (profile >= TOMOYO_MAX_PROFILES)
868 return NULL;
869 /***** EXCLUSIVE SECTION START *****/
870 mutex_lock(&lock);
871 ptr = tomoyo_profile_ptr[profile];
872 if (ptr)
873 goto ok;
874 ptr = tomoyo_alloc_element(sizeof(*ptr));
875 if (!ptr)
876 goto ok;
877 for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
878 ptr->value[i] = tomoyo_control_array[i].current_value;
879 mb(); /* Avoid out-of-order execution. */
880 tomoyo_profile_ptr[profile] = ptr;
881 ok:
882 mutex_unlock(&lock);
883 /***** EXCLUSIVE SECTION END *****/
884 return ptr;
885}
886
887/**
888 * tomoyo_write_profile - Write to profile table.
889 *
890 * @head: Pointer to "struct tomoyo_io_buffer".
891 *
892 * Returns 0 on success, negative value otherwise.
893 */
894static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
895{
896 char *data = head->write_buf;
897 unsigned int i;
898 unsigned int value;
899 char *cp;
900 struct tomoyo_profile *profile;
901 unsigned long num;
902
903 cp = strchr(data, '-');
904 if (cp)
905 *cp = '\0';
906 if (strict_strtoul(data, 10, &num))
907 return -EINVAL;
908 if (cp)
909 data = cp + 1;
910 profile = tomoyo_find_or_assign_new_profile(num);
911 if (!profile)
912 return -EINVAL;
913 cp = strchr(data, '=');
914 if (!cp)
915 return -EINVAL;
916 *cp = '\0';
917 if (!strcmp(data, "COMMENT")) {
918 profile->comment = tomoyo_save_name(cp + 1);
919 return 0;
920 }
921 for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
922 if (strcmp(data, tomoyo_control_array[i].keyword))
923 continue;
924 if (sscanf(cp + 1, "%u", &value) != 1) {
925 int j;
926 const char **modes;
927 switch (i) {
928 case TOMOYO_VERBOSE:
929 modes = tomoyo_mode_2;
930 break;
931 default:
932 modes = tomoyo_mode_4;
933 break;
934 }
935 for (j = 0; j < 4; j++) {
936 if (strcmp(cp + 1, modes[j]))
937 continue;
938 value = j;
939 break;
940 }
941 if (j == 4)
942 return -EINVAL;
943 } else if (value > tomoyo_control_array[i].max_value) {
944 value = tomoyo_control_array[i].max_value;
945 }
946 profile->value[i] = value;
947 return 0;
948 }
949 return -EINVAL;
950}
951
952/**
953 * tomoyo_read_profile - Read from profile table.
954 *
955 * @head: Pointer to "struct tomoyo_io_buffer".
956 *
957 * Returns 0.
958 */
959static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
960{
961 static const int total = TOMOYO_MAX_CONTROL_INDEX + 1;
962 int step;
963
964 if (head->read_eof)
965 return 0;
966 for (step = head->read_step; step < TOMOYO_MAX_PROFILES * total;
967 step++) {
968 const u8 index = step / total;
969 u8 type = step % total;
970 const struct tomoyo_profile *profile
971 = tomoyo_profile_ptr[index];
972 head->read_step = step;
973 if (!profile)
974 continue;
975 if (!type) { /* Print profile' comment tag. */
976 if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
977 index, profile->comment ?
978 profile->comment->name : ""))
979 break;
980 continue;
981 }
982 type--;
983 if (type < TOMOYO_MAX_CONTROL_INDEX) {
984 const unsigned int value = profile->value[type];
985 const char **modes = NULL;
986 const char *keyword
987 = tomoyo_control_array[type].keyword;
988 switch (tomoyo_control_array[type].max_value) {
989 case 3:
990 modes = tomoyo_mode_4;
991 break;
992 case 1:
993 modes = tomoyo_mode_2;
994 break;
995 }
996 if (modes) {
997 if (!tomoyo_io_printf(head, "%u-%s=%s\n", index,
998 keyword, modes[value]))
999 break;
1000 } else {
1001 if (!tomoyo_io_printf(head, "%u-%s=%u\n", index,
1002 keyword, value))
1003 break;
1004 }
1005 }
1006 }
1007 if (step == TOMOYO_MAX_PROFILES * total)
1008 head->read_eof = true;
1009 return 0;
1010}
1011
1012/* Structure for policy manager. */
1013struct tomoyo_policy_manager_entry {
1014 struct list_head list;
1015 /* A path to program or a domainname. */
1016 const struct tomoyo_path_info *manager;
1017 bool is_domain; /* True if manager is a domainname. */
1018 bool is_deleted; /* True if this entry is deleted. */
1019};
1020
1021/* The list for "struct tomoyo_policy_manager_entry". */
1022static LIST_HEAD(tomoyo_policy_manager_list);
1023static DECLARE_RWSEM(tomoyo_policy_manager_list_lock);
1024
1025/**
1026 * tomoyo_update_manager_entry - Add a manager entry.
1027 *
1028 * @manager: The path to manager or the domainnamme.
1029 * @is_delete: True if it is a delete request.
1030 *
1031 * Returns 0 on success, negative value otherwise.
1032 */
1033static int tomoyo_update_manager_entry(const char *manager,
1034 const bool is_delete)
1035{
1036 struct tomoyo_policy_manager_entry *new_entry;
1037 struct tomoyo_policy_manager_entry *ptr;
1038 const struct tomoyo_path_info *saved_manager;
1039 int error = -ENOMEM;
1040 bool is_domain = false;
1041
1042 if (tomoyo_is_domain_def(manager)) {
1043 if (!tomoyo_is_correct_domain(manager, __func__))
1044 return -EINVAL;
1045 is_domain = true;
1046 } else {
1047 if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__))
1048 return -EINVAL;
1049 }
1050 saved_manager = tomoyo_save_name(manager);
1051 if (!saved_manager)
1052 return -ENOMEM;
1053 /***** EXCLUSIVE SECTION START *****/
1054 down_write(&tomoyo_policy_manager_list_lock);
1055 list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
1056 if (ptr->manager != saved_manager)
1057 continue;
1058 ptr->is_deleted = is_delete;
1059 error = 0;
1060 goto out;
1061 }
1062 if (is_delete) {
1063 error = -ENOENT;
1064 goto out;
1065 }
1066 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
1067 if (!new_entry)
1068 goto out;
1069 new_entry->manager = saved_manager;
1070 new_entry->is_domain = is_domain;
1071 list_add_tail(&new_entry->list, &tomoyo_policy_manager_list);
1072 error = 0;
1073 out:
1074 up_write(&tomoyo_policy_manager_list_lock);
1075 /***** EXCLUSIVE SECTION END *****/
1076 return error;
1077}
1078
1079/**
1080 * tomoyo_write_manager_policy - Write manager policy.
1081 *
1082 * @head: Pointer to "struct tomoyo_io_buffer".
1083 *
1084 * Returns 0 on success, negative value otherwise.
1085 */
1086static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head)
1087{
1088 char *data = head->write_buf;
1089 bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
1090
1091 if (!strcmp(data, "manage_by_non_root")) {
1092 tomoyo_manage_by_non_root = !is_delete;
1093 return 0;
1094 }
1095 return tomoyo_update_manager_entry(data, is_delete);
1096}
1097
1098/**
1099 * tomoyo_read_manager_policy - Read manager policy.
1100 *
1101 * @head: Pointer to "struct tomoyo_io_buffer".
1102 *
1103 * Returns 0.
1104 */
1105static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head)
1106{
1107 struct list_head *pos;
1108 bool done = true;
1109
1110 if (head->read_eof)
1111 return 0;
1112 down_read(&tomoyo_policy_manager_list_lock);
1113 list_for_each_cookie(pos, head->read_var2,
1114 &tomoyo_policy_manager_list) {
1115 struct tomoyo_policy_manager_entry *ptr;
1116 ptr = list_entry(pos, struct tomoyo_policy_manager_entry,
1117 list);
1118 if (ptr->is_deleted)
1119 continue;
1120 if (!tomoyo_io_printf(head, "%s\n", ptr->manager->name)) {
1121 done = false;
1122 break;
1123 }
1124 }
1125 up_read(&tomoyo_policy_manager_list_lock);
1126 head->read_eof = done;
1127 return 0;
1128}
1129
1130/**
1131 * tomoyo_is_policy_manager - Check whether the current process is a policy manager.
1132 *
1133 * Returns true if the current process is permitted to modify policy
1134 * via /sys/kernel/security/tomoyo/ interface.
1135 */
1136static bool tomoyo_is_policy_manager(void)
1137{
1138 struct tomoyo_policy_manager_entry *ptr;
1139 const char *exe;
1140 const struct task_struct *task = current;
1141 const struct tomoyo_path_info *domainname = tomoyo_domain()->domainname;
1142 bool found = false;
1143
1144 if (!tomoyo_policy_loaded)
1145 return true;
1146 if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid))
1147 return false;
1148 down_read(&tomoyo_policy_manager_list_lock);
1149 list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
1150 if (!ptr->is_deleted && ptr->is_domain
1151 && !tomoyo_pathcmp(domainname, ptr->manager)) {
1152 found = true;
1153 break;
1154 }
1155 }
1156 up_read(&tomoyo_policy_manager_list_lock);
1157 if (found)
1158 return true;
1159 exe = tomoyo_get_exe();
1160 if (!exe)
1161 return false;
1162 down_read(&tomoyo_policy_manager_list_lock);
1163 list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) {
1164 if (!ptr->is_deleted && !ptr->is_domain
1165 && !strcmp(exe, ptr->manager->name)) {
1166 found = true;
1167 break;
1168 }
1169 }
1170 up_read(&tomoyo_policy_manager_list_lock);
1171 if (!found) { /* Reduce error messages. */
1172 static pid_t last_pid;
1173 const pid_t pid = current->pid;
1174 if (last_pid != pid) {
1175 printk(KERN_WARNING "%s ( %s ) is not permitted to "
1176 "update policies.\n", domainname->name, exe);
1177 last_pid = pid;
1178 }
1179 }
1180 tomoyo_free(exe);
1181 return found;
1182}
1183
1184/**
1185 * tomoyo_is_select_one - Parse select command.
1186 *
1187 * @head: Pointer to "struct tomoyo_io_buffer".
1188 * @data: String to parse.
1189 *
1190 * Returns true on success, false otherwise.
1191 */
1192static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
1193 const char *data)
1194{
1195 unsigned int pid;
1196 struct tomoyo_domain_info *domain = NULL;
1197
1198 if (sscanf(data, "pid=%u", &pid) == 1) {
1199 struct task_struct *p;
1200 /***** CRITICAL SECTION START *****/
1201 read_lock(&tasklist_lock);
1202 p = find_task_by_vpid(pid);
1203 if (p)
1204 domain = tomoyo_real_domain(p);
1205 read_unlock(&tasklist_lock);
1206 /***** CRITICAL SECTION END *****/
1207 } else if (!strncmp(data, "domain=", 7)) {
1208 if (tomoyo_is_domain_def(data + 7)) {
1209 down_read(&tomoyo_domain_list_lock);
1210 domain = tomoyo_find_domain(data + 7);
1211 up_read(&tomoyo_domain_list_lock);
1212 }
1213 } else
1214 return false;
1215 head->write_var1 = domain;
1216 /* Accessing read_buf is safe because head->io_sem is held. */
1217 if (!head->read_buf)
1218 return true; /* Do nothing if open(O_WRONLY). */
1219 head->read_avail = 0;
1220 tomoyo_io_printf(head, "# select %s\n", data);
1221 head->read_single_domain = true;
1222 head->read_eof = !domain;
1223 if (domain) {
1224 struct tomoyo_domain_info *d;
1225 head->read_var1 = NULL;
1226 down_read(&tomoyo_domain_list_lock);
1227 list_for_each_entry(d, &tomoyo_domain_list, list) {
1228 if (d == domain)
1229 break;
1230 head->read_var1 = &d->list;
1231 }
1232 up_read(&tomoyo_domain_list_lock);
1233 head->read_var2 = NULL;
1234 head->read_bit = 0;
1235 head->read_step = 0;
1236 if (domain->is_deleted)
1237 tomoyo_io_printf(head, "# This is a deleted domain.\n");
1238 }
1239 return true;
1240}
1241
1242/**
1243 * tomoyo_write_domain_policy - Write domain policy.
1244 *
1245 * @head: Pointer to "struct tomoyo_io_buffer".
1246 *
1247 * Returns 0 on success, negative value otherwise.
1248 */
1249static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
1250{
1251 char *data = head->write_buf;
1252 struct tomoyo_domain_info *domain = head->write_var1;
1253 bool is_delete = false;
1254 bool is_select = false;
1255 bool is_undelete = false;
1256 unsigned int profile;
1257
1258 if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE))
1259 is_delete = true;
1260 else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_SELECT))
1261 is_select = true;
1262 else if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_UNDELETE))
1263 is_undelete = true;
1264 if (is_select && tomoyo_is_select_one(head, data))
1265 return 0;
1266 /* Don't allow updating policies by non manager programs. */
1267 if (!tomoyo_is_policy_manager())
1268 return -EPERM;
1269 if (tomoyo_is_domain_def(data)) {
1270 domain = NULL;
1271 if (is_delete)
1272 tomoyo_delete_domain(data);
1273 else if (is_select) {
1274 down_read(&tomoyo_domain_list_lock);
1275 domain = tomoyo_find_domain(data);
1276 up_read(&tomoyo_domain_list_lock);
1277 } else if (is_undelete)
1278 domain = tomoyo_undelete_domain(data);
1279 else
1280 domain = tomoyo_find_or_assign_new_domain(data, 0);
1281 head->write_var1 = domain;
1282 return 0;
1283 }
1284 if (!domain)
1285 return -EINVAL;
1286
1287 if (sscanf(data, TOMOYO_KEYWORD_USE_PROFILE "%u", &profile) == 1
1288 && profile < TOMOYO_MAX_PROFILES) {
1289 if (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded)
1290 domain->profile = (u8) profile;
1291 return 0;
1292 }
1293 if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
1294 tomoyo_set_domain_flag(domain, is_delete,
1295 TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
1296 return 0;
1297 }
1298 return tomoyo_write_file_policy(data, domain, is_delete);
1299}
1300
1301/**
1302 * tomoyo_print_single_path_acl - Print a single path ACL entry.
1303 *
1304 * @head: Pointer to "struct tomoyo_io_buffer".
1305 * @ptr: Pointer to "struct tomoyo_single_path_acl_record".
1306 *
1307 * Returns true on success, false otherwise.
1308 */
1309static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head,
1310 struct tomoyo_single_path_acl_record *
1311 ptr)
1312{
1313 int pos;
1314 u8 bit;
1315 const char *atmark = "";
1316 const char *filename;
1317 const u16 perm = ptr->perm;
1318
1319 filename = ptr->filename->name;
1320 for (bit = head->read_bit; bit < TOMOYO_MAX_SINGLE_PATH_OPERATION;
1321 bit++) {
1322 const char *msg;
1323 if (!(perm & (1 << bit)))
1324 continue;
1325 /* Print "read/write" instead of "read" and "write". */
1326 if ((bit == TOMOYO_TYPE_READ_ACL ||
1327 bit == TOMOYO_TYPE_WRITE_ACL)
1328 && (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)))
1329 continue;
1330 msg = tomoyo_sp2keyword(bit);
1331 pos = head->read_avail;
1332 if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg,
1333 atmark, filename))
1334 goto out;
1335 }
1336 head->read_bit = 0;
1337 return true;
1338 out:
1339 head->read_bit = bit;
1340 head->read_avail = pos;
1341 return false;
1342}
1343
1344/**
1345 * tomoyo_print_double_path_acl - Print a double path ACL entry.
1346 *
1347 * @head: Pointer to "struct tomoyo_io_buffer".
1348 * @ptr: Pointer to "struct tomoyo_double_path_acl_record".
1349 *
1350 * Returns true on success, false otherwise.
1351 */
1352static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head,
1353 struct tomoyo_double_path_acl_record *
1354 ptr)
1355{
1356 int pos;
1357 const char *atmark1 = "";
1358 const char *atmark2 = "";
1359 const char *filename1;
1360 const char *filename2;
1361 const u8 perm = ptr->perm;
1362 u8 bit;
1363
1364 filename1 = ptr->filename1->name;
1365 filename2 = ptr->filename2->name;
1366 for (bit = head->read_bit; bit < TOMOYO_MAX_DOUBLE_PATH_OPERATION;
1367 bit++) {
1368 const char *msg;
1369 if (!(perm & (1 << bit)))
1370 continue;
1371 msg = tomoyo_dp2keyword(bit);
1372 pos = head->read_avail;
1373 if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg,
1374 atmark1, filename1, atmark2, filename2))
1375 goto out;
1376 }
1377 head->read_bit = 0;
1378 return true;
1379 out:
1380 head->read_bit = bit;
1381 head->read_avail = pos;
1382 return false;
1383}
1384
1385/**
1386 * tomoyo_print_entry - Print an ACL entry.
1387 *
1388 * @head: Pointer to "struct tomoyo_io_buffer".
1389 * @ptr: Pointer to an ACL entry.
1390 *
1391 * Returns true on success, false otherwise.
1392 */
1393static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
1394 struct tomoyo_acl_info *ptr)
1395{
1396 const u8 acl_type = tomoyo_acl_type2(ptr);
1397
1398 if (acl_type & TOMOYO_ACL_DELETED)
1399 return true;
1400 if (acl_type == TOMOYO_TYPE_SINGLE_PATH_ACL) {
1401 struct tomoyo_single_path_acl_record *acl
1402 = container_of(ptr,
1403 struct tomoyo_single_path_acl_record,
1404 head);
1405 return tomoyo_print_single_path_acl(head, acl);
1406 }
1407 if (acl_type == TOMOYO_TYPE_DOUBLE_PATH_ACL) {
1408 struct tomoyo_double_path_acl_record *acl
1409 = container_of(ptr,
1410 struct tomoyo_double_path_acl_record,
1411 head);
1412 return tomoyo_print_double_path_acl(head, acl);
1413 }
1414 BUG(); /* This must not happen. */
1415 return false;
1416}
1417
1418/**
1419 * tomoyo_read_domain_policy - Read domain policy.
1420 *
1421 * @head: Pointer to "struct tomoyo_io_buffer".
1422 *
1423 * Returns 0.
1424 */
1425static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head)
1426{
1427 struct list_head *dpos;
1428 struct list_head *apos;
1429 bool done = true;
1430
1431 if (head->read_eof)
1432 return 0;
1433 if (head->read_step == 0)
1434 head->read_step = 1;
1435 down_read(&tomoyo_domain_list_lock);
1436 list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) {
1437 struct tomoyo_domain_info *domain;
1438 const char *quota_exceeded = "";
1439 const char *transition_failed = "";
1440 const char *ignore_global_allow_read = "";
1441 domain = list_entry(dpos, struct tomoyo_domain_info, list);
1442 if (head->read_step != 1)
1443 goto acl_loop;
1444 if (domain->is_deleted && !head->read_single_domain)
1445 continue;
1446 /* Print domainname and flags. */
1447 if (domain->quota_warned)
1448 quota_exceeded = "quota_exceeded\n";
1449 if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED)
1450 transition_failed = "transition_failed\n";
1451 if (domain->flags &
1452 TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ)
1453 ignore_global_allow_read
1454 = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
1455 if (!tomoyo_io_printf(head,
1456 "%s\n" TOMOYO_KEYWORD_USE_PROFILE "%u\n"
1457 "%s%s%s\n", domain->domainname->name,
1458 domain->profile, quota_exceeded,
1459 transition_failed,
1460 ignore_global_allow_read)) {
1461 done = false;
1462 break;
1463 }
1464 head->read_step = 2;
1465acl_loop:
1466 if (head->read_step == 3)
1467 goto tail_mark;
1468 /* Print ACL entries in the domain. */
1469 down_read(&tomoyo_domain_acl_info_list_lock);
1470 list_for_each_cookie(apos, head->read_var2,
1471 &domain->acl_info_list) {
1472 struct tomoyo_acl_info *ptr
1473 = list_entry(apos, struct tomoyo_acl_info,
1474 list);
1475 if (!tomoyo_print_entry(head, ptr)) {
1476 done = false;
1477 break;
1478 }
1479 }
1480 up_read(&tomoyo_domain_acl_info_list_lock);
1481 if (!done)
1482 break;
1483 head->read_step = 3;
1484tail_mark:
1485 if (!tomoyo_io_printf(head, "\n")) {
1486 done = false;
1487 break;
1488 }
1489 head->read_step = 1;
1490 if (head->read_single_domain)
1491 break;
1492 }
1493 up_read(&tomoyo_domain_list_lock);
1494 head->read_eof = done;
1495 return 0;
1496}
1497
1498/**
1499 * tomoyo_write_domain_profile - Assign profile for specified domain.
1500 *
1501 * @head: Pointer to "struct tomoyo_io_buffer".
1502 *
1503 * Returns 0 on success, -EINVAL otherwise.
1504 *
1505 * This is equivalent to doing
1506 *
1507 * ( echo "select " $domainname; echo "use_profile " $profile ) |
1508 * /usr/lib/ccs/loadpolicy -d
1509 */
1510static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head)
1511{
1512 char *data = head->write_buf;
1513 char *cp = strchr(data, ' ');
1514 struct tomoyo_domain_info *domain;
1515 unsigned long profile;
1516
1517 if (!cp)
1518 return -EINVAL;
1519 *cp = '\0';
1520 down_read(&tomoyo_domain_list_lock);
1521 domain = tomoyo_find_domain(cp + 1);
1522 up_read(&tomoyo_domain_list_lock);
1523 if (strict_strtoul(data, 10, &profile))
1524 return -EINVAL;
1525 if (domain && profile < TOMOYO_MAX_PROFILES
1526 && (tomoyo_profile_ptr[profile] || !tomoyo_policy_loaded))
1527 domain->profile = (u8) profile;
1528 return 0;
1529}
1530
1531/**
1532 * tomoyo_read_domain_profile - Read only domainname and profile.
1533 *
1534 * @head: Pointer to "struct tomoyo_io_buffer".
1535 *
1536 * Returns list of profile number and domainname pairs.
1537 *
1538 * This is equivalent to doing
1539 *
1540 * grep -A 1 '^<kernel>' /sys/kernel/security/tomoyo/domain_policy |
1541 * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
1542 * domainname = $0; } else if ( $1 == "use_profile" ) {
1543 * print $2 " " domainname; domainname = ""; } } ; '
1544 */
1545static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head)
1546{
1547 struct list_head *pos;
1548 bool done = true;
1549
1550 if (head->read_eof)
1551 return 0;
1552 down_read(&tomoyo_domain_list_lock);
1553 list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) {
1554 struct tomoyo_domain_info *domain;
1555 domain = list_entry(pos, struct tomoyo_domain_info, list);
1556 if (domain->is_deleted)
1557 continue;
1558 if (!tomoyo_io_printf(head, "%u %s\n", domain->profile,
1559 domain->domainname->name)) {
1560 done = false;
1561 break;
1562 }
1563 }
1564 up_read(&tomoyo_domain_list_lock);
1565 head->read_eof = done;
1566 return 0;
1567}
1568
1569/**
1570 * tomoyo_write_pid: Specify PID to obtain domainname.
1571 *
1572 * @head: Pointer to "struct tomoyo_io_buffer".
1573 *
1574 * Returns 0.
1575 */
1576static int tomoyo_write_pid(struct tomoyo_io_buffer *head)
1577{
1578 unsigned long pid;
1579 /* No error check. */
1580 strict_strtoul(head->write_buf, 10, &pid);
1581 head->read_step = (int) pid;
1582 head->read_eof = false;
1583 return 0;
1584}
1585
1586/**
1587 * tomoyo_read_pid - Get domainname of the specified PID.
1588 *
1589 * @head: Pointer to "struct tomoyo_io_buffer".
1590 *
1591 * Returns the domainname which the specified PID is in on success,
1592 * empty string otherwise.
1593 * The PID is specified by tomoyo_write_pid() so that the user can obtain
1594 * using read()/write() interface rather than sysctl() interface.
1595 */
1596static int tomoyo_read_pid(struct tomoyo_io_buffer *head)
1597{
1598 if (head->read_avail == 0 && !head->read_eof) {
1599 const int pid = head->read_step;
1600 struct task_struct *p;
1601 struct tomoyo_domain_info *domain = NULL;
1602 /***** CRITICAL SECTION START *****/
1603 read_lock(&tasklist_lock);
1604 p = find_task_by_vpid(pid);
1605 if (p)
1606 domain = tomoyo_real_domain(p);
1607 read_unlock(&tasklist_lock);
1608 /***** CRITICAL SECTION END *****/
1609 if (domain)
1610 tomoyo_io_printf(head, "%d %u %s", pid, domain->profile,
1611 domain->domainname->name);
1612 head->read_eof = true;
1613 }
1614 return 0;
1615}
1616
1617/**
1618 * tomoyo_write_exception_policy - Write exception policy.
1619 *
1620 * @head: Pointer to "struct tomoyo_io_buffer".
1621 *
1622 * Returns 0 on success, negative value otherwise.
1623 */
1624static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
1625{
1626 char *data = head->write_buf;
1627 bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE);
1628
1629 if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN))
1630 return tomoyo_write_domain_keeper_policy(data, false,
1631 is_delete);
1632 if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN))
1633 return tomoyo_write_domain_keeper_policy(data, true, is_delete);
1634 if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN))
1635 return tomoyo_write_domain_initializer_policy(data, false,
1636 is_delete);
1637 if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN))
1638 return tomoyo_write_domain_initializer_policy(data, true,
1639 is_delete);
1640 if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS))
1641 return tomoyo_write_alias_policy(data, is_delete);
1642 if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ))
1643 return tomoyo_write_globally_readable_policy(data, is_delete);
1644 if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_FILE_PATTERN))
1645 return tomoyo_write_pattern_policy(data, is_delete);
1646 if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE))
1647 return tomoyo_write_no_rewrite_policy(data, is_delete);
1648 return -EINVAL;
1649}
1650
1651/**
1652 * tomoyo_read_exception_policy - Read exception policy.
1653 *
1654 * @head: Pointer to "struct tomoyo_io_buffer".
1655 *
1656 * Returns 0 on success, -EINVAL otherwise.
1657 */
1658static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
1659{
1660 if (!head->read_eof) {
1661 switch (head->read_step) {
1662 case 0:
1663 head->read_var2 = NULL;
1664 head->read_step = 1;
1665 case 1:
1666 if (!tomoyo_read_domain_keeper_policy(head))
1667 break;
1668 head->read_var2 = NULL;
1669 head->read_step = 2;
1670 case 2:
1671 if (!tomoyo_read_globally_readable_policy(head))
1672 break;
1673 head->read_var2 = NULL;
1674 head->read_step = 3;
1675 case 3:
1676 head->read_var2 = NULL;
1677 head->read_step = 4;
1678 case 4:
1679 if (!tomoyo_read_domain_initializer_policy(head))
1680 break;
1681 head->read_var2 = NULL;
1682 head->read_step = 5;
1683 case 5:
1684 if (!tomoyo_read_alias_policy(head))
1685 break;
1686 head->read_var2 = NULL;
1687 head->read_step = 6;
1688 case 6:
1689 head->read_var2 = NULL;
1690 head->read_step = 7;
1691 case 7:
1692 if (!tomoyo_read_file_pattern(head))
1693 break;
1694 head->read_var2 = NULL;
1695 head->read_step = 8;
1696 case 8:
1697 if (!tomoyo_read_no_rewrite_policy(head))
1698 break;
1699 head->read_var2 = NULL;
1700 head->read_step = 9;
1701 case 9:
1702 head->read_eof = true;
1703 break;
1704 default:
1705 return -EINVAL;
1706 }
1707 }
1708 return 0;
1709}
1710
1711/* path to policy loader */
1712static const char *tomoyo_loader = "/sbin/tomoyo-init";
1713
1714/**
1715 * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
1716 *
1717 * Returns true if /sbin/tomoyo-init exists, false otherwise.
1718 */
1719static bool tomoyo_policy_loader_exists(void)
1720{
1721 /*
1722 * Don't activate MAC if the policy loader doesn't exist.
1723 * If the initrd includes /sbin/init but real-root-dev has not
1724 * mounted on / yet, activating MAC will block the system since
1725 * policies are not loaded yet.
1726 * Thus, let do_execve() call this function everytime.
1727 */
1728 struct nameidata nd;
1729
1730 if (path_lookup(tomoyo_loader, LOOKUP_FOLLOW, &nd)) {
1731 printk(KERN_INFO "Not activating Mandatory Access Control now "
1732 "since %s doesn't exist.\n", tomoyo_loader);
1733 return false;
1734 }
1735 path_put(&nd.path);
1736 return true;
1737}
1738
1739/**
1740 * tomoyo_load_policy - Run external policy loader to load policy.
1741 *
1742 * @filename: The program about to start.
1743 *
1744 * This function checks whether @filename is /sbin/init , and if so
1745 * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
1746 * and then continues invocation of /sbin/init.
1747 * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
1748 * writes to /sys/kernel/security/tomoyo/ interfaces.
1749 *
1750 * Returns nothing.
1751 */
1752void tomoyo_load_policy(const char *filename)
1753{
1754 char *argv[2];
1755 char *envp[3];
1756
1757 if (tomoyo_policy_loaded)
1758 return;
1759 /*
1760 * Check filename is /sbin/init or /sbin/tomoyo-start.
1761 * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
1762 * be passed.
1763 * You can create /sbin/tomoyo-start by
1764 * "ln -s /bin/true /sbin/tomoyo-start".
1765 */
1766 if (strcmp(filename, "/sbin/init") &&
1767 strcmp(filename, "/sbin/tomoyo-start"))
1768 return;
1769 if (!tomoyo_policy_loader_exists())
1770 return;
1771
1772 printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
1773 tomoyo_loader);
1774 argv[0] = (char *) tomoyo_loader;
1775 argv[1] = NULL;
1776 envp[0] = "HOME=/";
1777 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
1778 envp[2] = NULL;
1779 call_usermodehelper(argv[0], argv, envp, 1);
1780
1781 printk(KERN_INFO "TOMOYO: 2.2.0-pre 2009/02/01\n");
1782 printk(KERN_INFO "Mandatory Access Control activated.\n");
1783 tomoyo_policy_loaded = true;
1784 { /* Check all profiles currently assigned to domains are defined. */
1785 struct tomoyo_domain_info *domain;
1786 down_read(&tomoyo_domain_list_lock);
1787 list_for_each_entry(domain, &tomoyo_domain_list, list) {
1788 const u8 profile = domain->profile;
1789 if (tomoyo_profile_ptr[profile])
1790 continue;
1791 panic("Profile %u (used by '%s') not defined.\n",
1792 profile, domain->domainname->name);
1793 }
1794 up_read(&tomoyo_domain_list_lock);
1795 }
1796}
1797
1798/**
1799 * tomoyo_read_version: Get version.
1800 *
1801 * @head: Pointer to "struct tomoyo_io_buffer".
1802 *
1803 * Returns version information.
1804 */
1805static int tomoyo_read_version(struct tomoyo_io_buffer *head)
1806{
1807 if (!head->read_eof) {
1808 tomoyo_io_printf(head, "2.2.0-pre");
1809 head->read_eof = true;
1810 }
1811 return 0;
1812}
1813
1814/**
1815 * tomoyo_read_self_domain - Get the current process's domainname.
1816 *
1817 * @head: Pointer to "struct tomoyo_io_buffer".
1818 *
1819 * Returns the current process's domainname.
1820 */
1821static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
1822{
1823 if (!head->read_eof) {
1824 /*
1825 * tomoyo_domain()->domainname != NULL
1826 * because every process belongs to a domain and
1827 * the domain's name cannot be NULL.
1828 */
1829 tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
1830 head->read_eof = true;
1831 }
1832 return 0;
1833}
1834
1835/**
1836 * tomoyo_open_control - open() for /sys/kernel/security/tomoyo/ interface.
1837 *
1838 * @type: Type of interface.
1839 * @file: Pointer to "struct file".
1840 *
1841 * Associates policy handler and returns 0 on success, -ENOMEM otherwise.
1842 */
1843static int tomoyo_open_control(const u8 type, struct file *file)
1844{
1845 struct tomoyo_io_buffer *head = tomoyo_alloc(sizeof(*head));
1846
1847 if (!head)
1848 return -ENOMEM;
1849 mutex_init(&head->io_sem);
1850 switch (type) {
1851 case TOMOYO_DOMAINPOLICY:
1852 /* /sys/kernel/security/tomoyo/domain_policy */
1853 head->write = tomoyo_write_domain_policy;
1854 head->read = tomoyo_read_domain_policy;
1855 break;
1856 case TOMOYO_EXCEPTIONPOLICY:
1857 /* /sys/kernel/security/tomoyo/exception_policy */
1858 head->write = tomoyo_write_exception_policy;
1859 head->read = tomoyo_read_exception_policy;
1860 break;
1861 case TOMOYO_SELFDOMAIN:
1862 /* /sys/kernel/security/tomoyo/self_domain */
1863 head->read = tomoyo_read_self_domain;
1864 break;
1865 case TOMOYO_DOMAIN_STATUS:
1866 /* /sys/kernel/security/tomoyo/.domain_status */
1867 head->write = tomoyo_write_domain_profile;
1868 head->read = tomoyo_read_domain_profile;
1869 break;
1870 case TOMOYO_PROCESS_STATUS:
1871 /* /sys/kernel/security/tomoyo/.process_status */
1872 head->write = tomoyo_write_pid;
1873 head->read = tomoyo_read_pid;
1874 break;
1875 case TOMOYO_VERSION:
1876 /* /sys/kernel/security/tomoyo/version */
1877 head->read = tomoyo_read_version;
1878 head->readbuf_size = 128;
1879 break;
1880 case TOMOYO_MEMINFO:
1881 /* /sys/kernel/security/tomoyo/meminfo */
1882 head->write = tomoyo_write_memory_quota;
1883 head->read = tomoyo_read_memory_counter;
1884 head->readbuf_size = 512;
1885 break;
1886 case TOMOYO_PROFILE:
1887 /* /sys/kernel/security/tomoyo/profile */
1888 head->write = tomoyo_write_profile;
1889 head->read = tomoyo_read_profile;
1890 break;
1891 case TOMOYO_MANAGER:
1892 /* /sys/kernel/security/tomoyo/manager */
1893 head->write = tomoyo_write_manager_policy;
1894 head->read = tomoyo_read_manager_policy;
1895 break;
1896 }
1897 if (!(file->f_mode & FMODE_READ)) {
1898 /*
1899 * No need to allocate read_buf since it is not opened
1900 * for reading.
1901 */
1902 head->read = NULL;
1903 } else {
1904 if (!head->readbuf_size)
1905 head->readbuf_size = 4096 * 2;
1906 head->read_buf = tomoyo_alloc(head->readbuf_size);
1907 if (!head->read_buf) {
1908 tomoyo_free(head);
1909 return -ENOMEM;
1910 }
1911 }
1912 if (!(file->f_mode & FMODE_WRITE)) {
1913 /*
1914 * No need to allocate write_buf since it is not opened
1915 * for writing.
1916 */
1917 head->write = NULL;
1918 } else if (head->write) {
1919 head->writebuf_size = 4096 * 2;
1920 head->write_buf = tomoyo_alloc(head->writebuf_size);
1921 if (!head->write_buf) {
1922 tomoyo_free(head->read_buf);
1923 tomoyo_free(head);
1924 return -ENOMEM;
1925 }
1926 }
1927 file->private_data = head;
1928 /*
1929 * Call the handler now if the file is
1930 * /sys/kernel/security/tomoyo/self_domain
1931 * so that the user can use
1932 * cat < /sys/kernel/security/tomoyo/self_domain"
1933 * to know the current process's domainname.
1934 */
1935 if (type == TOMOYO_SELFDOMAIN)
1936 tomoyo_read_control(file, NULL, 0);
1937 return 0;
1938}
1939
1940/**
1941 * tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
1942 *
1943 * @file: Pointer to "struct file".
1944 * @buffer: Poiner to buffer to write to.
1945 * @buffer_len: Size of @buffer.
1946 *
1947 * Returns bytes read on success, negative value otherwise.
1948 */
1949static int tomoyo_read_control(struct file *file, char __user *buffer,
1950 const int buffer_len)
1951{
1952 int len = 0;
1953 struct tomoyo_io_buffer *head = file->private_data;
1954 char *cp;
1955
1956 if (!head->read)
1957 return -ENOSYS;
1958 if (mutex_lock_interruptible(&head->io_sem))
1959 return -EINTR;
1960 /* Call the policy handler. */
1961 len = head->read(head);
1962 if (len < 0)
1963 goto out;
1964 /* Write to buffer. */
1965 len = head->read_avail;
1966 if (len > buffer_len)
1967 len = buffer_len;
1968 if (!len)
1969 goto out;
1970 /* head->read_buf changes by some functions. */
1971 cp = head->read_buf;
1972 if (copy_to_user(buffer, cp, len)) {
1973 len = -EFAULT;
1974 goto out;
1975 }
1976 head->read_avail -= len;
1977 memmove(cp, cp + len, head->read_avail);
1978 out:
1979 mutex_unlock(&head->io_sem);
1980 return len;
1981}
1982
1983/**
1984 * tomoyo_write_control - write() for /sys/kernel/security/tomoyo/ interface.
1985 *
1986 * @file: Pointer to "struct file".
1987 * @buffer: Pointer to buffer to read from.
1988 * @buffer_len: Size of @buffer.
1989 *
1990 * Returns @buffer_len on success, negative value otherwise.
1991 */
1992static int tomoyo_write_control(struct file *file, const char __user *buffer,
1993 const int buffer_len)
1994{
1995 struct tomoyo_io_buffer *head = file->private_data;
1996 int error = buffer_len;
1997 int avail_len = buffer_len;
1998 char *cp0 = head->write_buf;
1999
2000 if (!head->write)
2001 return -ENOSYS;
2002 if (!access_ok(VERIFY_READ, buffer, buffer_len))
2003 return -EFAULT;
2004 /* Don't allow updating policies by non manager programs. */
2005 if (head->write != tomoyo_write_pid &&
2006 head->write != tomoyo_write_domain_policy &&
2007 !tomoyo_is_policy_manager())
2008 return -EPERM;
2009 if (mutex_lock_interruptible(&head->io_sem))
2010 return -EINTR;
2011 /* Read a line and dispatch it to the policy handler. */
2012 while (avail_len > 0) {
2013 char c;
2014 if (head->write_avail >= head->writebuf_size - 1) {
2015 error = -ENOMEM;
2016 break;
2017 } else if (get_user(c, buffer)) {
2018 error = -EFAULT;
2019 break;
2020 }
2021 buffer++;
2022 avail_len--;
2023 cp0[head->write_avail++] = c;
2024 if (c != '\n')
2025 continue;
2026 cp0[head->write_avail - 1] = '\0';
2027 head->write_avail = 0;
2028 tomoyo_normalize_line(cp0);
2029 head->write(head);
2030 }
2031 mutex_unlock(&head->io_sem);
2032 return error;
2033}
2034
2035/**
2036 * tomoyo_close_control - close() for /sys/kernel/security/tomoyo/ interface.
2037 *
2038 * @file: Pointer to "struct file".
2039 *
2040 * Releases memory and returns 0.
2041 */
2042static int tomoyo_close_control(struct file *file)
2043{
2044 struct tomoyo_io_buffer *head = file->private_data;
2045
2046 /* Release memory used for policy I/O. */
2047 tomoyo_free(head->read_buf);
2048 head->read_buf = NULL;
2049 tomoyo_free(head->write_buf);
2050 head->write_buf = NULL;
2051 tomoyo_free(head);
2052 head = NULL;
2053 file->private_data = NULL;
2054 return 0;
2055}
2056
2057/**
2058 * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry.
2059 *
2060 * @acl_type: Type of ACL entry.
2061 *
2062 * Returns pointer to the ACL entry on success, NULL otherwise.
2063 */
2064void *tomoyo_alloc_acl_element(const u8 acl_type)
2065{
2066 int len;
2067 struct tomoyo_acl_info *ptr;
2068
2069 switch (acl_type) {
2070 case TOMOYO_TYPE_SINGLE_PATH_ACL:
2071 len = sizeof(struct tomoyo_single_path_acl_record);
2072 break;
2073 case TOMOYO_TYPE_DOUBLE_PATH_ACL:
2074 len = sizeof(struct tomoyo_double_path_acl_record);
2075 break;
2076 default:
2077 return NULL;
2078 }
2079 ptr = tomoyo_alloc_element(len);
2080 if (!ptr)
2081 return NULL;
2082 ptr->type = acl_type;
2083 return ptr;
2084}
2085
2086/**
2087 * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
2088 *
2089 * @inode: Pointer to "struct inode".
2090 * @file: Pointer to "struct file".
2091 *
2092 * Returns 0 on success, negative value otherwise.
2093 */
2094static int tomoyo_open(struct inode *inode, struct file *file)
2095{
2096 const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
2097 - ((u8 *) NULL);
2098 return tomoyo_open_control(key, file);
2099}
2100
2101/**
2102 * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
2103 *
2104 * @inode: Pointer to "struct inode".
2105 * @file: Pointer to "struct file".
2106 *
2107 * Returns 0 on success, negative value otherwise.
2108 */
2109static int tomoyo_release(struct inode *inode, struct file *file)
2110{
2111 return tomoyo_close_control(file);
2112}
2113
2114/**
2115 * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
2116 *
2117 * @file: Pointer to "struct file".
2118 * @buf: Pointer to buffer.
2119 * @count: Size of @buf.
2120 * @ppos: Unused.
2121 *
2122 * Returns bytes read on success, negative value otherwise.
2123 */
2124static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
2125 loff_t *ppos)
2126{
2127 return tomoyo_read_control(file, buf, count);
2128}
2129
2130/**
2131 * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
2132 *
2133 * @file: Pointer to "struct file".
2134 * @buf: Pointer to buffer.
2135 * @count: Size of @buf.
2136 * @ppos: Unused.
2137 *
2138 * Returns @count on success, negative value otherwise.
2139 */
2140static ssize_t tomoyo_write(struct file *file, const char __user *buf,
2141 size_t count, loff_t *ppos)
2142{
2143 return tomoyo_write_control(file, buf, count);
2144}
2145
2146/* Operations for /sys/kernel/security/tomoyo/ interface. */
2147static const struct file_operations tomoyo_operations = {
2148 .open = tomoyo_open,
2149 .release = tomoyo_release,
2150 .read = tomoyo_read,
2151 .write = tomoyo_write,
2152};
2153
2154/**
2155 * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
2156 *
2157 * @name: The name of the interface file.
2158 * @mode: The permission of the interface file.
2159 * @parent: The parent directory.
2160 * @key: Type of interface.
2161 *
2162 * Returns nothing.
2163 */
2164static void __init tomoyo_create_entry(const char *name, const mode_t mode,
2165 struct dentry *parent, const u8 key)
2166{
2167 securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
2168 &tomoyo_operations);
2169}
2170
2171/**
2172 * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
2173 *
2174 * Returns 0.
2175 */
2176static int __init tomoyo_initerface_init(void)
2177{
2178 struct dentry *tomoyo_dir;
2179
2180 tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
2181 tomoyo_create_entry("domain_policy", 0600, tomoyo_dir,
2182 TOMOYO_DOMAINPOLICY);
2183 tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
2184 TOMOYO_EXCEPTIONPOLICY);
2185 tomoyo_create_entry("self_domain", 0400, tomoyo_dir,
2186 TOMOYO_SELFDOMAIN);
2187 tomoyo_create_entry(".domain_status", 0600, tomoyo_dir,
2188 TOMOYO_DOMAIN_STATUS);
2189 tomoyo_create_entry(".process_status", 0600, tomoyo_dir,
2190 TOMOYO_PROCESS_STATUS);
2191 tomoyo_create_entry("meminfo", 0600, tomoyo_dir,
2192 TOMOYO_MEMINFO);
2193 tomoyo_create_entry("profile", 0600, tomoyo_dir,
2194 TOMOYO_PROFILE);
2195 tomoyo_create_entry("manager", 0600, tomoyo_dir,
2196 TOMOYO_MANAGER);
2197 tomoyo_create_entry("version", 0400, tomoyo_dir,
2198 TOMOYO_VERSION);
2199 return 0;
2200}
2201
2202fs_initcall(tomoyo_initerface_init);