diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /security/tomoyo/file.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'security/tomoyo/file.c')
-rw-r--r-- | security/tomoyo/file.c | 754 |
1 files changed, 350 insertions, 404 deletions
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 5ae3a571559f..6f3fe76a1fde 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -10,109 +10,65 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include "common.h" | 12 | #include "common.h" |
13 | #include "tomoyo.h" | 13 | #include <linux/slab.h> |
14 | #include "realpath.h" | ||
15 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) | ||
16 | |||
17 | /* | ||
18 | * tomoyo_globally_readable_file_entry is a structure which is used for holding | ||
19 | * "allow_read" entries. | ||
20 | * It has following fields. | ||
21 | * | ||
22 | * (1) "list" which is linked to tomoyo_globally_readable_list . | ||
23 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
24 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
25 | * otherwise. | ||
26 | */ | ||
27 | struct tomoyo_globally_readable_file_entry { | ||
28 | struct list_head list; | ||
29 | const struct tomoyo_path_info *filename; | ||
30 | bool is_deleted; | ||
31 | }; | ||
32 | |||
33 | /* | ||
34 | * tomoyo_pattern_entry is a structure which is used for holding | ||
35 | * "tomoyo_pattern_list" entries. | ||
36 | * It has following fields. | ||
37 | * | ||
38 | * (1) "list" which is linked to tomoyo_pattern_list . | ||
39 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
40 | * to pathname patterns during learning mode. | ||
41 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
42 | * otherwise. | ||
43 | */ | ||
44 | struct tomoyo_pattern_entry { | ||
45 | struct list_head list; | ||
46 | const struct tomoyo_path_info *pattern; | ||
47 | bool is_deleted; | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * tomoyo_no_rewrite_entry is a structure which is used for holding | ||
52 | * "deny_rewrite" entries. | ||
53 | * It has following fields. | ||
54 | * | ||
55 | * (1) "list" which is linked to tomoyo_no_rewrite_list . | ||
56 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
57 | * already existing content. | ||
58 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
59 | * otherwise. | ||
60 | */ | ||
61 | struct tomoyo_no_rewrite_entry { | ||
62 | struct list_head list; | ||
63 | const struct tomoyo_path_info *pattern; | ||
64 | bool is_deleted; | ||
65 | }; | ||
66 | 14 | ||
67 | /* Keyword array for single path operations. */ | 15 | /* Keyword array for single path operations. */ |
68 | static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { | 16 | static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { |
69 | [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", | 17 | [TOMOYO_TYPE_READ_WRITE] = "read/write", |
70 | [TOMOYO_TYPE_EXECUTE_ACL] = "execute", | 18 | [TOMOYO_TYPE_EXECUTE] = "execute", |
71 | [TOMOYO_TYPE_READ_ACL] = "read", | 19 | [TOMOYO_TYPE_READ] = "read", |
72 | [TOMOYO_TYPE_WRITE_ACL] = "write", | 20 | [TOMOYO_TYPE_WRITE] = "write", |
73 | [TOMOYO_TYPE_CREATE_ACL] = "create", | 21 | [TOMOYO_TYPE_CREATE] = "create", |
74 | [TOMOYO_TYPE_UNLINK_ACL] = "unlink", | 22 | [TOMOYO_TYPE_UNLINK] = "unlink", |
75 | [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", | 23 | [TOMOYO_TYPE_MKDIR] = "mkdir", |
76 | [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", | 24 | [TOMOYO_TYPE_RMDIR] = "rmdir", |
77 | [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", | 25 | [TOMOYO_TYPE_MKFIFO] = "mkfifo", |
78 | [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", | 26 | [TOMOYO_TYPE_MKSOCK] = "mksock", |
79 | [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", | 27 | [TOMOYO_TYPE_MKBLOCK] = "mkblock", |
80 | [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", | 28 | [TOMOYO_TYPE_MKCHAR] = "mkchar", |
81 | [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", | 29 | [TOMOYO_TYPE_TRUNCATE] = "truncate", |
82 | [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", | 30 | [TOMOYO_TYPE_SYMLINK] = "symlink", |
83 | [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", | 31 | [TOMOYO_TYPE_REWRITE] = "rewrite", |
32 | [TOMOYO_TYPE_IOCTL] = "ioctl", | ||
33 | [TOMOYO_TYPE_CHMOD] = "chmod", | ||
34 | [TOMOYO_TYPE_CHOWN] = "chown", | ||
35 | [TOMOYO_TYPE_CHGRP] = "chgrp", | ||
36 | [TOMOYO_TYPE_CHROOT] = "chroot", | ||
37 | [TOMOYO_TYPE_MOUNT] = "mount", | ||
38 | [TOMOYO_TYPE_UMOUNT] = "unmount", | ||
84 | }; | 39 | }; |
85 | 40 | ||
86 | /* Keyword array for double path operations. */ | 41 | /* Keyword array for double path operations. */ |
87 | static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { | 42 | static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { |
88 | [TOMOYO_TYPE_LINK_ACL] = "link", | 43 | [TOMOYO_TYPE_LINK] = "link", |
89 | [TOMOYO_TYPE_RENAME_ACL] = "rename", | 44 | [TOMOYO_TYPE_RENAME] = "rename", |
45 | [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", | ||
90 | }; | 46 | }; |
91 | 47 | ||
92 | /** | 48 | /** |
93 | * tomoyo_sp2keyword - Get the name of single path operation. | 49 | * tomoyo_path2keyword - Get the name of single path operation. |
94 | * | 50 | * |
95 | * @operation: Type of operation. | 51 | * @operation: Type of operation. |
96 | * | 52 | * |
97 | * Returns the name of single path operation. | 53 | * Returns the name of single path operation. |
98 | */ | 54 | */ |
99 | const char *tomoyo_sp2keyword(const u8 operation) | 55 | const char *tomoyo_path2keyword(const u8 operation) |
100 | { | 56 | { |
101 | return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) | 57 | return (operation < TOMOYO_MAX_PATH_OPERATION) |
102 | ? tomoyo_sp_keyword[operation] : NULL; | 58 | ? tomoyo_path_keyword[operation] : NULL; |
103 | } | 59 | } |
104 | 60 | ||
105 | /** | 61 | /** |
106 | * tomoyo_dp2keyword - Get the name of double path operation. | 62 | * tomoyo_path22keyword - Get the name of double path operation. |
107 | * | 63 | * |
108 | * @operation: Type of operation. | 64 | * @operation: Type of operation. |
109 | * | 65 | * |
110 | * Returns the name of double path operation. | 66 | * Returns the name of double path operation. |
111 | */ | 67 | */ |
112 | const char *tomoyo_dp2keyword(const u8 operation) | 68 | const char *tomoyo_path22keyword(const u8 operation) |
113 | { | 69 | { |
114 | return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) | 70 | return (operation < TOMOYO_MAX_PATH2_OPERATION) |
115 | ? tomoyo_dp_keyword[operation] : NULL; | 71 | ? tomoyo_path2_keyword[operation] : NULL; |
116 | } | 72 | } |
117 | 73 | ||
118 | /** | 74 | /** |
@@ -143,7 +99,8 @@ static bool tomoyo_strendswith(const char *name, const char *tail) | |||
143 | static struct tomoyo_path_info *tomoyo_get_path(struct path *path) | 99 | static struct tomoyo_path_info *tomoyo_get_path(struct path *path) |
144 | { | 100 | { |
145 | int error; | 101 | int error; |
146 | struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); | 102 | struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), |
103 | GFP_KERNEL); | ||
147 | 104 | ||
148 | if (!buf) | 105 | if (!buf) |
149 | return NULL; | 106 | return NULL; |
@@ -155,20 +112,17 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path) | |||
155 | tomoyo_fill_path_info(&buf->head); | 112 | tomoyo_fill_path_info(&buf->head); |
156 | return &buf->head; | 113 | return &buf->head; |
157 | } | 114 | } |
158 | tomoyo_free(buf); | 115 | kfree(buf); |
159 | return NULL; | 116 | return NULL; |
160 | } | 117 | } |
161 | 118 | ||
162 | /* Lock for domain->acl_info_list. */ | 119 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, |
163 | DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock); | 120 | const char *filename2, |
164 | 121 | struct tomoyo_domain_info *const domain, | |
165 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | 122 | const bool is_delete); |
166 | const char *filename2, | 123 | static int tomoyo_update_path_acl(const u8 type, const char *filename, |
167 | struct tomoyo_domain_info * | 124 | struct tomoyo_domain_info *const domain, |
168 | const domain, const bool is_delete); | 125 | const bool is_delete); |
169 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | ||
170 | struct tomoyo_domain_info * | ||
171 | const domain, const bool is_delete); | ||
172 | 126 | ||
173 | /* | 127 | /* |
174 | * tomoyo_globally_readable_list is used for holding list of pathnames which | 128 | * tomoyo_globally_readable_list is used for holding list of pathnames which |
@@ -195,8 +149,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
195 | * given "allow_read /lib/libc-2.5.so" to the domain which current process | 149 | * given "allow_read /lib/libc-2.5.so" to the domain which current process |
196 | * belongs to. | 150 | * belongs to. |
197 | */ | 151 | */ |
198 | static LIST_HEAD(tomoyo_globally_readable_list); | 152 | LIST_HEAD(tomoyo_globally_readable_list); |
199 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | ||
200 | 153 | ||
201 | /** | 154 | /** |
202 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. | 155 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. |
@@ -205,40 +158,42 @@ static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | |||
205 | * @is_delete: True if it is a delete request. | 158 | * @is_delete: True if it is a delete request. |
206 | * | 159 | * |
207 | * Returns 0 on success, negative value otherwise. | 160 | * Returns 0 on success, negative value otherwise. |
161 | * | ||
162 | * Caller holds tomoyo_read_lock(). | ||
208 | */ | 163 | */ |
209 | static int tomoyo_update_globally_readable_entry(const char *filename, | 164 | static int tomoyo_update_globally_readable_entry(const char *filename, |
210 | const bool is_delete) | 165 | const bool is_delete) |
211 | { | 166 | { |
212 | struct tomoyo_globally_readable_file_entry *new_entry; | 167 | struct tomoyo_globally_readable_file_entry *entry = NULL; |
213 | struct tomoyo_globally_readable_file_entry *ptr; | 168 | struct tomoyo_globally_readable_file_entry *ptr; |
214 | const struct tomoyo_path_info *saved_filename; | 169 | const struct tomoyo_path_info *saved_filename; |
215 | int error = -ENOMEM; | 170 | int error = is_delete ? -ENOENT : -ENOMEM; |
216 | 171 | ||
217 | if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) | 172 | if (!tomoyo_is_correct_path(filename, 1, 0, -1)) |
218 | return -EINVAL; | 173 | return -EINVAL; |
219 | saved_filename = tomoyo_save_name(filename); | 174 | saved_filename = tomoyo_get_name(filename); |
220 | if (!saved_filename) | 175 | if (!saved_filename) |
221 | return -ENOMEM; | 176 | return -ENOMEM; |
222 | down_write(&tomoyo_globally_readable_list_lock); | 177 | if (!is_delete) |
223 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 178 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
179 | mutex_lock(&tomoyo_policy_lock); | ||
180 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { | ||
224 | if (ptr->filename != saved_filename) | 181 | if (ptr->filename != saved_filename) |
225 | continue; | 182 | continue; |
226 | ptr->is_deleted = is_delete; | 183 | ptr->is_deleted = is_delete; |
227 | error = 0; | 184 | error = 0; |
228 | goto out; | 185 | break; |
229 | } | 186 | } |
230 | if (is_delete) { | 187 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
231 | error = -ENOENT; | 188 | entry->filename = saved_filename; |
232 | goto out; | 189 | saved_filename = NULL; |
190 | list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); | ||
191 | entry = NULL; | ||
192 | error = 0; | ||
233 | } | 193 | } |
234 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 194 | mutex_unlock(&tomoyo_policy_lock); |
235 | if (!new_entry) | 195 | tomoyo_put_name(saved_filename); |
236 | goto out; | 196 | kfree(entry); |
237 | new_entry->filename = saved_filename; | ||
238 | list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); | ||
239 | error = 0; | ||
240 | out: | ||
241 | up_write(&tomoyo_globally_readable_list_lock); | ||
242 | return error; | 197 | return error; |
243 | } | 198 | } |
244 | 199 | ||
@@ -248,21 +203,22 @@ static int tomoyo_update_globally_readable_entry(const char *filename, | |||
248 | * @filename: The filename to check. | 203 | * @filename: The filename to check. |
249 | * | 204 | * |
250 | * Returns true if any domain can open @filename for reading, false otherwise. | 205 | * Returns true if any domain can open @filename for reading, false otherwise. |
206 | * | ||
207 | * Caller holds tomoyo_read_lock(). | ||
251 | */ | 208 | */ |
252 | static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * | 209 | static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * |
253 | filename) | 210 | filename) |
254 | { | 211 | { |
255 | struct tomoyo_globally_readable_file_entry *ptr; | 212 | struct tomoyo_globally_readable_file_entry *ptr; |
256 | bool found = false; | 213 | bool found = false; |
257 | down_read(&tomoyo_globally_readable_list_lock); | 214 | |
258 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 215 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { |
259 | if (!ptr->is_deleted && | 216 | if (!ptr->is_deleted && |
260 | tomoyo_path_matches_pattern(filename, ptr->filename)) { | 217 | tomoyo_path_matches_pattern(filename, ptr->filename)) { |
261 | found = true; | 218 | found = true; |
262 | break; | 219 | break; |
263 | } | 220 | } |
264 | } | 221 | } |
265 | up_read(&tomoyo_globally_readable_list_lock); | ||
266 | return found; | 222 | return found; |
267 | } | 223 | } |
268 | 224 | ||
@@ -273,6 +229,8 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * | |||
273 | * @is_delete: True if it is a delete request. | 229 | * @is_delete: True if it is a delete request. |
274 | * | 230 | * |
275 | * Returns 0 on success, negative value otherwise. | 231 | * Returns 0 on success, negative value otherwise. |
232 | * | ||
233 | * Caller holds tomoyo_read_lock(). | ||
276 | */ | 234 | */ |
277 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) | 235 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) |
278 | { | 236 | { |
@@ -285,13 +243,14 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) | |||
285 | * @head: Pointer to "struct tomoyo_io_buffer". | 243 | * @head: Pointer to "struct tomoyo_io_buffer". |
286 | * | 244 | * |
287 | * Returns true on success, false otherwise. | 245 | * Returns true on success, false otherwise. |
246 | * | ||
247 | * Caller holds tomoyo_read_lock(). | ||
288 | */ | 248 | */ |
289 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | 249 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) |
290 | { | 250 | { |
291 | struct list_head *pos; | 251 | struct list_head *pos; |
292 | bool done = true; | 252 | bool done = true; |
293 | 253 | ||
294 | down_read(&tomoyo_globally_readable_list_lock); | ||
295 | list_for_each_cookie(pos, head->read_var2, | 254 | list_for_each_cookie(pos, head->read_var2, |
296 | &tomoyo_globally_readable_list) { | 255 | &tomoyo_globally_readable_list) { |
297 | struct tomoyo_globally_readable_file_entry *ptr; | 256 | struct tomoyo_globally_readable_file_entry *ptr; |
@@ -305,7 +264,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
305 | if (!done) | 264 | if (!done) |
306 | break; | 265 | break; |
307 | } | 266 | } |
308 | up_read(&tomoyo_globally_readable_list_lock); | ||
309 | return done; | 267 | return done; |
310 | } | 268 | } |
311 | 269 | ||
@@ -338,8 +296,7 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
338 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid | 296 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid |
339 | * current process from accessing other process's information. | 297 | * current process from accessing other process's information. |
340 | */ | 298 | */ |
341 | static LIST_HEAD(tomoyo_pattern_list); | 299 | LIST_HEAD(tomoyo_pattern_list); |
342 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); | ||
343 | 300 | ||
344 | /** | 301 | /** |
345 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. | 302 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. |
@@ -348,40 +305,43 @@ static DECLARE_RWSEM(tomoyo_pattern_list_lock); | |||
348 | * @is_delete: True if it is a delete request. | 305 | * @is_delete: True if it is a delete request. |
349 | * | 306 | * |
350 | * Returns 0 on success, negative value otherwise. | 307 | * Returns 0 on success, negative value otherwise. |
308 | * | ||
309 | * Caller holds tomoyo_read_lock(). | ||
351 | */ | 310 | */ |
352 | static int tomoyo_update_file_pattern_entry(const char *pattern, | 311 | static int tomoyo_update_file_pattern_entry(const char *pattern, |
353 | const bool is_delete) | 312 | const bool is_delete) |
354 | { | 313 | { |
355 | struct tomoyo_pattern_entry *new_entry; | 314 | struct tomoyo_pattern_entry *entry = NULL; |
356 | struct tomoyo_pattern_entry *ptr; | 315 | struct tomoyo_pattern_entry *ptr; |
357 | const struct tomoyo_path_info *saved_pattern; | 316 | const struct tomoyo_path_info *saved_pattern; |
358 | int error = -ENOMEM; | 317 | int error = is_delete ? -ENOENT : -ENOMEM; |
359 | 318 | ||
360 | if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) | 319 | saved_pattern = tomoyo_get_name(pattern); |
361 | return -EINVAL; | ||
362 | saved_pattern = tomoyo_save_name(pattern); | ||
363 | if (!saved_pattern) | 320 | if (!saved_pattern) |
364 | return -ENOMEM; | 321 | return error; |
365 | down_write(&tomoyo_pattern_list_lock); | 322 | if (!saved_pattern->is_patterned) |
366 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | 323 | goto out; |
324 | if (!is_delete) | ||
325 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
326 | mutex_lock(&tomoyo_policy_lock); | ||
327 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { | ||
367 | if (saved_pattern != ptr->pattern) | 328 | if (saved_pattern != ptr->pattern) |
368 | continue; | 329 | continue; |
369 | ptr->is_deleted = is_delete; | 330 | ptr->is_deleted = is_delete; |
370 | error = 0; | 331 | error = 0; |
371 | goto out; | 332 | break; |
372 | } | 333 | } |
373 | if (is_delete) { | 334 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
374 | error = -ENOENT; | 335 | entry->pattern = saved_pattern; |
375 | goto out; | 336 | saved_pattern = NULL; |
337 | list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); | ||
338 | entry = NULL; | ||
339 | error = 0; | ||
376 | } | 340 | } |
377 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 341 | mutex_unlock(&tomoyo_policy_lock); |
378 | if (!new_entry) | ||
379 | goto out; | ||
380 | new_entry->pattern = saved_pattern; | ||
381 | list_add_tail(&new_entry->list, &tomoyo_pattern_list); | ||
382 | error = 0; | ||
383 | out: | 342 | out: |
384 | up_write(&tomoyo_pattern_list_lock); | 343 | kfree(entry); |
344 | tomoyo_put_name(saved_pattern); | ||
385 | return error; | 345 | return error; |
386 | } | 346 | } |
387 | 347 | ||
@@ -391,6 +351,8 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
391 | * @filename: The filename to find patterned pathname. | 351 | * @filename: The filename to find patterned pathname. |
392 | * | 352 | * |
393 | * Returns pointer to pathname pattern if matched, @filename otherwise. | 353 | * Returns pointer to pathname pattern if matched, @filename otherwise. |
354 | * | ||
355 | * Caller holds tomoyo_read_lock(). | ||
394 | */ | 356 | */ |
395 | static const struct tomoyo_path_info * | 357 | static const struct tomoyo_path_info * |
396 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | 358 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) |
@@ -398,8 +360,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
398 | struct tomoyo_pattern_entry *ptr; | 360 | struct tomoyo_pattern_entry *ptr; |
399 | const struct tomoyo_path_info *pattern = NULL; | 361 | const struct tomoyo_path_info *pattern = NULL; |
400 | 362 | ||
401 | down_read(&tomoyo_pattern_list_lock); | 363 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { |
402 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | ||
403 | if (ptr->is_deleted) | 364 | if (ptr->is_deleted) |
404 | continue; | 365 | continue; |
405 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | 366 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) |
@@ -412,7 +373,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
412 | break; | 373 | break; |
413 | } | 374 | } |
414 | } | 375 | } |
415 | up_read(&tomoyo_pattern_list_lock); | ||
416 | if (pattern) | 376 | if (pattern) |
417 | filename = pattern; | 377 | filename = pattern; |
418 | return filename; | 378 | return filename; |
@@ -425,6 +385,8 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | |||
425 | * @is_delete: True if it is a delete request. | 385 | * @is_delete: True if it is a delete request. |
426 | * | 386 | * |
427 | * Returns 0 on success, negative value otherwise. | 387 | * Returns 0 on success, negative value otherwise. |
388 | * | ||
389 | * Caller holds tomoyo_read_lock(). | ||
428 | */ | 390 | */ |
429 | int tomoyo_write_pattern_policy(char *data, const bool is_delete) | 391 | int tomoyo_write_pattern_policy(char *data, const bool is_delete) |
430 | { | 392 | { |
@@ -437,13 +399,14 @@ int tomoyo_write_pattern_policy(char *data, const bool is_delete) | |||
437 | * @head: Pointer to "struct tomoyo_io_buffer". | 399 | * @head: Pointer to "struct tomoyo_io_buffer". |
438 | * | 400 | * |
439 | * Returns true on success, false otherwise. | 401 | * Returns true on success, false otherwise. |
402 | * | ||
403 | * Caller holds tomoyo_read_lock(). | ||
440 | */ | 404 | */ |
441 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | 405 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) |
442 | { | 406 | { |
443 | struct list_head *pos; | 407 | struct list_head *pos; |
444 | bool done = true; | 408 | bool done = true; |
445 | 409 | ||
446 | down_read(&tomoyo_pattern_list_lock); | ||
447 | list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { | 410 | list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { |
448 | struct tomoyo_pattern_entry *ptr; | 411 | struct tomoyo_pattern_entry *ptr; |
449 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); | 412 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); |
@@ -454,7 +417,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
454 | if (!done) | 417 | if (!done) |
455 | break; | 418 | break; |
456 | } | 419 | } |
457 | up_read(&tomoyo_pattern_list_lock); | ||
458 | return done; | 420 | return done; |
459 | } | 421 | } |
460 | 422 | ||
@@ -487,8 +449,7 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
487 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't | 449 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't |
488 | * need to worry whether the file is already unlink()ed or not. | 450 | * need to worry whether the file is already unlink()ed or not. |
489 | */ | 451 | */ |
490 | static LIST_HEAD(tomoyo_no_rewrite_list); | 452 | LIST_HEAD(tomoyo_no_rewrite_list); |
491 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | ||
492 | 453 | ||
493 | /** | 454 | /** |
494 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. | 455 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. |
@@ -497,39 +458,42 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | |||
497 | * @is_delete: True if it is a delete request. | 458 | * @is_delete: True if it is a delete request. |
498 | * | 459 | * |
499 | * Returns 0 on success, negative value otherwise. | 460 | * Returns 0 on success, negative value otherwise. |
461 | * | ||
462 | * Caller holds tomoyo_read_lock(). | ||
500 | */ | 463 | */ |
501 | static int tomoyo_update_no_rewrite_entry(const char *pattern, | 464 | static int tomoyo_update_no_rewrite_entry(const char *pattern, |
502 | const bool is_delete) | 465 | const bool is_delete) |
503 | { | 466 | { |
504 | struct tomoyo_no_rewrite_entry *new_entry, *ptr; | 467 | struct tomoyo_no_rewrite_entry *entry = NULL; |
468 | struct tomoyo_no_rewrite_entry *ptr; | ||
505 | const struct tomoyo_path_info *saved_pattern; | 469 | const struct tomoyo_path_info *saved_pattern; |
506 | int error = -ENOMEM; | 470 | int error = is_delete ? -ENOENT : -ENOMEM; |
507 | 471 | ||
508 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) | 472 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) |
509 | return -EINVAL; | 473 | return -EINVAL; |
510 | saved_pattern = tomoyo_save_name(pattern); | 474 | saved_pattern = tomoyo_get_name(pattern); |
511 | if (!saved_pattern) | 475 | if (!saved_pattern) |
512 | return -ENOMEM; | 476 | return error; |
513 | down_write(&tomoyo_no_rewrite_list_lock); | 477 | if (!is_delete) |
514 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | 478 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
479 | mutex_lock(&tomoyo_policy_lock); | ||
480 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { | ||
515 | if (ptr->pattern != saved_pattern) | 481 | if (ptr->pattern != saved_pattern) |
516 | continue; | 482 | continue; |
517 | ptr->is_deleted = is_delete; | 483 | ptr->is_deleted = is_delete; |
518 | error = 0; | 484 | error = 0; |
519 | goto out; | 485 | break; |
520 | } | 486 | } |
521 | if (is_delete) { | 487 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
522 | error = -ENOENT; | 488 | entry->pattern = saved_pattern; |
523 | goto out; | 489 | saved_pattern = NULL; |
490 | list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); | ||
491 | entry = NULL; | ||
492 | error = 0; | ||
524 | } | 493 | } |
525 | new_entry = tomoyo_alloc_element(sizeof(*new_entry)); | 494 | mutex_unlock(&tomoyo_policy_lock); |
526 | if (!new_entry) | 495 | tomoyo_put_name(saved_pattern); |
527 | goto out; | 496 | kfree(entry); |
528 | new_entry->pattern = saved_pattern; | ||
529 | list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); | ||
530 | error = 0; | ||
531 | out: | ||
532 | up_write(&tomoyo_no_rewrite_list_lock); | ||
533 | return error; | 497 | return error; |
534 | } | 498 | } |
535 | 499 | ||
@@ -540,14 +504,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, | |||
540 | * | 504 | * |
541 | * Returns true if @filename is specified by "deny_rewrite" directive, | 505 | * Returns true if @filename is specified by "deny_rewrite" directive, |
542 | * false otherwise. | 506 | * false otherwise. |
507 | * | ||
508 | * Caller holds tomoyo_read_lock(). | ||
543 | */ | 509 | */ |
544 | static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | 510 | static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) |
545 | { | 511 | { |
546 | struct tomoyo_no_rewrite_entry *ptr; | 512 | struct tomoyo_no_rewrite_entry *ptr; |
547 | bool found = false; | 513 | bool found = false; |
548 | 514 | ||
549 | down_read(&tomoyo_no_rewrite_list_lock); | 515 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { |
550 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | ||
551 | if (ptr->is_deleted) | 516 | if (ptr->is_deleted) |
552 | continue; | 517 | continue; |
553 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | 518 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) |
@@ -555,7 +520,6 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | |||
555 | found = true; | 520 | found = true; |
556 | break; | 521 | break; |
557 | } | 522 | } |
558 | up_read(&tomoyo_no_rewrite_list_lock); | ||
559 | return found; | 523 | return found; |
560 | } | 524 | } |
561 | 525 | ||
@@ -566,6 +530,8 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) | |||
566 | * @is_delete: True if it is a delete request. | 530 | * @is_delete: True if it is a delete request. |
567 | * | 531 | * |
568 | * Returns 0 on success, negative value otherwise. | 532 | * Returns 0 on success, negative value otherwise. |
533 | * | ||
534 | * Caller holds tomoyo_read_lock(). | ||
569 | */ | 535 | */ |
570 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) | 536 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) |
571 | { | 537 | { |
@@ -578,13 +544,14 @@ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) | |||
578 | * @head: Pointer to "struct tomoyo_io_buffer". | 544 | * @head: Pointer to "struct tomoyo_io_buffer". |
579 | * | 545 | * |
580 | * Returns true on success, false otherwise. | 546 | * Returns true on success, false otherwise. |
547 | * | ||
548 | * Caller holds tomoyo_read_lock(). | ||
581 | */ | 549 | */ |
582 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | 550 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) |
583 | { | 551 | { |
584 | struct list_head *pos; | 552 | struct list_head *pos; |
585 | bool done = true; | 553 | bool done = true; |
586 | 554 | ||
587 | down_read(&tomoyo_no_rewrite_list_lock); | ||
588 | list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { | 555 | list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { |
589 | struct tomoyo_no_rewrite_entry *ptr; | 556 | struct tomoyo_no_rewrite_entry *ptr; |
590 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); | 557 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); |
@@ -595,7 +562,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
595 | if (!done) | 562 | if (!done) |
596 | break; | 563 | break; |
597 | } | 564 | } |
598 | up_read(&tomoyo_no_rewrite_list_lock); | ||
599 | return done; | 565 | return done; |
600 | } | 566 | } |
601 | 567 | ||
@@ -613,6 +579,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
613 | * Current policy syntax uses "allow_read/write" instead of "6", | 579 | * Current policy syntax uses "allow_read/write" instead of "6", |
614 | * "allow_read" instead of "4", "allow_write" instead of "2", | 580 | * "allow_read" instead of "4", "allow_write" instead of "2", |
615 | * "allow_execute" instead of "1". | 581 | * "allow_execute" instead of "1". |
582 | * | ||
583 | * Caller holds tomoyo_read_lock(). | ||
616 | */ | 584 | */ |
617 | static int tomoyo_update_file_acl(const char *filename, u8 perm, | 585 | static int tomoyo_update_file_acl(const char *filename, u8 perm, |
618 | struct tomoyo_domain_info * const domain, | 586 | struct tomoyo_domain_info * const domain, |
@@ -630,19 +598,19 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, | |||
630 | */ | 598 | */ |
631 | return 0; | 599 | return 0; |
632 | if (perm & 4) | 600 | if (perm & 4) |
633 | tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, | 601 | tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, |
634 | domain, is_delete); | 602 | is_delete); |
635 | if (perm & 2) | 603 | if (perm & 2) |
636 | tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, | 604 | tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, |
637 | domain, is_delete); | 605 | is_delete); |
638 | if (perm & 1) | 606 | if (perm & 1) |
639 | tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, | 607 | tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, |
640 | filename, domain, is_delete); | 608 | is_delete); |
641 | return 0; | 609 | return 0; |
642 | } | 610 | } |
643 | 611 | ||
644 | /** | 612 | /** |
645 | * tomoyo_check_single_path_acl2 - Check permission for single path operation. | 613 | * tomoyo_path_acl2 - Check permission for single path operation. |
646 | * | 614 | * |
647 | * @domain: Pointer to "struct tomoyo_domain_info". | 615 | * @domain: Pointer to "struct tomoyo_domain_info". |
648 | * @filename: Filename to check. | 616 | * @filename: Filename to check. |
@@ -650,26 +618,28 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, | |||
650 | * @may_use_pattern: True if patterned ACL is permitted. | 618 | * @may_use_pattern: True if patterned ACL is permitted. |
651 | * | 619 | * |
652 | * Returns 0 on success, -EPERM otherwise. | 620 | * Returns 0 on success, -EPERM otherwise. |
621 | * | ||
622 | * Caller holds tomoyo_read_lock(). | ||
653 | */ | 623 | */ |
654 | static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | 624 | static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain, |
655 | domain, | 625 | const struct tomoyo_path_info *filename, |
656 | const struct tomoyo_path_info * | 626 | const u32 perm, const bool may_use_pattern) |
657 | filename, | ||
658 | const u16 perm, | ||
659 | const bool may_use_pattern) | ||
660 | { | 627 | { |
661 | struct tomoyo_acl_info *ptr; | 628 | struct tomoyo_acl_info *ptr; |
662 | int error = -EPERM; | 629 | int error = -EPERM; |
663 | 630 | ||
664 | down_read(&tomoyo_domain_acl_info_list_lock); | 631 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
665 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 632 | struct tomoyo_path_acl *acl; |
666 | struct tomoyo_single_path_acl_record *acl; | 633 | if (ptr->type != TOMOYO_TYPE_PATH_ACL) |
667 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | ||
668 | continue; | ||
669 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
670 | head); | ||
671 | if (!(acl->perm & perm)) | ||
672 | continue; | 634 | continue; |
635 | acl = container_of(ptr, struct tomoyo_path_acl, head); | ||
636 | if (perm <= 0xFFFF) { | ||
637 | if (!(acl->perm & perm)) | ||
638 | continue; | ||
639 | } else { | ||
640 | if (!(acl->perm_high & (perm >> 16))) | ||
641 | continue; | ||
642 | } | ||
673 | if (may_use_pattern || !acl->filename->is_patterned) { | 643 | if (may_use_pattern || !acl->filename->is_patterned) { |
674 | if (!tomoyo_path_matches_pattern(filename, | 644 | if (!tomoyo_path_matches_pattern(filename, |
675 | acl->filename)) | 645 | acl->filename)) |
@@ -680,7 +650,6 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | |||
680 | error = 0; | 650 | error = 0; |
681 | break; | 651 | break; |
682 | } | 652 | } |
683 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
684 | return error; | 653 | return error; |
685 | } | 654 | } |
686 | 655 | ||
@@ -692,27 +661,28 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * | |||
692 | * @operation: Mode ("read" or "write" or "read/write" or "execute"). | 661 | * @operation: Mode ("read" or "write" or "read/write" or "execute"). |
693 | * | 662 | * |
694 | * Returns 0 on success, -EPERM otherwise. | 663 | * Returns 0 on success, -EPERM otherwise. |
664 | * | ||
665 | * Caller holds tomoyo_read_lock(). | ||
695 | */ | 666 | */ |
696 | static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, | 667 | static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, |
697 | const struct tomoyo_path_info *filename, | 668 | const struct tomoyo_path_info *filename, |
698 | const u8 operation) | 669 | const u8 operation) |
699 | { | 670 | { |
700 | u16 perm = 0; | 671 | u32 perm = 0; |
701 | 672 | ||
702 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 673 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
703 | return 0; | 674 | return 0; |
704 | if (operation == 6) | 675 | if (operation == 6) |
705 | perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; | 676 | perm = 1 << TOMOYO_TYPE_READ_WRITE; |
706 | else if (operation == 4) | 677 | else if (operation == 4) |
707 | perm = 1 << TOMOYO_TYPE_READ_ACL; | 678 | perm = 1 << TOMOYO_TYPE_READ; |
708 | else if (operation == 2) | 679 | else if (operation == 2) |
709 | perm = 1 << TOMOYO_TYPE_WRITE_ACL; | 680 | perm = 1 << TOMOYO_TYPE_WRITE; |
710 | else if (operation == 1) | 681 | else if (operation == 1) |
711 | perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; | 682 | perm = 1 << TOMOYO_TYPE_EXECUTE; |
712 | else | 683 | else |
713 | BUG(); | 684 | BUG(); |
714 | return tomoyo_check_single_path_acl2(domain, filename, perm, | 685 | return tomoyo_path_acl2(domain, filename, perm, operation != 1); |
715 | operation != 1); | ||
716 | } | 686 | } |
717 | 687 | ||
718 | /** | 688 | /** |
@@ -725,6 +695,8 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, | |||
725 | * @mode: Access control mode. | 695 | * @mode: Access control mode. |
726 | * | 696 | * |
727 | * Returns 0 on success, negative value otherwise. | 697 | * Returns 0 on success, negative value otherwise. |
698 | * | ||
699 | * Caller holds tomoyo_read_lock(). | ||
728 | */ | 700 | */ |
729 | static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | 701 | static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, |
730 | const struct tomoyo_path_info *filename, | 702 | const struct tomoyo_path_info *filename, |
@@ -738,18 +710,17 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | |||
738 | if (!filename) | 710 | if (!filename) |
739 | return 0; | 711 | return 0; |
740 | error = tomoyo_check_file_acl(domain, filename, perm); | 712 | error = tomoyo_check_file_acl(domain, filename, perm); |
741 | if (error && perm == 4 && | 713 | if (error && perm == 4 && !domain->ignore_global_allow_read |
742 | (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 | ||
743 | && tomoyo_is_globally_readable_file(filename)) | 714 | && tomoyo_is_globally_readable_file(filename)) |
744 | error = 0; | 715 | error = 0; |
745 | if (perm == 6) | 716 | if (perm == 6) |
746 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); | 717 | msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); |
747 | else if (perm == 4) | 718 | else if (perm == 4) |
748 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); | 719 | msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); |
749 | else if (perm == 2) | 720 | else if (perm == 2) |
750 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); | 721 | msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); |
751 | else if (perm == 1) | 722 | else if (perm == 1) |
752 | msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); | 723 | msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); |
753 | else | 724 | else |
754 | BUG(); | 725 | BUG(); |
755 | if (!error) | 726 | if (!error) |
@@ -778,6 +749,8 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, | |||
778 | * @is_delete: True if it is a delete request. | 749 | * @is_delete: True if it is a delete request. |
779 | * | 750 | * |
780 | * Returns 0 on success, negative value otherwise. | 751 | * Returns 0 on success, negative value otherwise. |
752 | * | ||
753 | * Caller holds tomoyo_read_lock(). | ||
781 | */ | 754 | */ |
782 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | 755 | int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, |
783 | const bool is_delete) | 756 | const bool is_delete) |
@@ -796,28 +769,28 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | |||
796 | if (strncmp(data, "allow_", 6)) | 769 | if (strncmp(data, "allow_", 6)) |
797 | goto out; | 770 | goto out; |
798 | data += 6; | 771 | data += 6; |
799 | for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { | 772 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { |
800 | if (strcmp(data, tomoyo_sp_keyword[type])) | 773 | if (strcmp(data, tomoyo_path_keyword[type])) |
801 | continue; | 774 | continue; |
802 | return tomoyo_update_single_path_acl(type, filename, | 775 | return tomoyo_update_path_acl(type, filename, domain, |
803 | domain, is_delete); | 776 | is_delete); |
804 | } | 777 | } |
805 | filename2 = strchr(filename, ' '); | 778 | filename2 = strchr(filename, ' '); |
806 | if (!filename2) | 779 | if (!filename2) |
807 | goto out; | 780 | goto out; |
808 | *filename2++ = '\0'; | 781 | *filename2++ = '\0'; |
809 | for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) { | 782 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { |
810 | if (strcmp(data, tomoyo_dp_keyword[type])) | 783 | if (strcmp(data, tomoyo_path2_keyword[type])) |
811 | continue; | 784 | continue; |
812 | return tomoyo_update_double_path_acl(type, filename, filename2, | 785 | return tomoyo_update_path2_acl(type, filename, filename2, |
813 | domain, is_delete); | 786 | domain, is_delete); |
814 | } | 787 | } |
815 | out: | 788 | out: |
816 | return -EINVAL; | 789 | return -EINVAL; |
817 | } | 790 | } |
818 | 791 | ||
819 | /** | 792 | /** |
820 | * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. | 793 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. |
821 | * | 794 | * |
822 | * @type: Type of operation. | 795 | * @type: Type of operation. |
823 | * @filename: Filename. | 796 | * @filename: Filename. |
@@ -825,85 +798,82 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | |||
825 | * @is_delete: True if it is a delete request. | 798 | * @is_delete: True if it is a delete request. |
826 | * | 799 | * |
827 | * Returns 0 on success, negative value otherwise. | 800 | * Returns 0 on success, negative value otherwise. |
801 | * | ||
802 | * Caller holds tomoyo_read_lock(). | ||
828 | */ | 803 | */ |
829 | static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | 804 | static int tomoyo_update_path_acl(const u8 type, const char *filename, |
830 | struct tomoyo_domain_info * | 805 | struct tomoyo_domain_info *const domain, |
831 | const domain, const bool is_delete) | 806 | const bool is_delete) |
832 | { | 807 | { |
833 | static const u16 rw_mask = | 808 | static const u32 rw_mask = |
834 | (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); | 809 | (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); |
835 | const struct tomoyo_path_info *saved_filename; | 810 | const struct tomoyo_path_info *saved_filename; |
836 | struct tomoyo_acl_info *ptr; | 811 | struct tomoyo_acl_info *ptr; |
837 | struct tomoyo_single_path_acl_record *acl; | 812 | struct tomoyo_path_acl *entry = NULL; |
838 | int error = -ENOMEM; | 813 | int error = is_delete ? -ENOENT : -ENOMEM; |
839 | const u16 perm = 1 << type; | 814 | const u32 perm = 1 << type; |
840 | 815 | ||
841 | if (!domain) | 816 | if (!domain) |
842 | return -EINVAL; | 817 | return -EINVAL; |
843 | if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) | 818 | if (!tomoyo_is_correct_path(filename, 0, 0, 0)) |
844 | return -EINVAL; | 819 | return -EINVAL; |
845 | saved_filename = tomoyo_save_name(filename); | 820 | saved_filename = tomoyo_get_name(filename); |
846 | if (!saved_filename) | 821 | if (!saved_filename) |
847 | return -ENOMEM; | 822 | return -ENOMEM; |
848 | down_write(&tomoyo_domain_acl_info_list_lock); | 823 | if (!is_delete) |
849 | if (is_delete) | 824 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
850 | goto delete; | 825 | mutex_lock(&tomoyo_policy_lock); |
851 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 826 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
852 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | 827 | struct tomoyo_path_acl *acl = |
828 | container_of(ptr, struct tomoyo_path_acl, head); | ||
829 | if (ptr->type != TOMOYO_TYPE_PATH_ACL) | ||
853 | continue; | 830 | continue; |
854 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
855 | head); | ||
856 | if (acl->filename != saved_filename) | 831 | if (acl->filename != saved_filename) |
857 | continue; | 832 | continue; |
858 | /* Special case. Clear all bits if marked as deleted. */ | 833 | if (is_delete) { |
859 | if (ptr->type & TOMOYO_ACL_DELETED) | 834 | if (perm <= 0xFFFF) |
860 | acl->perm = 0; | 835 | acl->perm &= ~perm; |
861 | acl->perm |= perm; | 836 | else |
862 | if ((acl->perm & rw_mask) == rw_mask) | 837 | acl->perm_high &= ~(perm >> 16); |
863 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; | 838 | if ((acl->perm & rw_mask) != rw_mask) |
864 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | 839 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); |
865 | acl->perm |= rw_mask; | 840 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) |
866 | ptr->type &= ~TOMOYO_ACL_DELETED; | 841 | acl->perm &= ~rw_mask; |
842 | } else { | ||
843 | if (perm <= 0xFFFF) | ||
844 | acl->perm |= perm; | ||
845 | else | ||
846 | acl->perm_high |= (perm >> 16); | ||
847 | if ((acl->perm & rw_mask) == rw_mask) | ||
848 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; | ||
849 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) | ||
850 | acl->perm |= rw_mask; | ||
851 | } | ||
867 | error = 0; | 852 | error = 0; |
868 | goto out; | 853 | break; |
869 | } | 854 | } |
870 | /* Not found. Append it to the tail. */ | 855 | if (!is_delete && error && tomoyo_memory_ok(entry)) { |
871 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); | 856 | entry->head.type = TOMOYO_TYPE_PATH_ACL; |
872 | if (!acl) | 857 | if (perm <= 0xFFFF) |
873 | goto out; | 858 | entry->perm = perm; |
874 | acl->perm = perm; | 859 | else |
875 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) | 860 | entry->perm_high = (perm >> 16); |
876 | acl->perm |= rw_mask; | 861 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE)) |
877 | acl->filename = saved_filename; | 862 | entry->perm |= rw_mask; |
878 | list_add_tail(&acl->head.list, &domain->acl_info_list); | 863 | entry->filename = saved_filename; |
879 | error = 0; | 864 | saved_filename = NULL; |
880 | goto out; | 865 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); |
881 | delete: | 866 | entry = NULL; |
882 | error = -ENOENT; | ||
883 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
884 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) | ||
885 | continue; | ||
886 | acl = container_of(ptr, struct tomoyo_single_path_acl_record, | ||
887 | head); | ||
888 | if (acl->filename != saved_filename) | ||
889 | continue; | ||
890 | acl->perm &= ~perm; | ||
891 | if ((acl->perm & rw_mask) != rw_mask) | ||
892 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); | ||
893 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) | ||
894 | acl->perm &= ~rw_mask; | ||
895 | if (!acl->perm) | ||
896 | ptr->type |= TOMOYO_ACL_DELETED; | ||
897 | error = 0; | 867 | error = 0; |
898 | break; | ||
899 | } | 868 | } |
900 | out: | 869 | mutex_unlock(&tomoyo_policy_lock); |
901 | up_write(&tomoyo_domain_acl_info_list_lock); | 870 | kfree(entry); |
871 | tomoyo_put_name(saved_filename); | ||
902 | return error; | 872 | return error; |
903 | } | 873 | } |
904 | 874 | ||
905 | /** | 875 | /** |
906 | * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. | 876 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. |
907 | * | 877 | * |
908 | * @type: Type of operation. | 878 | * @type: Type of operation. |
909 | * @filename1: First filename. | 879 | * @filename1: First filename. |
@@ -912,98 +882,88 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
912 | * @is_delete: True if it is a delete request. | 882 | * @is_delete: True if it is a delete request. |
913 | * | 883 | * |
914 | * Returns 0 on success, negative value otherwise. | 884 | * Returns 0 on success, negative value otherwise. |
885 | * | ||
886 | * Caller holds tomoyo_read_lock(). | ||
915 | */ | 887 | */ |
916 | static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | 888 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, |
917 | const char *filename2, | 889 | const char *filename2, |
918 | struct tomoyo_domain_info * | 890 | struct tomoyo_domain_info *const domain, |
919 | const domain, const bool is_delete) | 891 | const bool is_delete) |
920 | { | 892 | { |
921 | const struct tomoyo_path_info *saved_filename1; | 893 | const struct tomoyo_path_info *saved_filename1; |
922 | const struct tomoyo_path_info *saved_filename2; | 894 | const struct tomoyo_path_info *saved_filename2; |
923 | struct tomoyo_acl_info *ptr; | 895 | struct tomoyo_acl_info *ptr; |
924 | struct tomoyo_double_path_acl_record *acl; | 896 | struct tomoyo_path2_acl *entry = NULL; |
925 | int error = -ENOMEM; | 897 | int error = is_delete ? -ENOENT : -ENOMEM; |
926 | const u8 perm = 1 << type; | 898 | const u8 perm = 1 << type; |
927 | 899 | ||
928 | if (!domain) | 900 | if (!domain) |
929 | return -EINVAL; | 901 | return -EINVAL; |
930 | if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || | 902 | if (!tomoyo_is_correct_path(filename1, 0, 0, 0) || |
931 | !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) | 903 | !tomoyo_is_correct_path(filename2, 0, 0, 0)) |
932 | return -EINVAL; | 904 | return -EINVAL; |
933 | saved_filename1 = tomoyo_save_name(filename1); | 905 | saved_filename1 = tomoyo_get_name(filename1); |
934 | saved_filename2 = tomoyo_save_name(filename2); | 906 | saved_filename2 = tomoyo_get_name(filename2); |
935 | if (!saved_filename1 || !saved_filename2) | 907 | if (!saved_filename1 || !saved_filename2) |
936 | return -ENOMEM; | ||
937 | down_write(&tomoyo_domain_acl_info_list_lock); | ||
938 | if (is_delete) | ||
939 | goto delete; | ||
940 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
941 | if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
942 | continue; | ||
943 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | ||
944 | head); | ||
945 | if (acl->filename1 != saved_filename1 || | ||
946 | acl->filename2 != saved_filename2) | ||
947 | continue; | ||
948 | /* Special case. Clear all bits if marked as deleted. */ | ||
949 | if (ptr->type & TOMOYO_ACL_DELETED) | ||
950 | acl->perm = 0; | ||
951 | acl->perm |= perm; | ||
952 | ptr->type &= ~TOMOYO_ACL_DELETED; | ||
953 | error = 0; | ||
954 | goto out; | 908 | goto out; |
955 | } | 909 | if (!is_delete) |
956 | /* Not found. Append it to the tail. */ | 910 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); |
957 | acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL); | 911 | mutex_lock(&tomoyo_policy_lock); |
958 | if (!acl) | 912 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
959 | goto out; | 913 | struct tomoyo_path2_acl *acl = |
960 | acl->perm = perm; | 914 | container_of(ptr, struct tomoyo_path2_acl, head); |
961 | acl->filename1 = saved_filename1; | 915 | if (ptr->type != TOMOYO_TYPE_PATH2_ACL) |
962 | acl->filename2 = saved_filename2; | ||
963 | list_add_tail(&acl->head.list, &domain->acl_info_list); | ||
964 | error = 0; | ||
965 | goto out; | ||
966 | delete: | ||
967 | error = -ENOENT; | ||
968 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | ||
969 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
970 | continue; | 916 | continue; |
971 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | ||
972 | head); | ||
973 | if (acl->filename1 != saved_filename1 || | 917 | if (acl->filename1 != saved_filename1 || |
974 | acl->filename2 != saved_filename2) | 918 | acl->filename2 != saved_filename2) |
975 | continue; | 919 | continue; |
976 | acl->perm &= ~perm; | 920 | if (is_delete) |
977 | if (!acl->perm) | 921 | acl->perm &= ~perm; |
978 | ptr->type |= TOMOYO_ACL_DELETED; | 922 | else |
923 | acl->perm |= perm; | ||
979 | error = 0; | 924 | error = 0; |
980 | break; | 925 | break; |
981 | } | 926 | } |
927 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | ||
928 | entry->head.type = TOMOYO_TYPE_PATH2_ACL; | ||
929 | entry->perm = perm; | ||
930 | entry->filename1 = saved_filename1; | ||
931 | saved_filename1 = NULL; | ||
932 | entry->filename2 = saved_filename2; | ||
933 | saved_filename2 = NULL; | ||
934 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); | ||
935 | entry = NULL; | ||
936 | error = 0; | ||
937 | } | ||
938 | mutex_unlock(&tomoyo_policy_lock); | ||
982 | out: | 939 | out: |
983 | up_write(&tomoyo_domain_acl_info_list_lock); | 940 | tomoyo_put_name(saved_filename1); |
941 | tomoyo_put_name(saved_filename2); | ||
942 | kfree(entry); | ||
984 | return error; | 943 | return error; |
985 | } | 944 | } |
986 | 945 | ||
987 | /** | 946 | /** |
988 | * tomoyo_check_single_path_acl - Check permission for single path operation. | 947 | * tomoyo_path_acl - Check permission for single path operation. |
989 | * | 948 | * |
990 | * @domain: Pointer to "struct tomoyo_domain_info". | 949 | * @domain: Pointer to "struct tomoyo_domain_info". |
991 | * @type: Type of operation. | 950 | * @type: Type of operation. |
992 | * @filename: Filename to check. | 951 | * @filename: Filename to check. |
993 | * | 952 | * |
994 | * Returns 0 on success, negative value otherwise. | 953 | * Returns 0 on success, negative value otherwise. |
954 | * | ||
955 | * Caller holds tomoyo_read_lock(). | ||
995 | */ | 956 | */ |
996 | static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, | 957 | static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type, |
997 | const u8 type, | 958 | const struct tomoyo_path_info *filename) |
998 | const struct tomoyo_path_info *filename) | ||
999 | { | 959 | { |
1000 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 960 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
1001 | return 0; | 961 | return 0; |
1002 | return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); | 962 | return tomoyo_path_acl2(domain, filename, 1 << type, 1); |
1003 | } | 963 | } |
1004 | 964 | ||
1005 | /** | 965 | /** |
1006 | * tomoyo_check_double_path_acl - Check permission for double path operation. | 966 | * tomoyo_path2_acl - Check permission for double path operation. |
1007 | * | 967 | * |
1008 | * @domain: Pointer to "struct tomoyo_domain_info". | 968 | * @domain: Pointer to "struct tomoyo_domain_info". |
1009 | * @type: Type of operation. | 969 | * @type: Type of operation. |
@@ -1011,13 +971,13 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, | |||
1011 | * @filename2: Second filename to check. | 971 | * @filename2: Second filename to check. |
1012 | * | 972 | * |
1013 | * Returns 0 on success, -EPERM otherwise. | 973 | * Returns 0 on success, -EPERM otherwise. |
974 | * | ||
975 | * Caller holds tomoyo_read_lock(). | ||
1014 | */ | 976 | */ |
1015 | static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | 977 | static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain, |
1016 | const u8 type, | 978 | const u8 type, |
1017 | const struct tomoyo_path_info * | 979 | const struct tomoyo_path_info *filename1, |
1018 | filename1, | 980 | const struct tomoyo_path_info *filename2) |
1019 | const struct tomoyo_path_info * | ||
1020 | filename2) | ||
1021 | { | 981 | { |
1022 | struct tomoyo_acl_info *ptr; | 982 | struct tomoyo_acl_info *ptr; |
1023 | const u8 perm = 1 << type; | 983 | const u8 perm = 1 << type; |
@@ -1025,13 +985,11 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | |||
1025 | 985 | ||
1026 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) | 986 | if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) |
1027 | return 0; | 987 | return 0; |
1028 | down_read(&tomoyo_domain_acl_info_list_lock); | 988 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
1029 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 989 | struct tomoyo_path2_acl *acl; |
1030 | struct tomoyo_double_path_acl_record *acl; | 990 | if (ptr->type != TOMOYO_TYPE_PATH2_ACL) |
1031 | if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) | ||
1032 | continue; | 991 | continue; |
1033 | acl = container_of(ptr, struct tomoyo_double_path_acl_record, | 992 | acl = container_of(ptr, struct tomoyo_path2_acl, head); |
1034 | head); | ||
1035 | if (!(acl->perm & perm)) | 993 | if (!(acl->perm & perm)) |
1036 | continue; | 994 | continue; |
1037 | if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) | 995 | if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) |
@@ -1041,12 +999,11 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | |||
1041 | error = 0; | 999 | error = 0; |
1042 | break; | 1000 | break; |
1043 | } | 1001 | } |
1044 | up_read(&tomoyo_domain_acl_info_list_lock); | ||
1045 | return error; | 1002 | return error; |
1046 | } | 1003 | } |
1047 | 1004 | ||
1048 | /** | 1005 | /** |
1049 | * tomoyo_check_single_path_permission2 - Check permission for single path operation. | 1006 | * tomoyo_path_permission2 - Check permission for single path operation. |
1050 | * | 1007 | * |
1051 | * @domain: Pointer to "struct tomoyo_domain_info". | 1008 | * @domain: Pointer to "struct tomoyo_domain_info". |
1052 | * @operation: Type of operation. | 1009 | * @operation: Type of operation. |
@@ -1054,11 +1011,13 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, | |||
1054 | * @mode: Access control mode. | 1011 | * @mode: Access control mode. |
1055 | * | 1012 | * |
1056 | * Returns 0 on success, negative value otherwise. | 1013 | * Returns 0 on success, negative value otherwise. |
1014 | * | ||
1015 | * Caller holds tomoyo_read_lock(). | ||
1057 | */ | 1016 | */ |
1058 | static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | 1017 | static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain, |
1059 | const domain, u8 operation, | 1018 | u8 operation, |
1060 | const struct tomoyo_path_info * | 1019 | const struct tomoyo_path_info *filename, |
1061 | filename, const u8 mode) | 1020 | const u8 mode) |
1062 | { | 1021 | { |
1063 | const char *msg; | 1022 | const char *msg; |
1064 | int error; | 1023 | int error; |
@@ -1067,8 +1026,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1067 | if (!mode) | 1026 | if (!mode) |
1068 | return 0; | 1027 | return 0; |
1069 | next: | 1028 | next: |
1070 | error = tomoyo_check_single_path_acl(domain, operation, filename); | 1029 | error = tomoyo_path_acl(domain, operation, filename); |
1071 | msg = tomoyo_sp2keyword(operation); | 1030 | msg = tomoyo_path2keyword(operation); |
1072 | if (!error) | 1031 | if (!error) |
1073 | goto ok; | 1032 | goto ok; |
1074 | if (tomoyo_verbose_mode(domain)) | 1033 | if (tomoyo_verbose_mode(domain)) |
@@ -1077,7 +1036,7 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1077 | tomoyo_get_last_name(domain)); | 1036 | tomoyo_get_last_name(domain)); |
1078 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { | 1037 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { |
1079 | const char *name = tomoyo_get_file_pattern(filename)->name; | 1038 | const char *name = tomoyo_get_file_pattern(filename)->name; |
1080 | tomoyo_update_single_path_acl(operation, name, domain, false); | 1039 | tomoyo_update_path_acl(operation, name, domain, false); |
1081 | } | 1040 | } |
1082 | if (!is_enforce) | 1041 | if (!is_enforce) |
1083 | error = 0; | 1042 | error = 0; |
@@ -1087,42 +1046,23 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * | |||
1087 | * we need to check "allow_rewrite" permission if the filename is | 1046 | * we need to check "allow_rewrite" permission if the filename is |
1088 | * specified by "deny_rewrite" keyword. | 1047 | * specified by "deny_rewrite" keyword. |
1089 | */ | 1048 | */ |
1090 | if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && | 1049 | if (!error && operation == TOMOYO_TYPE_TRUNCATE && |
1091 | tomoyo_is_no_rewrite_file(filename)) { | 1050 | tomoyo_is_no_rewrite_file(filename)) { |
1092 | operation = TOMOYO_TYPE_REWRITE_ACL; | 1051 | operation = TOMOYO_TYPE_REWRITE; |
1093 | goto next; | 1052 | goto next; |
1094 | } | 1053 | } |
1095 | return error; | 1054 | return error; |
1096 | } | 1055 | } |
1097 | 1056 | ||
1098 | /** | 1057 | /** |
1099 | * tomoyo_check_file_perm - Check permission for sysctl()'s "read" and "write". | ||
1100 | * | ||
1101 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1102 | * @filename: Filename to check. | ||
1103 | * @perm: Mode ("read" or "write" or "read/write"). | ||
1104 | * Returns 0 on success, negative value otherwise. | ||
1105 | */ | ||
1106 | int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, | ||
1107 | const char *filename, const u8 perm) | ||
1108 | { | ||
1109 | struct tomoyo_path_info name; | ||
1110 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | ||
1111 | |||
1112 | if (!mode) | ||
1113 | return 0; | ||
1114 | name.name = filename; | ||
1115 | tomoyo_fill_path_info(&name); | ||
1116 | return tomoyo_check_file_perm2(domain, &name, perm, "sysctl", mode); | ||
1117 | } | ||
1118 | |||
1119 | /** | ||
1120 | * tomoyo_check_exec_perm - Check permission for "execute". | 1058 | * tomoyo_check_exec_perm - Check permission for "execute". |
1121 | * | 1059 | * |
1122 | * @domain: Pointer to "struct tomoyo_domain_info". | 1060 | * @domain: Pointer to "struct tomoyo_domain_info". |
1123 | * @filename: Check permission for "execute". | 1061 | * @filename: Check permission for "execute". |
1124 | * | 1062 | * |
1125 | * Returns 0 on success, negativevalue otherwise. | 1063 | * Returns 0 on success, negativevalue otherwise. |
1064 | * | ||
1065 | * Caller holds tomoyo_read_lock(). | ||
1126 | */ | 1066 | */ |
1127 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 1067 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
1128 | const struct tomoyo_path_info *filename) | 1068 | const struct tomoyo_path_info *filename) |
@@ -1151,6 +1091,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1151 | struct tomoyo_path_info *buf; | 1091 | struct tomoyo_path_info *buf; |
1152 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1092 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1153 | const bool is_enforce = (mode == 3); | 1093 | const bool is_enforce = (mode == 3); |
1094 | int idx; | ||
1154 | 1095 | ||
1155 | if (!mode || !path->mnt) | 1096 | if (!mode || !path->mnt) |
1156 | return 0; | 1097 | return 0; |
@@ -1162,6 +1103,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1162 | * don't call me. | 1103 | * don't call me. |
1163 | */ | 1104 | */ |
1164 | return 0; | 1105 | return 0; |
1106 | idx = tomoyo_read_lock(); | ||
1165 | buf = tomoyo_get_path(path); | 1107 | buf = tomoyo_get_path(path); |
1166 | if (!buf) | 1108 | if (!buf) |
1167 | goto out; | 1109 | goto out; |
@@ -1174,49 +1116,50 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1174 | if ((acc_mode & MAY_WRITE) && | 1116 | if ((acc_mode & MAY_WRITE) && |
1175 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && | 1117 | ((flag & O_TRUNC) || !(flag & O_APPEND)) && |
1176 | (tomoyo_is_no_rewrite_file(buf))) { | 1118 | (tomoyo_is_no_rewrite_file(buf))) { |
1177 | error = tomoyo_check_single_path_permission2(domain, | 1119 | error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, |
1178 | TOMOYO_TYPE_REWRITE_ACL, | 1120 | buf, mode); |
1179 | buf, mode); | ||
1180 | } | 1121 | } |
1181 | if (!error) | 1122 | if (!error) |
1182 | error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", | 1123 | error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", |
1183 | mode); | 1124 | mode); |
1184 | if (!error && (flag & O_TRUNC)) | 1125 | if (!error && (flag & O_TRUNC)) |
1185 | error = tomoyo_check_single_path_permission2(domain, | 1126 | error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE, |
1186 | TOMOYO_TYPE_TRUNCATE_ACL, | 1127 | buf, mode); |
1187 | buf, mode); | ||
1188 | out: | 1128 | out: |
1189 | tomoyo_free(buf); | 1129 | kfree(buf); |
1130 | tomoyo_read_unlock(idx); | ||
1190 | if (!is_enforce) | 1131 | if (!is_enforce) |
1191 | error = 0; | 1132 | error = 0; |
1192 | return error; | 1133 | return error; |
1193 | } | 1134 | } |
1194 | 1135 | ||
1195 | /** | 1136 | /** |
1196 | * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink". | 1137 | * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". |
1197 | * | 1138 | * |
1198 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1199 | * @operation: Type of operation. | 1139 | * @operation: Type of operation. |
1200 | * @path: Pointer to "struct path". | 1140 | * @path: Pointer to "struct path". |
1201 | * | 1141 | * |
1202 | * Returns 0 on success, negative value otherwise. | 1142 | * Returns 0 on success, negative value otherwise. |
1203 | */ | 1143 | */ |
1204 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | 1144 | int tomoyo_path_perm(const u8 operation, struct path *path) |
1205 | const u8 operation, struct path *path) | ||
1206 | { | 1145 | { |
1207 | int error = -ENOMEM; | 1146 | int error = -ENOMEM; |
1208 | struct tomoyo_path_info *buf; | 1147 | struct tomoyo_path_info *buf; |
1148 | struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
1209 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1149 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1210 | const bool is_enforce = (mode == 3); | 1150 | const bool is_enforce = (mode == 3); |
1151 | int idx; | ||
1211 | 1152 | ||
1212 | if (!mode || !path->mnt) | 1153 | if (!mode || !path->mnt) |
1213 | return 0; | 1154 | return 0; |
1155 | idx = tomoyo_read_lock(); | ||
1214 | buf = tomoyo_get_path(path); | 1156 | buf = tomoyo_get_path(path); |
1215 | if (!buf) | 1157 | if (!buf) |
1216 | goto out; | 1158 | goto out; |
1217 | switch (operation) { | 1159 | switch (operation) { |
1218 | case TOMOYO_TYPE_MKDIR_ACL: | 1160 | case TOMOYO_TYPE_MKDIR: |
1219 | case TOMOYO_TYPE_RMDIR_ACL: | 1161 | case TOMOYO_TYPE_RMDIR: |
1162 | case TOMOYO_TYPE_CHROOT: | ||
1220 | if (!buf->is_dir) { | 1163 | if (!buf->is_dir) { |
1221 | /* | 1164 | /* |
1222 | * tomoyo_get_path() reserves space for appending "/." | 1165 | * tomoyo_get_path() reserves space for appending "/." |
@@ -1225,10 +1168,10 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | |||
1225 | tomoyo_fill_path_info(buf); | 1168 | tomoyo_fill_path_info(buf); |
1226 | } | 1169 | } |
1227 | } | 1170 | } |
1228 | error = tomoyo_check_single_path_permission2(domain, operation, buf, | 1171 | error = tomoyo_path_permission2(domain, operation, buf, mode); |
1229 | mode); | ||
1230 | out: | 1172 | out: |
1231 | tomoyo_free(buf); | 1173 | kfree(buf); |
1174 | tomoyo_read_unlock(idx); | ||
1232 | if (!is_enforce) | 1175 | if (!is_enforce) |
1233 | error = 0; | 1176 | error = 0; |
1234 | return error; | 1177 | return error; |
@@ -1237,21 +1180,23 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | |||
1237 | /** | 1180 | /** |
1238 | * tomoyo_check_rewrite_permission - Check permission for "rewrite". | 1181 | * tomoyo_check_rewrite_permission - Check permission for "rewrite". |
1239 | * | 1182 | * |
1240 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1241 | * @filp: Pointer to "struct file". | 1183 | * @filp: Pointer to "struct file". |
1242 | * | 1184 | * |
1243 | * Returns 0 on success, negative value otherwise. | 1185 | * Returns 0 on success, negative value otherwise. |
1244 | */ | 1186 | */ |
1245 | int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | 1187 | int tomoyo_check_rewrite_permission(struct file *filp) |
1246 | struct file *filp) | ||
1247 | { | 1188 | { |
1248 | int error = -ENOMEM; | 1189 | int error = -ENOMEM; |
1190 | struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
1249 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1191 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1250 | const bool is_enforce = (mode == 3); | 1192 | const bool is_enforce = (mode == 3); |
1251 | struct tomoyo_path_info *buf; | 1193 | struct tomoyo_path_info *buf; |
1194 | int idx; | ||
1252 | 1195 | ||
1253 | if (!mode || !filp->f_path.mnt) | 1196 | if (!mode || !filp->f_path.mnt) |
1254 | return 0; | 1197 | return 0; |
1198 | |||
1199 | idx = tomoyo_read_lock(); | ||
1255 | buf = tomoyo_get_path(&filp->f_path); | 1200 | buf = tomoyo_get_path(&filp->f_path); |
1256 | if (!buf) | 1201 | if (!buf) |
1257 | goto out; | 1202 | goto out; |
@@ -1259,38 +1204,38 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, | |||
1259 | error = 0; | 1204 | error = 0; |
1260 | goto out; | 1205 | goto out; |
1261 | } | 1206 | } |
1262 | error = tomoyo_check_single_path_permission2(domain, | 1207 | error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode); |
1263 | TOMOYO_TYPE_REWRITE_ACL, | ||
1264 | buf, mode); | ||
1265 | out: | 1208 | out: |
1266 | tomoyo_free(buf); | 1209 | kfree(buf); |
1210 | tomoyo_read_unlock(idx); | ||
1267 | if (!is_enforce) | 1211 | if (!is_enforce) |
1268 | error = 0; | 1212 | error = 0; |
1269 | return error; | 1213 | return error; |
1270 | } | 1214 | } |
1271 | 1215 | ||
1272 | /** | 1216 | /** |
1273 | * tomoyo_check_2path_perm - Check permission for "rename" and "link". | 1217 | * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". |
1274 | * | 1218 | * |
1275 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1276 | * @operation: Type of operation. | 1219 | * @operation: Type of operation. |
1277 | * @path1: Pointer to "struct path". | 1220 | * @path1: Pointer to "struct path". |
1278 | * @path2: Pointer to "struct path". | 1221 | * @path2: Pointer to "struct path". |
1279 | * | 1222 | * |
1280 | * Returns 0 on success, negative value otherwise. | 1223 | * Returns 0 on success, negative value otherwise. |
1281 | */ | 1224 | */ |
1282 | int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | 1225 | int tomoyo_path2_perm(const u8 operation, struct path *path1, |
1283 | const u8 operation, struct path *path1, | 1226 | struct path *path2) |
1284 | struct path *path2) | ||
1285 | { | 1227 | { |
1286 | int error = -ENOMEM; | 1228 | int error = -ENOMEM; |
1287 | struct tomoyo_path_info *buf1, *buf2; | 1229 | struct tomoyo_path_info *buf1, *buf2; |
1230 | struct tomoyo_domain_info *domain = tomoyo_domain(); | ||
1288 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1231 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1289 | const bool is_enforce = (mode == 3); | 1232 | const bool is_enforce = (mode == 3); |
1290 | const char *msg; | 1233 | const char *msg; |
1234 | int idx; | ||
1291 | 1235 | ||
1292 | if (!mode || !path1->mnt || !path2->mnt) | 1236 | if (!mode || !path1->mnt || !path2->mnt) |
1293 | return 0; | 1237 | return 0; |
1238 | idx = tomoyo_read_lock(); | ||
1294 | buf1 = tomoyo_get_path(path1); | 1239 | buf1 = tomoyo_get_path(path1); |
1295 | buf2 = tomoyo_get_path(path2); | 1240 | buf2 = tomoyo_get_path(path2); |
1296 | if (!buf1 || !buf2) | 1241 | if (!buf1 || !buf2) |
@@ -1311,8 +1256,8 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | |||
1311 | } | 1256 | } |
1312 | } | 1257 | } |
1313 | } | 1258 | } |
1314 | error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); | 1259 | error = tomoyo_path2_acl(domain, operation, buf1, buf2); |
1315 | msg = tomoyo_dp2keyword(operation); | 1260 | msg = tomoyo_path22keyword(operation); |
1316 | if (!error) | 1261 | if (!error) |
1317 | goto out; | 1262 | goto out; |
1318 | if (tomoyo_verbose_mode(domain)) | 1263 | if (tomoyo_verbose_mode(domain)) |
@@ -1323,12 +1268,13 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, | |||
1323 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { | 1268 | if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { |
1324 | const char *name1 = tomoyo_get_file_pattern(buf1)->name; | 1269 | const char *name1 = tomoyo_get_file_pattern(buf1)->name; |
1325 | const char *name2 = tomoyo_get_file_pattern(buf2)->name; | 1270 | const char *name2 = tomoyo_get_file_pattern(buf2)->name; |
1326 | tomoyo_update_double_path_acl(operation, name1, name2, domain, | 1271 | tomoyo_update_path2_acl(operation, name1, name2, domain, |
1327 | false); | 1272 | false); |
1328 | } | 1273 | } |
1329 | out: | 1274 | out: |
1330 | tomoyo_free(buf1); | 1275 | kfree(buf1); |
1331 | tomoyo_free(buf2); | 1276 | kfree(buf2); |
1277 | tomoyo_read_unlock(idx); | ||
1332 | if (!is_enforce) | 1278 | if (!is_enforce) |
1333 | error = 0; | 1279 | error = 0; |
1334 | return error; | 1280 | return error; |