diff options
Diffstat (limited to 'security/tomoyo/file.c')
-rw-r--r-- | security/tomoyo/file.c | 954 |
1 files changed, 389 insertions, 565 deletions
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index d64e8ecb6fb..743c35f5084 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -1,80 +1,51 @@ | |||
1 | /* | 1 | /* |
2 | * security/tomoyo/file.c | 2 | * security/tomoyo/file.c |
3 | * | 3 | * |
4 | * Pathname restriction functions. | 4 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
5 | * | ||
6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
7 | */ | 5 | */ |
8 | 6 | ||
9 | #include "common.h" | 7 | #include "common.h" |
10 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
11 | 9 | ||
12 | /* Keyword array for operations with one pathname. */ | 10 | /* |
13 | const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { | 11 | * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index". |
14 | [TOMOYO_TYPE_READ_WRITE] = "read/write", | 12 | */ |
15 | [TOMOYO_TYPE_EXECUTE] = "execute", | ||
16 | [TOMOYO_TYPE_READ] = "read", | ||
17 | [TOMOYO_TYPE_WRITE] = "write", | ||
18 | [TOMOYO_TYPE_UNLINK] = "unlink", | ||
19 | [TOMOYO_TYPE_RMDIR] = "rmdir", | ||
20 | [TOMOYO_TYPE_TRUNCATE] = "truncate", | ||
21 | [TOMOYO_TYPE_SYMLINK] = "symlink", | ||
22 | [TOMOYO_TYPE_REWRITE] = "rewrite", | ||
23 | [TOMOYO_TYPE_CHROOT] = "chroot", | ||
24 | [TOMOYO_TYPE_UMOUNT] = "unmount", | ||
25 | }; | ||
26 | |||
27 | /* Keyword array for operations with one pathname and three numbers. */ | ||
28 | const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = { | ||
29 | [TOMOYO_TYPE_MKBLOCK] = "mkblock", | ||
30 | [TOMOYO_TYPE_MKCHAR] = "mkchar", | ||
31 | }; | ||
32 | |||
33 | /* Keyword array for operations with two pathnames. */ | ||
34 | const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { | ||
35 | [TOMOYO_TYPE_LINK] = "link", | ||
36 | [TOMOYO_TYPE_RENAME] = "rename", | ||
37 | [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", | ||
38 | }; | ||
39 | |||
40 | /* Keyword array for operations with one pathname and one number. */ | ||
41 | const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | ||
42 | [TOMOYO_TYPE_CREATE] = "create", | ||
43 | [TOMOYO_TYPE_MKDIR] = "mkdir", | ||
44 | [TOMOYO_TYPE_MKFIFO] = "mkfifo", | ||
45 | [TOMOYO_TYPE_MKSOCK] = "mksock", | ||
46 | [TOMOYO_TYPE_IOCTL] = "ioctl", | ||
47 | [TOMOYO_TYPE_CHMOD] = "chmod", | ||
48 | [TOMOYO_TYPE_CHOWN] = "chown", | ||
49 | [TOMOYO_TYPE_CHGRP] = "chgrp", | ||
50 | }; | ||
51 | |||
52 | static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { | 13 | static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { |
53 | [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN, | ||
54 | [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, | 14 | [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, |
55 | [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, | 15 | [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, |
56 | [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, | 16 | [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, |
17 | [TOMOYO_TYPE_APPEND] = TOMOYO_MAC_FILE_OPEN, | ||
57 | [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, | 18 | [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, |
19 | [TOMOYO_TYPE_GETATTR] = TOMOYO_MAC_FILE_GETATTR, | ||
58 | [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, | 20 | [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, |
59 | [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, | 21 | [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, |
60 | [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, | 22 | [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, |
61 | [TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE, | ||
62 | [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, | 23 | [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, |
63 | [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, | 24 | [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, |
64 | }; | 25 | }; |
65 | 26 | ||
66 | static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { | 27 | /* |
28 | * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index". | ||
29 | */ | ||
30 | const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { | ||
67 | [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, | 31 | [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, |
68 | [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, | 32 | [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, |
69 | }; | 33 | }; |
70 | 34 | ||
71 | static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { | 35 | /* |
36 | * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index". | ||
37 | */ | ||
38 | const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { | ||
72 | [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, | 39 | [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, |
73 | [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, | 40 | [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, |
74 | [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, | 41 | [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, |
75 | }; | 42 | }; |
76 | 43 | ||
77 | static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | 44 | /* |
45 | * Mapping table from "enum tomoyo_path_number_acl_index" to | ||
46 | * "enum tomoyo_mac_index". | ||
47 | */ | ||
48 | const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | ||
78 | [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, | 49 | [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, |
79 | [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, | 50 | [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, |
80 | [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, | 51 | [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, |
@@ -85,41 +56,76 @@ static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { | |||
85 | [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, | 56 | [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, |
86 | }; | 57 | }; |
87 | 58 | ||
59 | /** | ||
60 | * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union". | ||
61 | * | ||
62 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
63 | * | ||
64 | * Returns nothing. | ||
65 | */ | ||
88 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr) | 66 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr) |
89 | { | 67 | { |
90 | if (!ptr) | 68 | tomoyo_put_group(ptr->group); |
91 | return; | 69 | tomoyo_put_name(ptr->filename); |
92 | if (ptr->is_group) | ||
93 | tomoyo_put_group(ptr->group); | ||
94 | else | ||
95 | tomoyo_put_name(ptr->filename); | ||
96 | } | 70 | } |
97 | 71 | ||
72 | /** | ||
73 | * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not. | ||
74 | * | ||
75 | * @name: Pointer to "struct tomoyo_path_info". | ||
76 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
77 | * | ||
78 | * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise. | ||
79 | */ | ||
98 | const struct tomoyo_path_info * | 80 | const struct tomoyo_path_info * |
99 | tomoyo_compare_name_union(const struct tomoyo_path_info *name, | 81 | tomoyo_compare_name_union(const struct tomoyo_path_info *name, |
100 | const struct tomoyo_name_union *ptr) | 82 | const struct tomoyo_name_union *ptr) |
101 | { | 83 | { |
102 | if (ptr->is_group) | 84 | if (ptr->group) |
103 | return tomoyo_path_matches_group(name, ptr->group); | 85 | return tomoyo_path_matches_group(name, ptr->group); |
104 | if (tomoyo_path_matches_pattern(name, ptr->filename)) | 86 | if (tomoyo_path_matches_pattern(name, ptr->filename)) |
105 | return ptr->filename; | 87 | return ptr->filename; |
106 | return NULL; | 88 | return NULL; |
107 | } | 89 | } |
108 | 90 | ||
91 | /** | ||
92 | * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union". | ||
93 | * | ||
94 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
95 | * | ||
96 | * Returns nothing. | ||
97 | */ | ||
109 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr) | 98 | void tomoyo_put_number_union(struct tomoyo_number_union *ptr) |
110 | { | 99 | { |
111 | if (ptr && ptr->is_group) | 100 | tomoyo_put_group(ptr->group); |
112 | tomoyo_put_group(ptr->group); | ||
113 | } | 101 | } |
114 | 102 | ||
103 | /** | ||
104 | * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not. | ||
105 | * | ||
106 | * @value: Number to check. | ||
107 | * @ptr: Pointer to "struct tomoyo_number_union". | ||
108 | * | ||
109 | * Returns true if @value matches @ptr, false otherwise. | ||
110 | */ | ||
115 | bool tomoyo_compare_number_union(const unsigned long value, | 111 | bool tomoyo_compare_number_union(const unsigned long value, |
116 | const struct tomoyo_number_union *ptr) | 112 | const struct tomoyo_number_union *ptr) |
117 | { | 113 | { |
118 | if (ptr->is_group) | 114 | if (ptr->group) |
119 | return tomoyo_number_matches_group(value, value, ptr->group); | 115 | return tomoyo_number_matches_group(value, value, ptr->group); |
120 | return value >= ptr->values[0] && value <= ptr->values[1]; | 116 | return value >= ptr->values[0] && value <= ptr->values[1]; |
121 | } | 117 | } |
122 | 118 | ||
119 | /** | ||
120 | * tomoyo_add_slash - Add trailing '/' if needed. | ||
121 | * | ||
122 | * @buf: Pointer to "struct tomoyo_path_info". | ||
123 | * | ||
124 | * Returns nothing. | ||
125 | * | ||
126 | * @buf must be generated by tomoyo_encode() because this function does not | ||
127 | * allocate memory for adding '/'. | ||
128 | */ | ||
123 | static void tomoyo_add_slash(struct tomoyo_path_info *buf) | 129 | static void tomoyo_add_slash(struct tomoyo_path_info *buf) |
124 | { | 130 | { |
125 | if (buf->is_dir) | 131 | if (buf->is_dir) |
@@ -132,24 +138,6 @@ static void tomoyo_add_slash(struct tomoyo_path_info *buf) | |||
132 | } | 138 | } |
133 | 139 | ||
134 | /** | 140 | /** |
135 | * tomoyo_strendswith - Check whether the token ends with the given token. | ||
136 | * | ||
137 | * @name: The token to check. | ||
138 | * @tail: The token to find. | ||
139 | * | ||
140 | * Returns true if @name ends with @tail, false otherwise. | ||
141 | */ | ||
142 | static bool tomoyo_strendswith(const char *name, const char *tail) | ||
143 | { | ||
144 | int len; | ||
145 | |||
146 | if (!name || !tail) | ||
147 | return false; | ||
148 | len = strlen(name) - strlen(tail); | ||
149 | return len >= 0 && !strcmp(name + len, tail); | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * tomoyo_get_realpath - Get realpath. | 141 | * tomoyo_get_realpath - Get realpath. |
154 | * | 142 | * |
155 | * @buf: Pointer to "struct tomoyo_path_info". | 143 | * @buf: Pointer to "struct tomoyo_path_info". |
@@ -164,7 +152,7 @@ static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) | |||
164 | tomoyo_fill_path_info(buf); | 152 | tomoyo_fill_path_info(buf); |
165 | return true; | 153 | return true; |
166 | } | 154 | } |
167 | return false; | 155 | return false; |
168 | } | 156 | } |
169 | 157 | ||
170 | /** | 158 | /** |
@@ -176,13 +164,9 @@ static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) | |||
176 | */ | 164 | */ |
177 | static int tomoyo_audit_path_log(struct tomoyo_request_info *r) | 165 | static int tomoyo_audit_path_log(struct tomoyo_request_info *r) |
178 | { | 166 | { |
179 | const char *operation = tomoyo_path_keyword[r->param.path.operation]; | 167 | return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword |
180 | const struct tomoyo_path_info *filename = r->param.path.filename; | 168 | [r->param.path.operation], |
181 | if (r->granted) | 169 | r->param.path.filename->name); |
182 | return 0; | ||
183 | tomoyo_warn_log(r, "%s %s", operation, filename->name); | ||
184 | return tomoyo_supervisor(r, "allow_%s %s\n", operation, | ||
185 | tomoyo_pattern(filename)); | ||
186 | } | 170 | } |
187 | 171 | ||
188 | /** | 172 | /** |
@@ -194,16 +178,10 @@ static int tomoyo_audit_path_log(struct tomoyo_request_info *r) | |||
194 | */ | 178 | */ |
195 | static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) | 179 | static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) |
196 | { | 180 | { |
197 | const char *operation = tomoyo_path2_keyword[r->param.path2.operation]; | 181 | return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords |
198 | const struct tomoyo_path_info *filename1 = r->param.path2.filename1; | 182 | [tomoyo_pp2mac[r->param.path2.operation]], |
199 | const struct tomoyo_path_info *filename2 = r->param.path2.filename2; | 183 | r->param.path2.filename1->name, |
200 | if (r->granted) | 184 | r->param.path2.filename2->name); |
201 | return 0; | ||
202 | tomoyo_warn_log(r, "%s %s %s", operation, filename1->name, | ||
203 | filename2->name); | ||
204 | return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, | ||
205 | tomoyo_pattern(filename1), | ||
206 | tomoyo_pattern(filename2)); | ||
207 | } | 185 | } |
208 | 186 | ||
209 | /** | 187 | /** |
@@ -215,24 +193,18 @@ static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) | |||
215 | */ | 193 | */ |
216 | static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) | 194 | static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) |
217 | { | 195 | { |
218 | const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation]; | 196 | return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n", |
219 | const struct tomoyo_path_info *filename = r->param.mkdev.filename; | 197 | tomoyo_mac_keywords |
220 | const unsigned int major = r->param.mkdev.major; | 198 | [tomoyo_pnnn2mac[r->param.mkdev.operation]], |
221 | const unsigned int minor = r->param.mkdev.minor; | 199 | r->param.mkdev.filename->name, |
222 | const unsigned int mode = r->param.mkdev.mode; | 200 | r->param.mkdev.mode, r->param.mkdev.major, |
223 | if (r->granted) | 201 | r->param.mkdev.minor); |
224 | return 0; | ||
225 | tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode, | ||
226 | major, minor); | ||
227 | return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation, | ||
228 | tomoyo_pattern(filename), mode, major, minor); | ||
229 | } | 202 | } |
230 | 203 | ||
231 | /** | 204 | /** |
232 | * tomoyo_audit_path_number_log - Audit path/number request log. | 205 | * tomoyo_audit_path_number_log - Audit path/number request log. |
233 | * | 206 | * |
234 | * @r: Pointer to "struct tomoyo_request_info". | 207 | * @r: Pointer to "struct tomoyo_request_info". |
235 | * @error: Error code. | ||
236 | * | 208 | * |
237 | * Returns 0 on success, negative value otherwise. | 209 | * Returns 0 on success, negative value otherwise. |
238 | */ | 210 | */ |
@@ -240,11 +212,7 @@ static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) | |||
240 | { | 212 | { |
241 | const u8 type = r->param.path_number.operation; | 213 | const u8 type = r->param.path_number.operation; |
242 | u8 radix; | 214 | u8 radix; |
243 | const struct tomoyo_path_info *filename = r->param.path_number.filename; | ||
244 | const char *operation = tomoyo_path_number_keyword[type]; | ||
245 | char buffer[64]; | 215 | char buffer[64]; |
246 | if (r->granted) | ||
247 | return 0; | ||
248 | switch (type) { | 216 | switch (type) { |
249 | case TOMOYO_TYPE_CREATE: | 217 | case TOMOYO_TYPE_CREATE: |
250 | case TOMOYO_TYPE_MKDIR: | 218 | case TOMOYO_TYPE_MKDIR: |
@@ -262,251 +230,23 @@ static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) | |||
262 | } | 230 | } |
263 | tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, | 231 | tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, |
264 | radix); | 232 | radix); |
265 | tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer); | 233 | return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords |
266 | return tomoyo_supervisor(r, "allow_%s %s %s\n", operation, | 234 | [tomoyo_pn2mac[type]], |
267 | tomoyo_pattern(filename), buffer); | 235 | r->param.path_number.filename->name, buffer); |
268 | } | ||
269 | |||
270 | static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a, | ||
271 | const struct tomoyo_acl_head *b) | ||
272 | { | ||
273 | return container_of(a, struct tomoyo_readable_file, | ||
274 | head)->filename == | ||
275 | container_of(b, struct tomoyo_readable_file, | ||
276 | head)->filename; | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list. | ||
281 | * | ||
282 | * @filename: Filename unconditionally permitted to open() for reading. | ||
283 | * @is_delete: True if it is a delete request. | ||
284 | * | ||
285 | * Returns 0 on success, negative value otherwise. | ||
286 | * | ||
287 | * Caller holds tomoyo_read_lock(). | ||
288 | */ | ||
289 | static int tomoyo_update_globally_readable_entry(const char *filename, | ||
290 | const bool is_delete) | ||
291 | { | ||
292 | struct tomoyo_readable_file e = { }; | ||
293 | int error; | ||
294 | |||
295 | if (!tomoyo_correct_word(filename)) | ||
296 | return -EINVAL; | ||
297 | e.filename = tomoyo_get_name(filename); | ||
298 | if (!e.filename) | ||
299 | return -ENOMEM; | ||
300 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | ||
301 | &tomoyo_policy_list | ||
302 | [TOMOYO_ID_GLOBALLY_READABLE], | ||
303 | tomoyo_same_globally_readable); | ||
304 | tomoyo_put_name(e.filename); | ||
305 | return error; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. | ||
310 | * | ||
311 | * @filename: The filename to check. | ||
312 | * | ||
313 | * Returns true if any domain can open @filename for reading, false otherwise. | ||
314 | * | ||
315 | * Caller holds tomoyo_read_lock(). | ||
316 | */ | ||
317 | static bool tomoyo_globally_readable_file(const struct tomoyo_path_info * | ||
318 | filename) | ||
319 | { | ||
320 | struct tomoyo_readable_file *ptr; | ||
321 | bool found = false; | ||
322 | |||
323 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list | ||
324 | [TOMOYO_ID_GLOBALLY_READABLE], head.list) { | ||
325 | if (!ptr->head.is_deleted && | ||
326 | tomoyo_path_matches_pattern(filename, ptr->filename)) { | ||
327 | found = true; | ||
328 | break; | ||
329 | } | ||
330 | } | ||
331 | return found; | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list. | ||
336 | * | ||
337 | * @data: String to parse. | ||
338 | * @is_delete: True if it is a delete request. | ||
339 | * | ||
340 | * Returns 0 on success, negative value otherwise. | ||
341 | * | ||
342 | * Caller holds tomoyo_read_lock(). | ||
343 | */ | ||
344 | int tomoyo_write_globally_readable(char *data, const bool is_delete) | ||
345 | { | ||
346 | return tomoyo_update_globally_readable_entry(data, is_delete); | ||
347 | } | ||
348 | |||
349 | static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a, | ||
350 | const struct tomoyo_acl_head *b) | ||
351 | { | ||
352 | return container_of(a, struct tomoyo_no_pattern, head)->pattern == | ||
353 | container_of(b, struct tomoyo_no_pattern, head)->pattern; | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list. | ||
358 | * | ||
359 | * @pattern: Pathname pattern. | ||
360 | * @is_delete: True if it is a delete request. | ||
361 | * | ||
362 | * Returns 0 on success, negative value otherwise. | ||
363 | * | ||
364 | * Caller holds tomoyo_read_lock(). | ||
365 | */ | ||
366 | static int tomoyo_update_file_pattern_entry(const char *pattern, | ||
367 | const bool is_delete) | ||
368 | { | ||
369 | struct tomoyo_no_pattern e = { }; | ||
370 | int error; | ||
371 | |||
372 | if (!tomoyo_correct_word(pattern)) | ||
373 | return -EINVAL; | ||
374 | e.pattern = tomoyo_get_name(pattern); | ||
375 | if (!e.pattern) | ||
376 | return -ENOMEM; | ||
377 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | ||
378 | &tomoyo_policy_list[TOMOYO_ID_PATTERN], | ||
379 | tomoyo_same_pattern); | ||
380 | tomoyo_put_name(e.pattern); | ||
381 | return error; | ||
382 | } | ||
383 | |||
384 | /** | ||
385 | * tomoyo_pattern - Get patterned pathname. | ||
386 | * | ||
387 | * @filename: The filename to find patterned pathname. | ||
388 | * | ||
389 | * Returns pointer to pathname pattern if matched, @filename otherwise. | ||
390 | * | ||
391 | * Caller holds tomoyo_read_lock(). | ||
392 | */ | ||
393 | const char *tomoyo_pattern(const struct tomoyo_path_info *filename) | ||
394 | { | ||
395 | struct tomoyo_no_pattern *ptr; | ||
396 | const struct tomoyo_path_info *pattern = NULL; | ||
397 | |||
398 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN], | ||
399 | head.list) { | ||
400 | if (ptr->head.is_deleted) | ||
401 | continue; | ||
402 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | ||
403 | continue; | ||
404 | pattern = ptr->pattern; | ||
405 | if (tomoyo_strendswith(pattern->name, "/\\*")) { | ||
406 | /* Do nothing. Try to find the better match. */ | ||
407 | } else { | ||
408 | /* This would be the better match. Use this. */ | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | if (pattern) | ||
413 | filename = pattern; | ||
414 | return filename->name; | ||
415 | } | ||
416 | |||
417 | /** | ||
418 | * tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list. | ||
419 | * | ||
420 | * @data: String to parse. | ||
421 | * @is_delete: True if it is a delete request. | ||
422 | * | ||
423 | * Returns 0 on success, negative value otherwise. | ||
424 | * | ||
425 | * Caller holds tomoyo_read_lock(). | ||
426 | */ | ||
427 | int tomoyo_write_pattern(char *data, const bool is_delete) | ||
428 | { | ||
429 | return tomoyo_update_file_pattern_entry(data, is_delete); | ||
430 | } | ||
431 | |||
432 | static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a, | ||
433 | const struct tomoyo_acl_head *b) | ||
434 | { | ||
435 | return container_of(a, struct tomoyo_no_rewrite, head)->pattern | ||
436 | == container_of(b, struct tomoyo_no_rewrite, head) | ||
437 | ->pattern; | ||
438 | } | ||
439 | |||
440 | /** | ||
441 | * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list. | ||
442 | * | ||
443 | * @pattern: Pathname pattern that are not rewritable by default. | ||
444 | * @is_delete: True if it is a delete request. | ||
445 | * | ||
446 | * Returns 0 on success, negative value otherwise. | ||
447 | * | ||
448 | * Caller holds tomoyo_read_lock(). | ||
449 | */ | ||
450 | static int tomoyo_update_no_rewrite_entry(const char *pattern, | ||
451 | const bool is_delete) | ||
452 | { | ||
453 | struct tomoyo_no_rewrite e = { }; | ||
454 | int error; | ||
455 | |||
456 | if (!tomoyo_correct_word(pattern)) | ||
457 | return -EINVAL; | ||
458 | e.pattern = tomoyo_get_name(pattern); | ||
459 | if (!e.pattern) | ||
460 | return -ENOMEM; | ||
461 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | ||
462 | &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE], | ||
463 | tomoyo_same_no_rewrite); | ||
464 | tomoyo_put_name(e.pattern); | ||
465 | return error; | ||
466 | } | 236 | } |
467 | 237 | ||
468 | /** | 238 | /** |
469 | * tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. | 239 | * tomoyo_check_path_acl - Check permission for path operation. |
470 | * | 240 | * |
471 | * @filename: Filename to check. | 241 | * @r: Pointer to "struct tomoyo_request_info". |
242 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
472 | * | 243 | * |
473 | * Returns true if @filename is specified by "deny_rewrite" directive, | 244 | * Returns true if granted, false otherwise. |
474 | * false otherwise. | ||
475 | * | 245 | * |
476 | * Caller holds tomoyo_read_lock(). | 246 | * To be able to use wildcard for domain transition, this function sets |
247 | * matching entry on success. Since the caller holds tomoyo_read_lock(), | ||
248 | * it is safe to set matching entry. | ||
477 | */ | 249 | */ |
478 | static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename) | ||
479 | { | ||
480 | struct tomoyo_no_rewrite *ptr; | ||
481 | bool found = false; | ||
482 | |||
483 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE], | ||
484 | head.list) { | ||
485 | if (ptr->head.is_deleted) | ||
486 | continue; | ||
487 | if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) | ||
488 | continue; | ||
489 | found = true; | ||
490 | break; | ||
491 | } | ||
492 | return found; | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list. | ||
497 | * | ||
498 | * @data: String to parse. | ||
499 | * @is_delete: True if it is a delete request. | ||
500 | * | ||
501 | * Returns 0 on success, negative value otherwise. | ||
502 | * | ||
503 | * Caller holds tomoyo_read_lock(). | ||
504 | */ | ||
505 | int tomoyo_write_no_rewrite(char *data, const bool is_delete) | ||
506 | { | ||
507 | return tomoyo_update_no_rewrite_entry(data, is_delete); | ||
508 | } | ||
509 | |||
510 | static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, | 250 | static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, |
511 | const struct tomoyo_acl_info *ptr) | 251 | const struct tomoyo_acl_info *ptr) |
512 | { | 252 | { |
@@ -521,6 +261,14 @@ static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, | |||
521 | return false; | 261 | return false; |
522 | } | 262 | } |
523 | 263 | ||
264 | /** | ||
265 | * tomoyo_check_path_number_acl - Check permission for path number operation. | ||
266 | * | ||
267 | * @r: Pointer to "struct tomoyo_request_info". | ||
268 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
269 | * | ||
270 | * Returns true if granted, false otherwise. | ||
271 | */ | ||
524 | static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, | 272 | static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, |
525 | const struct tomoyo_acl_info *ptr) | 273 | const struct tomoyo_acl_info *ptr) |
526 | { | 274 | { |
@@ -533,6 +281,14 @@ static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, | |||
533 | &acl->name); | 281 | &acl->name); |
534 | } | 282 | } |
535 | 283 | ||
284 | /** | ||
285 | * tomoyo_check_path2_acl - Check permission for path path operation. | ||
286 | * | ||
287 | * @r: Pointer to "struct tomoyo_request_info". | ||
288 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
289 | * | ||
290 | * Returns true if granted, false otherwise. | ||
291 | */ | ||
536 | static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, | 292 | static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, |
537 | const struct tomoyo_acl_info *ptr) | 293 | const struct tomoyo_acl_info *ptr) |
538 | { | 294 | { |
@@ -544,8 +300,16 @@ static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, | |||
544 | &acl->name2); | 300 | &acl->name2); |
545 | } | 301 | } |
546 | 302 | ||
303 | /** | ||
304 | * tomoyo_check_mkdev_acl - Check permission for path number number number operation. | ||
305 | * | ||
306 | * @r: Pointer to "struct tomoyo_request_info". | ||
307 | * @ptr: Pointer to "struct tomoyo_acl_info". | ||
308 | * | ||
309 | * Returns true if granted, false otherwise. | ||
310 | */ | ||
547 | static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, | 311 | static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, |
548 | const struct tomoyo_acl_info *ptr) | 312 | const struct tomoyo_acl_info *ptr) |
549 | { | 313 | { |
550 | const struct tomoyo_mkdev_acl *acl = | 314 | const struct tomoyo_mkdev_acl *acl = |
551 | container_of(ptr, typeof(*acl), head); | 315 | container_of(ptr, typeof(*acl), head); |
@@ -560,15 +324,31 @@ static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, | |||
560 | &acl->name); | 324 | &acl->name); |
561 | } | 325 | } |
562 | 326 | ||
327 | /** | ||
328 | * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry. | ||
329 | * | ||
330 | * @a: Pointer to "struct tomoyo_acl_info". | ||
331 | * @b: Pointer to "struct tomoyo_acl_info". | ||
332 | * | ||
333 | * Returns true if @a == @b except permission bits, false otherwise. | ||
334 | */ | ||
563 | static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, | 335 | static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, |
564 | const struct tomoyo_acl_info *b) | 336 | const struct tomoyo_acl_info *b) |
565 | { | 337 | { |
566 | const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); | 338 | const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); |
567 | const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); | 339 | const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); |
568 | return tomoyo_same_acl_head(&p1->head, &p2->head) && | 340 | return tomoyo_same_name_union(&p1->name, &p2->name); |
569 | tomoyo_same_name_union(&p1->name, &p2->name); | ||
570 | } | 341 | } |
571 | 342 | ||
343 | /** | ||
344 | * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry. | ||
345 | * | ||
346 | * @a: Pointer to "struct tomoyo_acl_info". | ||
347 | * @b: Pointer to "struct tomoyo_acl_info". | ||
348 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
349 | * | ||
350 | * Returns true if @a is empty, false otherwise. | ||
351 | */ | ||
572 | static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, | 352 | static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, |
573 | struct tomoyo_acl_info *b, | 353 | struct tomoyo_acl_info *b, |
574 | const bool is_delete) | 354 | const bool is_delete) |
@@ -577,19 +357,10 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, | |||
577 | ->perm; | 357 | ->perm; |
578 | u16 perm = *a_perm; | 358 | u16 perm = *a_perm; |
579 | const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; | 359 | const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; |
580 | if (is_delete) { | 360 | if (is_delete) |
581 | perm &= ~b_perm; | 361 | perm &= ~b_perm; |
582 | if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK) | 362 | else |
583 | perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); | ||
584 | else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE))) | ||
585 | perm &= ~TOMOYO_RW_MASK; | ||
586 | } else { | ||
587 | perm |= b_perm; | 363 | perm |= b_perm; |
588 | if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK) | ||
589 | perm |= (1 << TOMOYO_TYPE_READ_WRITE); | ||
590 | else if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) | ||
591 | perm |= TOMOYO_RW_MASK; | ||
592 | } | ||
593 | *a_perm = perm; | 364 | *a_perm = perm; |
594 | return !perm; | 365 | return !perm; |
595 | } | 366 | } |
@@ -597,52 +368,62 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, | |||
597 | /** | 368 | /** |
598 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. | 369 | * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. |
599 | * | 370 | * |
600 | * @type: Type of operation. | 371 | * @perm: Permission. |
601 | * @filename: Filename. | 372 | * @param: Pointer to "struct tomoyo_acl_param". |
602 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
603 | * @is_delete: True if it is a delete request. | ||
604 | * | 373 | * |
605 | * Returns 0 on success, negative value otherwise. | 374 | * Returns 0 on success, negative value otherwise. |
606 | * | 375 | * |
607 | * Caller holds tomoyo_read_lock(). | 376 | * Caller holds tomoyo_read_lock(). |
608 | */ | 377 | */ |
609 | static int tomoyo_update_path_acl(const u8 type, const char *filename, | 378 | static int tomoyo_update_path_acl(const u16 perm, |
610 | struct tomoyo_domain_info * const domain, | 379 | struct tomoyo_acl_param *param) |
611 | const bool is_delete) | ||
612 | { | 380 | { |
613 | struct tomoyo_path_acl e = { | 381 | struct tomoyo_path_acl e = { |
614 | .head.type = TOMOYO_TYPE_PATH_ACL, | 382 | .head.type = TOMOYO_TYPE_PATH_ACL, |
615 | .perm = 1 << type | 383 | .perm = perm |
616 | }; | 384 | }; |
617 | int error; | 385 | int error; |
618 | if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE)) | 386 | if (!tomoyo_parse_name_union(param, &e.name)) |
619 | e.perm |= TOMOYO_RW_MASK; | 387 | error = -EINVAL; |
620 | if (!tomoyo_parse_name_union(filename, &e.name)) | 388 | else |
621 | return -EINVAL; | 389 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
622 | error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | 390 | tomoyo_same_path_acl, |
623 | tomoyo_same_path_acl, | 391 | tomoyo_merge_path_acl); |
624 | tomoyo_merge_path_acl); | ||
625 | tomoyo_put_name_union(&e.name); | 392 | tomoyo_put_name_union(&e.name); |
626 | return error; | 393 | return error; |
627 | } | 394 | } |
628 | 395 | ||
396 | /** | ||
397 | * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry. | ||
398 | * | ||
399 | * @a: Pointer to "struct tomoyo_acl_info". | ||
400 | * @b: Pointer to "struct tomoyo_acl_info". | ||
401 | * | ||
402 | * Returns true if @a == @b except permission bits, false otherwise. | ||
403 | */ | ||
629 | static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, | 404 | static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, |
630 | const struct tomoyo_acl_info *b) | 405 | const struct tomoyo_acl_info *b) |
631 | { | 406 | { |
632 | const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), | 407 | const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head); |
633 | head); | 408 | const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head); |
634 | const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), | 409 | return tomoyo_same_name_union(&p1->name, &p2->name) && |
635 | head); | 410 | tomoyo_same_number_union(&p1->mode, &p2->mode) && |
636 | return tomoyo_same_acl_head(&p1->head, &p2->head) | 411 | tomoyo_same_number_union(&p1->major, &p2->major) && |
637 | && tomoyo_same_name_union(&p1->name, &p2->name) | 412 | tomoyo_same_number_union(&p1->minor, &p2->minor); |
638 | && tomoyo_same_number_union(&p1->mode, &p2->mode) | ||
639 | && tomoyo_same_number_union(&p1->major, &p2->major) | ||
640 | && tomoyo_same_number_union(&p1->minor, &p2->minor); | ||
641 | } | 413 | } |
642 | 414 | ||
415 | /** | ||
416 | * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry. | ||
417 | * | ||
418 | * @a: Pointer to "struct tomoyo_acl_info". | ||
419 | * @b: Pointer to "struct tomoyo_acl_info". | ||
420 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
421 | * | ||
422 | * Returns true if @a is empty, false otherwise. | ||
423 | */ | ||
643 | static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, | 424 | static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, |
644 | struct tomoyo_acl_info *b, | 425 | struct tomoyo_acl_info *b, |
645 | const bool is_delete) | 426 | const bool is_delete) |
646 | { | 427 | { |
647 | u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, | 428 | u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, |
648 | head)->perm; | 429 | head)->perm; |
@@ -660,37 +441,30 @@ static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, | |||
660 | /** | 441 | /** |
661 | * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. | 442 | * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. |
662 | * | 443 | * |
663 | * @type: Type of operation. | 444 | * @perm: Permission. |
664 | * @filename: Filename. | 445 | * @param: Pointer to "struct tomoyo_acl_param". |
665 | * @mode: Create mode. | ||
666 | * @major: Device major number. | ||
667 | * @minor: Device minor number. | ||
668 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
669 | * @is_delete: True if it is a delete request. | ||
670 | * | 446 | * |
671 | * Returns 0 on success, negative value otherwise. | 447 | * Returns 0 on success, negative value otherwise. |
672 | * | 448 | * |
673 | * Caller holds tomoyo_read_lock(). | 449 | * Caller holds tomoyo_read_lock(). |
674 | */ | 450 | */ |
675 | static int tomoyo_update_mkdev_acl(const u8 type, const char *filename, | 451 | static int tomoyo_update_mkdev_acl(const u8 perm, |
676 | char *mode, char *major, char *minor, | 452 | struct tomoyo_acl_param *param) |
677 | struct tomoyo_domain_info * const | ||
678 | domain, const bool is_delete) | ||
679 | { | 453 | { |
680 | struct tomoyo_mkdev_acl e = { | 454 | struct tomoyo_mkdev_acl e = { |
681 | .head.type = TOMOYO_TYPE_MKDEV_ACL, | 455 | .head.type = TOMOYO_TYPE_MKDEV_ACL, |
682 | .perm = 1 << type | 456 | .perm = perm |
683 | }; | 457 | }; |
684 | int error = is_delete ? -ENOENT : -ENOMEM; | 458 | int error; |
685 | if (!tomoyo_parse_name_union(filename, &e.name) || | 459 | if (!tomoyo_parse_name_union(param, &e.name) || |
686 | !tomoyo_parse_number_union(mode, &e.mode) || | 460 | !tomoyo_parse_number_union(param, &e.mode) || |
687 | !tomoyo_parse_number_union(major, &e.major) || | 461 | !tomoyo_parse_number_union(param, &e.major) || |
688 | !tomoyo_parse_number_union(minor, &e.minor)) | 462 | !tomoyo_parse_number_union(param, &e.minor)) |
689 | goto out; | 463 | error = -EINVAL; |
690 | error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | 464 | else |
691 | tomoyo_same_mkdev_acl, | 465 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
692 | tomoyo_merge_mkdev_acl); | 466 | tomoyo_same_mkdev_acl, |
693 | out: | 467 | tomoyo_merge_mkdev_acl); |
694 | tomoyo_put_name_union(&e.name); | 468 | tomoyo_put_name_union(&e.name); |
695 | tomoyo_put_number_union(&e.mode); | 469 | tomoyo_put_number_union(&e.mode); |
696 | tomoyo_put_number_union(&e.major); | 470 | tomoyo_put_number_union(&e.major); |
@@ -698,16 +472,32 @@ static int tomoyo_update_mkdev_acl(const u8 type, const char *filename, | |||
698 | return error; | 472 | return error; |
699 | } | 473 | } |
700 | 474 | ||
475 | /** | ||
476 | * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry. | ||
477 | * | ||
478 | * @a: Pointer to "struct tomoyo_acl_info". | ||
479 | * @b: Pointer to "struct tomoyo_acl_info". | ||
480 | * | ||
481 | * Returns true if @a == @b except permission bits, false otherwise. | ||
482 | */ | ||
701 | static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, | 483 | static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, |
702 | const struct tomoyo_acl_info *b) | 484 | const struct tomoyo_acl_info *b) |
703 | { | 485 | { |
704 | const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); | 486 | const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); |
705 | const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); | 487 | const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); |
706 | return tomoyo_same_acl_head(&p1->head, &p2->head) | 488 | return tomoyo_same_name_union(&p1->name1, &p2->name1) && |
707 | && tomoyo_same_name_union(&p1->name1, &p2->name1) | 489 | tomoyo_same_name_union(&p1->name2, &p2->name2); |
708 | && tomoyo_same_name_union(&p1->name2, &p2->name2); | ||
709 | } | 490 | } |
710 | 491 | ||
492 | /** | ||
493 | * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry. | ||
494 | * | ||
495 | * @a: Pointer to "struct tomoyo_acl_info". | ||
496 | * @b: Pointer to "struct tomoyo_acl_info". | ||
497 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
498 | * | ||
499 | * Returns true if @a is empty, false otherwise. | ||
500 | */ | ||
711 | static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, | 501 | static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, |
712 | struct tomoyo_acl_info *b, | 502 | struct tomoyo_acl_info *b, |
713 | const bool is_delete) | 503 | const bool is_delete) |
@@ -727,33 +517,28 @@ static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, | |||
727 | /** | 517 | /** |
728 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. | 518 | * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. |
729 | * | 519 | * |
730 | * @type: Type of operation. | 520 | * @perm: Permission. |
731 | * @filename1: First filename. | 521 | * @param: Pointer to "struct tomoyo_acl_param". |
732 | * @filename2: Second filename. | ||
733 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
734 | * @is_delete: True if it is a delete request. | ||
735 | * | 522 | * |
736 | * Returns 0 on success, negative value otherwise. | 523 | * Returns 0 on success, negative value otherwise. |
737 | * | 524 | * |
738 | * Caller holds tomoyo_read_lock(). | 525 | * Caller holds tomoyo_read_lock(). |
739 | */ | 526 | */ |
740 | static int tomoyo_update_path2_acl(const u8 type, const char *filename1, | 527 | static int tomoyo_update_path2_acl(const u8 perm, |
741 | const char *filename2, | 528 | struct tomoyo_acl_param *param) |
742 | struct tomoyo_domain_info * const domain, | ||
743 | const bool is_delete) | ||
744 | { | 529 | { |
745 | struct tomoyo_path2_acl e = { | 530 | struct tomoyo_path2_acl e = { |
746 | .head.type = TOMOYO_TYPE_PATH2_ACL, | 531 | .head.type = TOMOYO_TYPE_PATH2_ACL, |
747 | .perm = 1 << type | 532 | .perm = perm |
748 | }; | 533 | }; |
749 | int error = is_delete ? -ENOENT : -ENOMEM; | 534 | int error; |
750 | if (!tomoyo_parse_name_union(filename1, &e.name1) || | 535 | if (!tomoyo_parse_name_union(param, &e.name1) || |
751 | !tomoyo_parse_name_union(filename2, &e.name2)) | 536 | !tomoyo_parse_name_union(param, &e.name2)) |
752 | goto out; | 537 | error = -EINVAL; |
753 | error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | 538 | else |
754 | tomoyo_same_path2_acl, | 539 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
755 | tomoyo_merge_path2_acl); | 540 | tomoyo_same_path2_acl, |
756 | out: | 541 | tomoyo_merge_path2_acl); |
757 | tomoyo_put_name_union(&e.name1); | 542 | tomoyo_put_name_union(&e.name1); |
758 | tomoyo_put_name_union(&e.name2); | 543 | tomoyo_put_name_union(&e.name2); |
759 | return error; | 544 | return error; |
@@ -775,9 +560,8 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
775 | { | 560 | { |
776 | int error; | 561 | int error; |
777 | 562 | ||
778 | next: | ||
779 | r->type = tomoyo_p2mac[operation]; | 563 | r->type = tomoyo_p2mac[operation]; |
780 | r->mode = tomoyo_get_mode(r->profile, r->type); | 564 | r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); |
781 | if (r->mode == TOMOYO_CONFIG_DISABLED) | 565 | if (r->mode == TOMOYO_CONFIG_DISABLED) |
782 | return 0; | 566 | return 0; |
783 | r->param_type = TOMOYO_TYPE_PATH_ACL; | 567 | r->param_type = TOMOYO_TYPE_PATH_ACL; |
@@ -785,10 +569,6 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
785 | r->param.path.operation = operation; | 569 | r->param.path.operation = operation; |
786 | do { | 570 | do { |
787 | tomoyo_check_acl(r, tomoyo_check_path_acl); | 571 | tomoyo_check_acl(r, tomoyo_check_path_acl); |
788 | if (!r->granted && operation == TOMOYO_TYPE_READ && | ||
789 | !r->domain->ignore_global_allow_read && | ||
790 | tomoyo_globally_readable_file(filename)) | ||
791 | r->granted = true; | ||
792 | error = tomoyo_audit_path_log(r); | 572 | error = tomoyo_audit_path_log(r); |
793 | /* | 573 | /* |
794 | * Do not retry for execute request, for alias may have | 574 | * Do not retry for execute request, for alias may have |
@@ -796,19 +576,17 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, | |||
796 | */ | 576 | */ |
797 | } while (error == TOMOYO_RETRY_REQUEST && | 577 | } while (error == TOMOYO_RETRY_REQUEST && |
798 | operation != TOMOYO_TYPE_EXECUTE); | 578 | operation != TOMOYO_TYPE_EXECUTE); |
799 | /* | ||
800 | * Since "allow_truncate" doesn't imply "allow_rewrite" permission, | ||
801 | * we need to check "allow_rewrite" permission if the filename is | ||
802 | * specified by "deny_rewrite" keyword. | ||
803 | */ | ||
804 | if (!error && operation == TOMOYO_TYPE_TRUNCATE && | ||
805 | tomoyo_no_rewrite_file(filename)) { | ||
806 | operation = TOMOYO_TYPE_REWRITE; | ||
807 | goto next; | ||
808 | } | ||
809 | return error; | 579 | return error; |
810 | } | 580 | } |
811 | 581 | ||
582 | /** | ||
583 | * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. | ||
584 | * | ||
585 | * @a: Pointer to "struct tomoyo_acl_info". | ||
586 | * @b: Pointer to "struct tomoyo_acl_info". | ||
587 | * | ||
588 | * Returns true if @a == @b except permission bits, false otherwise. | ||
589 | */ | ||
812 | static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, | 590 | static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, |
813 | const struct tomoyo_acl_info *b) | 591 | const struct tomoyo_acl_info *b) |
814 | { | 592 | { |
@@ -816,11 +594,19 @@ static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, | |||
816 | head); | 594 | head); |
817 | const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), | 595 | const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), |
818 | head); | 596 | head); |
819 | return tomoyo_same_acl_head(&p1->head, &p2->head) | 597 | return tomoyo_same_name_union(&p1->name, &p2->name) && |
820 | && tomoyo_same_name_union(&p1->name, &p2->name) | 598 | tomoyo_same_number_union(&p1->number, &p2->number); |
821 | && tomoyo_same_number_union(&p1->number, &p2->number); | ||
822 | } | 599 | } |
823 | 600 | ||
601 | /** | ||
602 | * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry. | ||
603 | * | ||
604 | * @a: Pointer to "struct tomoyo_acl_info". | ||
605 | * @b: Pointer to "struct tomoyo_acl_info". | ||
606 | * @is_delete: True for @a &= ~@b, false for @a |= @b. | ||
607 | * | ||
608 | * Returns true if @a is empty, false otherwise. | ||
609 | */ | ||
824 | static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, | 610 | static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, |
825 | struct tomoyo_acl_info *b, | 611 | struct tomoyo_acl_info *b, |
826 | const bool is_delete) | 612 | const bool is_delete) |
@@ -841,33 +627,26 @@ static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, | |||
841 | /** | 627 | /** |
842 | * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. | 628 | * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. |
843 | * | 629 | * |
844 | * @type: Type of operation. | 630 | * @perm: Permission. |
845 | * @filename: Filename. | 631 | * @param: Pointer to "struct tomoyo_acl_param". |
846 | * @number: Number. | ||
847 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
848 | * @is_delete: True if it is a delete request. | ||
849 | * | 632 | * |
850 | * Returns 0 on success, negative value otherwise. | 633 | * Returns 0 on success, negative value otherwise. |
851 | */ | 634 | */ |
852 | static int tomoyo_update_path_number_acl(const u8 type, const char *filename, | 635 | static int tomoyo_update_path_number_acl(const u8 perm, |
853 | char *number, | 636 | struct tomoyo_acl_param *param) |
854 | struct tomoyo_domain_info * const | ||
855 | domain, | ||
856 | const bool is_delete) | ||
857 | { | 637 | { |
858 | struct tomoyo_path_number_acl e = { | 638 | struct tomoyo_path_number_acl e = { |
859 | .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, | 639 | .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, |
860 | .perm = 1 << type | 640 | .perm = perm |
861 | }; | 641 | }; |
862 | int error = is_delete ? -ENOENT : -ENOMEM; | 642 | int error; |
863 | if (!tomoyo_parse_name_union(filename, &e.name)) | 643 | if (!tomoyo_parse_name_union(param, &e.name) || |
864 | return -EINVAL; | 644 | !tomoyo_parse_number_union(param, &e.number)) |
865 | if (!tomoyo_parse_number_union(number, &e.number)) | 645 | error = -EINVAL; |
866 | goto out; | 646 | else |
867 | error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain, | 647 | error = tomoyo_update_domain(&e.head, sizeof(e), param, |
868 | tomoyo_same_path_number_acl, | 648 | tomoyo_same_path_number_acl, |
869 | tomoyo_merge_path_number_acl); | 649 | tomoyo_merge_path_number_acl); |
870 | out: | ||
871 | tomoyo_put_name_union(&e.name); | 650 | tomoyo_put_name_union(&e.name); |
872 | tomoyo_put_number_union(&e.number); | 651 | tomoyo_put_number_union(&e.number); |
873 | return error; | 652 | return error; |
@@ -886,16 +665,20 @@ int tomoyo_path_number_perm(const u8 type, struct path *path, | |||
886 | unsigned long number) | 665 | unsigned long number) |
887 | { | 666 | { |
888 | struct tomoyo_request_info r; | 667 | struct tomoyo_request_info r; |
668 | struct tomoyo_obj_info obj = { | ||
669 | .path1 = *path, | ||
670 | }; | ||
889 | int error = -ENOMEM; | 671 | int error = -ENOMEM; |
890 | struct tomoyo_path_info buf; | 672 | struct tomoyo_path_info buf; |
891 | int idx; | 673 | int idx; |
892 | 674 | ||
893 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) | 675 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) |
894 | == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry) | 676 | == TOMOYO_CONFIG_DISABLED || !path->dentry) |
895 | return 0; | 677 | return 0; |
896 | idx = tomoyo_read_lock(); | 678 | idx = tomoyo_read_lock(); |
897 | if (!tomoyo_get_realpath(&buf, path)) | 679 | if (!tomoyo_get_realpath(&buf, path)) |
898 | goto out; | 680 | goto out; |
681 | r.obj = &obj; | ||
899 | if (type == TOMOYO_TYPE_MKDIR) | 682 | if (type == TOMOYO_TYPE_MKDIR) |
900 | tomoyo_add_slash(&buf); | 683 | tomoyo_add_slash(&buf); |
901 | r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; | 684 | r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; |
@@ -930,45 +713,30 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
930 | int error = 0; | 713 | int error = 0; |
931 | struct tomoyo_path_info buf; | 714 | struct tomoyo_path_info buf; |
932 | struct tomoyo_request_info r; | 715 | struct tomoyo_request_info r; |
716 | struct tomoyo_obj_info obj = { | ||
717 | .path1 = *path, | ||
718 | }; | ||
933 | int idx; | 719 | int idx; |
934 | 720 | ||
935 | if (!path->mnt || | ||
936 | (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))) | ||
937 | return 0; | ||
938 | buf.name = NULL; | 721 | buf.name = NULL; |
939 | r.mode = TOMOYO_CONFIG_DISABLED; | 722 | r.mode = TOMOYO_CONFIG_DISABLED; |
940 | idx = tomoyo_read_lock(); | 723 | idx = tomoyo_read_lock(); |
941 | /* | 724 | if (acc_mode && |
942 | * If the filename is specified by "deny_rewrite" keyword, | 725 | tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) |
943 | * we need to check "allow_rewrite" permission when the filename is not | ||
944 | * opened for append mode or the filename is truncated at open time. | ||
945 | */ | ||
946 | if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND) | ||
947 | && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE) | ||
948 | != TOMOYO_CONFIG_DISABLED) { | 726 | != TOMOYO_CONFIG_DISABLED) { |
949 | if (!tomoyo_get_realpath(&buf, path)) { | 727 | if (!tomoyo_get_realpath(&buf, path)) { |
950 | error = -ENOMEM; | 728 | error = -ENOMEM; |
951 | goto out; | 729 | goto out; |
952 | } | 730 | } |
953 | if (tomoyo_no_rewrite_file(&buf)) | 731 | r.obj = &obj; |
954 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, | 732 | if (acc_mode & MAY_READ) |
733 | error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ, | ||
734 | &buf); | ||
735 | if (!error && (acc_mode & MAY_WRITE)) | ||
736 | error = tomoyo_path_permission(&r, (flag & O_APPEND) ? | ||
737 | TOMOYO_TYPE_APPEND : | ||
738 | TOMOYO_TYPE_WRITE, | ||
955 | &buf); | 739 | &buf); |
956 | } | ||
957 | if (!error && acc_mode && | ||
958 | tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) | ||
959 | != TOMOYO_CONFIG_DISABLED) { | ||
960 | u8 operation; | ||
961 | if (!buf.name && !tomoyo_get_realpath(&buf, path)) { | ||
962 | error = -ENOMEM; | ||
963 | goto out; | ||
964 | } | ||
965 | if (acc_mode == (MAY_READ | MAY_WRITE)) | ||
966 | operation = TOMOYO_TYPE_READ_WRITE; | ||
967 | else if (acc_mode == MAY_READ) | ||
968 | operation = TOMOYO_TYPE_READ; | ||
969 | else | ||
970 | operation = TOMOYO_TYPE_WRITE; | ||
971 | error = tomoyo_path_permission(&r, operation, &buf); | ||
972 | } | 740 | } |
973 | out: | 741 | out: |
974 | kfree(buf.name); | 742 | kfree(buf.name); |
@@ -979,46 +747,57 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
979 | } | 747 | } |
980 | 748 | ||
981 | /** | 749 | /** |
982 | * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". | 750 | * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount". |
983 | * | 751 | * |
984 | * @operation: Type of operation. | 752 | * @operation: Type of operation. |
985 | * @path: Pointer to "struct path". | 753 | * @path: Pointer to "struct path". |
754 | * @target: Symlink's target if @operation is TOMOYO_TYPE_SYMLINK, | ||
755 | * NULL otherwise. | ||
986 | * | 756 | * |
987 | * Returns 0 on success, negative value otherwise. | 757 | * Returns 0 on success, negative value otherwise. |
988 | */ | 758 | */ |
989 | int tomoyo_path_perm(const u8 operation, struct path *path) | 759 | int tomoyo_path_perm(const u8 operation, struct path *path, const char *target) |
990 | { | 760 | { |
991 | int error = -ENOMEM; | ||
992 | struct tomoyo_path_info buf; | ||
993 | struct tomoyo_request_info r; | 761 | struct tomoyo_request_info r; |
762 | struct tomoyo_obj_info obj = { | ||
763 | .path1 = *path, | ||
764 | }; | ||
765 | int error; | ||
766 | struct tomoyo_path_info buf; | ||
767 | bool is_enforce; | ||
768 | struct tomoyo_path_info symlink_target; | ||
994 | int idx; | 769 | int idx; |
995 | 770 | ||
996 | if (!path->mnt) | ||
997 | return 0; | ||
998 | if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) | 771 | if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) |
999 | == TOMOYO_CONFIG_DISABLED) | 772 | == TOMOYO_CONFIG_DISABLED) |
1000 | return 0; | 773 | return 0; |
774 | is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING); | ||
775 | error = -ENOMEM; | ||
1001 | buf.name = NULL; | 776 | buf.name = NULL; |
1002 | idx = tomoyo_read_lock(); | 777 | idx = tomoyo_read_lock(); |
1003 | if (!tomoyo_get_realpath(&buf, path)) | 778 | if (!tomoyo_get_realpath(&buf, path)) |
1004 | goto out; | 779 | goto out; |
780 | r.obj = &obj; | ||
1005 | switch (operation) { | 781 | switch (operation) { |
1006 | case TOMOYO_TYPE_REWRITE: | ||
1007 | if (!tomoyo_no_rewrite_file(&buf)) { | ||
1008 | error = 0; | ||
1009 | goto out; | ||
1010 | } | ||
1011 | break; | ||
1012 | case TOMOYO_TYPE_RMDIR: | 782 | case TOMOYO_TYPE_RMDIR: |
1013 | case TOMOYO_TYPE_CHROOT: | 783 | case TOMOYO_TYPE_CHROOT: |
1014 | tomoyo_add_slash(&buf); | 784 | tomoyo_add_slash(&buf); |
1015 | break; | 785 | break; |
786 | case TOMOYO_TYPE_SYMLINK: | ||
787 | symlink_target.name = tomoyo_encode(target); | ||
788 | if (!symlink_target.name) | ||
789 | goto out; | ||
790 | tomoyo_fill_path_info(&symlink_target); | ||
791 | obj.symlink_target = &symlink_target; | ||
792 | break; | ||
1016 | } | 793 | } |
1017 | error = tomoyo_path_permission(&r, operation, &buf); | 794 | error = tomoyo_path_permission(&r, operation, &buf); |
795 | if (operation == TOMOYO_TYPE_SYMLINK) | ||
796 | kfree(symlink_target.name); | ||
1018 | out: | 797 | out: |
1019 | kfree(buf.name); | 798 | kfree(buf.name); |
1020 | tomoyo_read_unlock(idx); | 799 | tomoyo_read_unlock(idx); |
1021 | if (r.mode != TOMOYO_CONFIG_ENFORCING) | 800 | if (!is_enforce) |
1022 | error = 0; | 801 | error = 0; |
1023 | return error; | 802 | return error; |
1024 | } | 803 | } |
@@ -1034,20 +813,23 @@ int tomoyo_path_perm(const u8 operation, struct path *path) | |||
1034 | * Returns 0 on success, negative value otherwise. | 813 | * Returns 0 on success, negative value otherwise. |
1035 | */ | 814 | */ |
1036 | int tomoyo_mkdev_perm(const u8 operation, struct path *path, | 815 | int tomoyo_mkdev_perm(const u8 operation, struct path *path, |
1037 | const unsigned int mode, unsigned int dev) | 816 | const unsigned int mode, unsigned int dev) |
1038 | { | 817 | { |
1039 | struct tomoyo_request_info r; | 818 | struct tomoyo_request_info r; |
819 | struct tomoyo_obj_info obj = { | ||
820 | .path1 = *path, | ||
821 | }; | ||
1040 | int error = -ENOMEM; | 822 | int error = -ENOMEM; |
1041 | struct tomoyo_path_info buf; | 823 | struct tomoyo_path_info buf; |
1042 | int idx; | 824 | int idx; |
1043 | 825 | ||
1044 | if (!path->mnt || | 826 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) |
1045 | tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) | ||
1046 | == TOMOYO_CONFIG_DISABLED) | 827 | == TOMOYO_CONFIG_DISABLED) |
1047 | return 0; | 828 | return 0; |
1048 | idx = tomoyo_read_lock(); | 829 | idx = tomoyo_read_lock(); |
1049 | error = -ENOMEM; | 830 | error = -ENOMEM; |
1050 | if (tomoyo_get_realpath(&buf, path)) { | 831 | if (tomoyo_get_realpath(&buf, path)) { |
832 | r.obj = &obj; | ||
1051 | dev = new_decode_dev(dev); | 833 | dev = new_decode_dev(dev); |
1052 | r.param_type = TOMOYO_TYPE_MKDEV_ACL; | 834 | r.param_type = TOMOYO_TYPE_MKDEV_ACL; |
1053 | r.param.mkdev.filename = &buf; | 835 | r.param.mkdev.filename = &buf; |
@@ -1081,10 +863,13 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1081 | struct tomoyo_path_info buf1; | 863 | struct tomoyo_path_info buf1; |
1082 | struct tomoyo_path_info buf2; | 864 | struct tomoyo_path_info buf2; |
1083 | struct tomoyo_request_info r; | 865 | struct tomoyo_request_info r; |
866 | struct tomoyo_obj_info obj = { | ||
867 | .path1 = *path1, | ||
868 | .path2 = *path2, | ||
869 | }; | ||
1084 | int idx; | 870 | int idx; |
1085 | 871 | ||
1086 | if (!path1->mnt || !path2->mnt || | 872 | if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) |
1087 | tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) | ||
1088 | == TOMOYO_CONFIG_DISABLED) | 873 | == TOMOYO_CONFIG_DISABLED) |
1089 | return 0; | 874 | return 0; |
1090 | buf1.name = NULL; | 875 | buf1.name = NULL; |
@@ -1096,16 +881,17 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1096 | switch (operation) { | 881 | switch (operation) { |
1097 | struct dentry *dentry; | 882 | struct dentry *dentry; |
1098 | case TOMOYO_TYPE_RENAME: | 883 | case TOMOYO_TYPE_RENAME: |
1099 | case TOMOYO_TYPE_LINK: | 884 | case TOMOYO_TYPE_LINK: |
1100 | dentry = path1->dentry; | 885 | dentry = path1->dentry; |
1101 | if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) | 886 | if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) |
1102 | break; | 887 | break; |
1103 | /* fall through */ | 888 | /* fall through */ |
1104 | case TOMOYO_TYPE_PIVOT_ROOT: | 889 | case TOMOYO_TYPE_PIVOT_ROOT: |
1105 | tomoyo_add_slash(&buf1); | 890 | tomoyo_add_slash(&buf1); |
1106 | tomoyo_add_slash(&buf2); | 891 | tomoyo_add_slash(&buf2); |
1107 | break; | 892 | break; |
1108 | } | 893 | } |
894 | r.obj = &obj; | ||
1109 | r.param_type = TOMOYO_TYPE_PATH2_ACL; | 895 | r.param_type = TOMOYO_TYPE_PATH2_ACL; |
1110 | r.param.path2.operation = operation; | 896 | r.param.path2.operation = operation; |
1111 | r.param.path2.filename1 = &buf1; | 897 | r.param.path2.filename1 = &buf1; |
@@ -1124,53 +910,91 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
1124 | } | 910 | } |
1125 | 911 | ||
1126 | /** | 912 | /** |
913 | * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry. | ||
914 | * | ||
915 | * @a: Pointer to "struct tomoyo_acl_info". | ||
916 | * @b: Pointer to "struct tomoyo_acl_info". | ||
917 | * | ||
918 | * Returns true if @a == @b, false otherwise. | ||
919 | */ | ||
920 | static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, | ||
921 | const struct tomoyo_acl_info *b) | ||
922 | { | ||
923 | const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); | ||
924 | const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); | ||
925 | return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && | ||
926 | tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && | ||
927 | tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && | ||
928 | tomoyo_same_number_union(&p1->flags, &p2->flags); | ||
929 | } | ||
930 | |||
931 | /** | ||
932 | * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list. | ||
933 | * | ||
934 | * @param: Pointer to "struct tomoyo_acl_param". | ||
935 | * | ||
936 | * Returns 0 on success, negative value otherwise. | ||
937 | * | ||
938 | * Caller holds tomoyo_read_lock(). | ||
939 | */ | ||
940 | static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param) | ||
941 | { | ||
942 | struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; | ||
943 | int error; | ||
944 | if (!tomoyo_parse_name_union(param, &e.dev_name) || | ||
945 | !tomoyo_parse_name_union(param, &e.dir_name) || | ||
946 | !tomoyo_parse_name_union(param, &e.fs_type) || | ||
947 | !tomoyo_parse_number_union(param, &e.flags)) | ||
948 | error = -EINVAL; | ||
949 | else | ||
950 | error = tomoyo_update_domain(&e.head, sizeof(e), param, | ||
951 | tomoyo_same_mount_acl, NULL); | ||
952 | tomoyo_put_name_union(&e.dev_name); | ||
953 | tomoyo_put_name_union(&e.dir_name); | ||
954 | tomoyo_put_name_union(&e.fs_type); | ||
955 | tomoyo_put_number_union(&e.flags); | ||
956 | return error; | ||
957 | } | ||
958 | |||
959 | /** | ||
1127 | * tomoyo_write_file - Update file related list. | 960 | * tomoyo_write_file - Update file related list. |
1128 | * | 961 | * |
1129 | * @data: String to parse. | 962 | * @param: Pointer to "struct tomoyo_acl_param". |
1130 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
1131 | * @is_delete: True if it is a delete request. | ||
1132 | * | 963 | * |
1133 | * Returns 0 on success, negative value otherwise. | 964 | * Returns 0 on success, negative value otherwise. |
1134 | * | 965 | * |
1135 | * Caller holds tomoyo_read_lock(). | 966 | * Caller holds tomoyo_read_lock(). |
1136 | */ | 967 | */ |
1137 | int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain, | 968 | int tomoyo_write_file(struct tomoyo_acl_param *param) |
1138 | const bool is_delete) | ||
1139 | { | 969 | { |
1140 | char *w[5]; | 970 | u16 perm = 0; |
1141 | u8 type; | 971 | u8 type; |
1142 | if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) | 972 | const char *operation = tomoyo_read_token(param); |
1143 | return -EINVAL; | 973 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) |
1144 | if (strncmp(w[0], "allow_", 6)) | 974 | if (tomoyo_permstr(operation, tomoyo_path_keyword[type])) |
1145 | goto out; | 975 | perm |= 1 << type; |
1146 | w[0] += 6; | 976 | if (perm) |
1147 | for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { | 977 | return tomoyo_update_path_acl(perm, param); |
1148 | if (strcmp(w[0], tomoyo_path_keyword[type])) | 978 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) |
1149 | continue; | 979 | if (tomoyo_permstr(operation, |
1150 | return tomoyo_update_path_acl(type, w[1], domain, is_delete); | 980 | tomoyo_mac_keywords[tomoyo_pp2mac[type]])) |
1151 | } | 981 | perm |= 1 << type; |
1152 | if (!w[2][0]) | 982 | if (perm) |
1153 | goto out; | 983 | return tomoyo_update_path2_acl(perm, param); |
1154 | for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { | 984 | for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) |
1155 | if (strcmp(w[0], tomoyo_path2_keyword[type])) | 985 | if (tomoyo_permstr(operation, |
1156 | continue; | 986 | tomoyo_mac_keywords[tomoyo_pn2mac[type]])) |
1157 | return tomoyo_update_path2_acl(type, w[1], w[2], domain, | 987 | perm |= 1 << type; |
1158 | is_delete); | 988 | if (perm) |
1159 | } | 989 | return tomoyo_update_path_number_acl(perm, param); |
1160 | for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { | 990 | for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) |
1161 | if (strcmp(w[0], tomoyo_path_number_keyword[type])) | 991 | if (tomoyo_permstr(operation, |
1162 | continue; | 992 | tomoyo_mac_keywords[tomoyo_pnnn2mac[type]])) |
1163 | return tomoyo_update_path_number_acl(type, w[1], w[2], domain, | 993 | perm |= 1 << type; |
1164 | is_delete); | 994 | if (perm) |
1165 | } | 995 | return tomoyo_update_mkdev_acl(perm, param); |
1166 | if (!w[3][0] || !w[4][0]) | 996 | if (tomoyo_permstr(operation, |
1167 | goto out; | 997 | tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT])) |
1168 | for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) { | 998 | return tomoyo_update_mount_acl(param); |
1169 | if (strcmp(w[0], tomoyo_mkdev_keyword[type])) | ||
1170 | continue; | ||
1171 | return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3], | ||
1172 | w[4], domain, is_delete); | ||
1173 | } | ||
1174 | out: | ||
1175 | return -EINVAL; | 999 | return -EINVAL; |
1176 | } | 1000 | } |