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