diff options
Diffstat (limited to 'security/tomoyo/domain.c')
-rw-r--r-- | security/tomoyo/domain.c | 146 |
1 files changed, 61 insertions, 85 deletions
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 43977083254b..d818717954f8 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -20,8 +20,7 @@ struct tomoyo_domain_info tomoyo_kernel_domain; | |||
20 | * | 20 | * |
21 | * @new_entry: Pointer to "struct tomoyo_acl_info". | 21 | * @new_entry: Pointer to "struct tomoyo_acl_info". |
22 | * @size: Size of @new_entry in bytes. | 22 | * @size: Size of @new_entry in bytes. |
23 | * @is_delete: True if it is a delete request. | 23 | * @param: Pointer to "struct tomoyo_acl_param". |
24 | * @list: Pointer to "struct list_head". | ||
25 | * @check_duplicate: Callback function to find duplicated entry. | 24 | * @check_duplicate: Callback function to find duplicated entry. |
26 | * | 25 | * |
27 | * Returns 0 on success, negative value otherwise. | 26 | * Returns 0 on success, negative value otherwise. |
@@ -29,25 +28,26 @@ struct tomoyo_domain_info tomoyo_kernel_domain; | |||
29 | * Caller holds tomoyo_read_lock(). | 28 | * Caller holds tomoyo_read_lock(). |
30 | */ | 29 | */ |
31 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | 30 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, |
32 | bool is_delete, struct list_head *list, | 31 | struct tomoyo_acl_param *param, |
33 | bool (*check_duplicate) (const struct tomoyo_acl_head | 32 | bool (*check_duplicate) (const struct tomoyo_acl_head |
34 | *, | 33 | *, |
35 | const struct tomoyo_acl_head | 34 | const struct tomoyo_acl_head |
36 | *)) | 35 | *)) |
37 | { | 36 | { |
38 | int error = is_delete ? -ENOENT : -ENOMEM; | 37 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
39 | struct tomoyo_acl_head *entry; | 38 | struct tomoyo_acl_head *entry; |
39 | struct list_head *list = param->list; | ||
40 | 40 | ||
41 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 41 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
42 | return -ENOMEM; | 42 | return -ENOMEM; |
43 | list_for_each_entry_rcu(entry, list, list) { | 43 | list_for_each_entry_rcu(entry, list, list) { |
44 | if (!check_duplicate(entry, new_entry)) | 44 | if (!check_duplicate(entry, new_entry)) |
45 | continue; | 45 | continue; |
46 | entry->is_deleted = is_delete; | 46 | entry->is_deleted = param->is_delete; |
47 | error = 0; | 47 | error = 0; |
48 | break; | 48 | break; |
49 | } | 49 | } |
50 | if (error && !is_delete) { | 50 | if (error && !param->is_delete) { |
51 | entry = tomoyo_commit_ok(new_entry, size); | 51 | entry = tomoyo_commit_ok(new_entry, size); |
52 | if (entry) { | 52 | if (entry) { |
53 | list_add_tail_rcu(&entry->list, list); | 53 | list_add_tail_rcu(&entry->list, list); |
@@ -77,8 +77,7 @@ static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, | |||
77 | * | 77 | * |
78 | * @new_entry: Pointer to "struct tomoyo_acl_info". | 78 | * @new_entry: Pointer to "struct tomoyo_acl_info". |
79 | * @size: Size of @new_entry in bytes. | 79 | * @size: Size of @new_entry in bytes. |
80 | * @is_delete: True if it is a delete request. | 80 | * @param: Pointer to "struct tomoyo_acl_param". |
81 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
82 | * @check_duplicate: Callback function to find duplicated entry. | 81 | * @check_duplicate: Callback function to find duplicated entry. |
83 | * @merge_duplicate: Callback function to merge duplicated entry. | 82 | * @merge_duplicate: Callback function to merge duplicated entry. |
84 | * | 83 | * |
@@ -87,7 +86,7 @@ static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, | |||
87 | * Caller holds tomoyo_read_lock(). | 86 | * Caller holds tomoyo_read_lock(). |
88 | */ | 87 | */ |
89 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | 88 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, |
90 | bool is_delete, struct tomoyo_domain_info *domain, | 89 | struct tomoyo_acl_param *param, |
91 | bool (*check_duplicate) (const struct tomoyo_acl_info | 90 | bool (*check_duplicate) (const struct tomoyo_acl_info |
92 | *, | 91 | *, |
93 | const struct tomoyo_acl_info | 92 | const struct tomoyo_acl_info |
@@ -96,12 +95,14 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | |||
96 | struct tomoyo_acl_info *, | 95 | struct tomoyo_acl_info *, |
97 | const bool)) | 96 | const bool)) |
98 | { | 97 | { |
98 | const bool is_delete = param->is_delete; | ||
99 | int error = is_delete ? -ENOENT : -ENOMEM; | 99 | int error = is_delete ? -ENOENT : -ENOMEM; |
100 | struct tomoyo_acl_info *entry; | 100 | struct tomoyo_acl_info *entry; |
101 | struct list_head * const list = param->list; | ||
101 | 102 | ||
102 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | 103 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
103 | return error; | 104 | return error; |
104 | list_for_each_entry_rcu(entry, &domain->acl_info_list, list) { | 105 | list_for_each_entry_rcu(entry, list, list) { |
105 | if (!tomoyo_same_acl_head(entry, new_entry) || | 106 | if (!tomoyo_same_acl_head(entry, new_entry) || |
106 | !check_duplicate(entry, new_entry)) | 107 | !check_duplicate(entry, new_entry)) |
107 | continue; | 108 | continue; |
@@ -116,7 +117,7 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | |||
116 | if (error && !is_delete) { | 117 | if (error && !is_delete) { |
117 | entry = tomoyo_commit_ok(new_entry, size); | 118 | entry = tomoyo_commit_ok(new_entry, size); |
118 | if (entry) { | 119 | if (entry) { |
119 | list_add_tail_rcu(&entry->list, &domain->acl_info_list); | 120 | list_add_tail_rcu(&entry->list, list); |
120 | error = 0; | 121 | error = 0; |
121 | } | 122 | } |
122 | } | 123 | } |
@@ -163,6 +164,14 @@ static const char *tomoyo_last_word(const char *name) | |||
163 | return name; | 164 | return name; |
164 | } | 165 | } |
165 | 166 | ||
167 | /** | ||
168 | * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry. | ||
169 | * | ||
170 | * @a: Pointer to "struct tomoyo_acl_head". | ||
171 | * @b: Pointer to "struct tomoyo_acl_head". | ||
172 | * | ||
173 | * Returns true if @a == @b, false otherwise. | ||
174 | */ | ||
166 | static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, | 175 | static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, |
167 | const struct tomoyo_acl_head *b) | 176 | const struct tomoyo_acl_head *b) |
168 | { | 177 | { |
@@ -178,22 +187,28 @@ static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, | |||
178 | } | 187 | } |
179 | 188 | ||
180 | /** | 189 | /** |
181 | * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list. | 190 | * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. |
182 | * | 191 | * |
183 | * @domainname: The name of domain. Maybe NULL. | 192 | * @param: Pointer to "struct tomoyo_acl_param". |
184 | * @program: The name of program. Maybe NULL. | 193 | * @type: Type of this entry. |
185 | * @type: Type of transition. | ||
186 | * @is_delete: True if it is a delete request. | ||
187 | * | 194 | * |
188 | * Returns 0 on success, negative value otherwise. | 195 | * Returns 0 on success, negative value otherwise. |
189 | */ | 196 | */ |
190 | static int tomoyo_update_transition_control_entry(const char *domainname, | 197 | int tomoyo_write_transition_control(struct tomoyo_acl_param *param, |
191 | const char *program, | 198 | const u8 type) |
192 | const u8 type, | ||
193 | const bool is_delete) | ||
194 | { | 199 | { |
195 | struct tomoyo_transition_control e = { .type = type }; | 200 | struct tomoyo_transition_control e = { .type = type }; |
196 | int error = is_delete ? -ENOENT : -ENOMEM; | 201 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
202 | char *program = param->data; | ||
203 | char *domainname = strstr(program, " from "); | ||
204 | if (domainname) { | ||
205 | *domainname = '\0'; | ||
206 | domainname += 6; | ||
207 | } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || | ||
208 | type == TOMOYO_TRANSITION_CONTROL_KEEP) { | ||
209 | domainname = program; | ||
210 | program = NULL; | ||
211 | } | ||
197 | if (program) { | 212 | if (program) { |
198 | if (!tomoyo_correct_path(program)) | 213 | if (!tomoyo_correct_path(program)) |
199 | return -EINVAL; | 214 | return -EINVAL; |
@@ -211,42 +226,16 @@ static int tomoyo_update_transition_control_entry(const char *domainname, | |||
211 | if (!e.domainname) | 226 | if (!e.domainname) |
212 | goto out; | 227 | goto out; |
213 | } | 228 | } |
214 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 229 | param->list = &tomoyo_policy_list[TOMOYO_ID_TRANSITION_CONTROL]; |
215 | &tomoyo_policy_list | 230 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
216 | [TOMOYO_ID_TRANSITION_CONTROL], | ||
217 | tomoyo_same_transition_control); | 231 | tomoyo_same_transition_control); |
218 | out: | 232 | out: |
219 | tomoyo_put_name(e.domainname); | 233 | tomoyo_put_name(e.domainname); |
220 | tomoyo_put_name(e.program); | 234 | tomoyo_put_name(e.program); |
221 | return error; | 235 | return error; |
222 | } | 236 | } |
223 | 237 | ||
224 | /** | 238 | /** |
225 | * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. | ||
226 | * | ||
227 | * @data: String to parse. | ||
228 | * @is_delete: True if it is a delete request. | ||
229 | * @type: Type of this entry. | ||
230 | * | ||
231 | * Returns 0 on success, negative value otherwise. | ||
232 | */ | ||
233 | int tomoyo_write_transition_control(char *data, const bool is_delete, | ||
234 | const u8 type) | ||
235 | { | ||
236 | char *domainname = strstr(data, " from "); | ||
237 | if (domainname) { | ||
238 | *domainname = '\0'; | ||
239 | domainname += 6; | ||
240 | } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || | ||
241 | type == TOMOYO_TRANSITION_CONTROL_KEEP) { | ||
242 | domainname = data; | ||
243 | data = NULL; | ||
244 | } | ||
245 | return tomoyo_update_transition_control_entry(domainname, data, type, | ||
246 | is_delete); | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * tomoyo_transition_type - Get domain transition type. | 239 | * tomoyo_transition_type - Get domain transition type. |
251 | * | 240 | * |
252 | * @domainname: The name of domain. | 241 | * @domainname: The name of domain. |
@@ -303,34 +292,41 @@ static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, | |||
303 | return type; | 292 | return type; |
304 | } | 293 | } |
305 | 294 | ||
295 | /** | ||
296 | * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry. | ||
297 | * | ||
298 | * @a: Pointer to "struct tomoyo_acl_head". | ||
299 | * @b: Pointer to "struct tomoyo_acl_head". | ||
300 | * | ||
301 | * Returns true if @a == @b, false otherwise. | ||
302 | */ | ||
306 | static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, | 303 | static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, |
307 | const struct tomoyo_acl_head *b) | 304 | const struct tomoyo_acl_head *b) |
308 | { | 305 | { |
309 | const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head); | 306 | const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), |
310 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head); | 307 | head); |
308 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), | ||
309 | head); | ||
311 | return p1->original_name == p2->original_name && | 310 | return p1->original_name == p2->original_name && |
312 | p1->aggregated_name == p2->aggregated_name; | 311 | p1->aggregated_name == p2->aggregated_name; |
313 | } | 312 | } |
314 | 313 | ||
315 | /** | 314 | /** |
316 | * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator" list. | 315 | * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. |
317 | * | 316 | * |
318 | * @original_name: The original program's name. | 317 | * @param: Pointer to "struct tomoyo_acl_param". |
319 | * @aggregated_name: The program name to use. | ||
320 | * @is_delete: True if it is a delete request. | ||
321 | * | 318 | * |
322 | * Returns 0 on success, negative value otherwise. | 319 | * Returns 0 on success, negative value otherwise. |
323 | * | 320 | * |
324 | * Caller holds tomoyo_read_lock(). | 321 | * Caller holds tomoyo_read_lock(). |
325 | */ | 322 | */ |
326 | static int tomoyo_update_aggregator_entry(const char *original_name, | 323 | int tomoyo_write_aggregator(struct tomoyo_acl_param *param) |
327 | const char *aggregated_name, | ||
328 | const bool is_delete) | ||
329 | { | 324 | { |
330 | struct tomoyo_aggregator e = { }; | 325 | struct tomoyo_aggregator e = { }; |
331 | int error = is_delete ? -ENOENT : -ENOMEM; | 326 | int error = param->is_delete ? -ENOENT : -ENOMEM; |
332 | 327 | const char *original_name = tomoyo_read_token(param); | |
333 | if (!tomoyo_correct_path(original_name) || | 328 | const char *aggregated_name = tomoyo_read_token(param); |
329 | if (!tomoyo_correct_word(original_name) || | ||
334 | !tomoyo_correct_path(aggregated_name)) | 330 | !tomoyo_correct_path(aggregated_name)) |
335 | return -EINVAL; | 331 | return -EINVAL; |
336 | e.original_name = tomoyo_get_name(original_name); | 332 | e.original_name = tomoyo_get_name(original_name); |
@@ -338,36 +334,16 @@ static int tomoyo_update_aggregator_entry(const char *original_name, | |||
338 | if (!e.original_name || !e.aggregated_name || | 334 | if (!e.original_name || !e.aggregated_name || |
339 | e.aggregated_name->is_patterned) /* No patterns allowed. */ | 335 | e.aggregated_name->is_patterned) /* No patterns allowed. */ |
340 | goto out; | 336 | goto out; |
341 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 337 | param->list = &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR]; |
342 | &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR], | 338 | error = tomoyo_update_policy(&e.head, sizeof(e), param, |
343 | tomoyo_same_aggregator); | 339 | tomoyo_same_aggregator); |
344 | out: | 340 | out: |
345 | tomoyo_put_name(e.original_name); | 341 | tomoyo_put_name(e.original_name); |
346 | tomoyo_put_name(e.aggregated_name); | 342 | tomoyo_put_name(e.aggregated_name); |
347 | return error; | 343 | return error; |
348 | } | 344 | } |
349 | 345 | ||
350 | /** | 346 | /** |
351 | * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. | ||
352 | * | ||
353 | * @data: String to parse. | ||
354 | * @is_delete: True if it is a delete request. | ||
355 | * | ||
356 | * Returns 0 on success, negative value otherwise. | ||
357 | * | ||
358 | * Caller holds tomoyo_read_lock(). | ||
359 | */ | ||
360 | int tomoyo_write_aggregator(char *data, const bool is_delete) | ||
361 | { | ||
362 | char *cp = strchr(data, ' '); | ||
363 | |||
364 | if (!cp) | ||
365 | return -EINVAL; | ||
366 | *cp++ = '\0'; | ||
367 | return tomoyo_update_aggregator_entry(data, cp, is_delete); | ||
368 | } | ||
369 | |||
370 | /** | ||
371 | * tomoyo_assign_domain - Create a domain. | 347 | * tomoyo_assign_domain - Create a domain. |
372 | * | 348 | * |
373 | * @domainname: The name of domain. | 349 | * @domainname: The name of domain. |