diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-06-20 22:14:39 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-08-02 01:34:43 -0400 |
commit | 5448ec4f5062ef75ce74f8d7784d4cea9c46ad00 (patch) | |
tree | c4c742b928c799e03328e345e1d4af738f315afb /security/tomoyo/domain.c | |
parent | 0617c7ff34dc9b1d641640c3953274bb2dbe21a6 (diff) |
TOMOYO: Use common code for domain transition control.
Use common code for "initialize_domain"/"no_initialize_domain"/"keep_domain"/
"no_keep_domain" keywords.
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/domain.c')
-rw-r--r-- | security/tomoyo/domain.c | 316 |
1 files changed, 107 insertions, 209 deletions
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 273e670acf0c..05450b17c57f 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -150,59 +150,60 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
150 | return cp0; | 150 | return cp0; |
151 | } | 151 | } |
152 | 152 | ||
153 | static bool tomoyo_same_domain_initializer_entry(const struct tomoyo_acl_head * | 153 | static bool tomoyo_same_transition_control_entry(const struct tomoyo_acl_head * |
154 | a, | 154 | a, |
155 | const struct tomoyo_acl_head * | 155 | const struct tomoyo_acl_head * |
156 | b) | 156 | b) |
157 | { | 157 | { |
158 | const struct tomoyo_domain_initializer_entry *p1 = | 158 | const struct tomoyo_transition_control *p1 = container_of(a, |
159 | container_of(a, typeof(*p1), head); | 159 | typeof(*p1), |
160 | const struct tomoyo_domain_initializer_entry *p2 = | 160 | head); |
161 | container_of(b, typeof(*p2), head); | 161 | const struct tomoyo_transition_control *p2 = container_of(b, |
162 | return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name | 162 | typeof(*p2), |
163 | head); | ||
164 | return p1->type == p2->type && p1->is_last_name == p2->is_last_name | ||
163 | && p1->domainname == p2->domainname | 165 | && p1->domainname == p2->domainname |
164 | && p1->program == p2->program; | 166 | && p1->program == p2->program; |
165 | } | 167 | } |
166 | 168 | ||
167 | /** | 169 | /** |
168 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. | 170 | * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list. |
169 | * | 171 | * |
170 | * @domainname: The name of domain. May be NULL. | 172 | * @domainname: The name of domain. Maybe NULL. |
171 | * @program: The name of program. | 173 | * @program: The name of program. Maybe NULL. |
172 | * @is_not: True if it is "no_initialize_domain" entry. | 174 | * @type: Type of transition. |
173 | * @is_delete: True if it is a delete request. | 175 | * @is_delete: True if it is a delete request. |
174 | * | 176 | * |
175 | * Returns 0 on success, negative value otherwise. | 177 | * Returns 0 on success, negative value otherwise. |
176 | * | ||
177 | * Caller holds tomoyo_read_lock(). | ||
178 | */ | 178 | */ |
179 | static int tomoyo_update_domain_initializer_entry(const char *domainname, | 179 | static int tomoyo_update_transition_control_entry(const char *domainname, |
180 | const char *program, | 180 | const char *program, |
181 | const bool is_not, | 181 | const u8 type, |
182 | const bool is_delete) | 182 | const bool is_delete) |
183 | { | 183 | { |
184 | struct tomoyo_domain_initializer_entry e = { .is_not = is_not }; | 184 | struct tomoyo_transition_control e = { .type = type }; |
185 | int error = is_delete ? -ENOENT : -ENOMEM; | 185 | int error = is_delete ? -ENOENT : -ENOMEM; |
186 | 186 | if (program) { | |
187 | if (!tomoyo_correct_path(program)) | 187 | if (!tomoyo_correct_path(program)) |
188 | return -EINVAL; | 188 | return -EINVAL; |
189 | e.program = tomoyo_get_name(program); | ||
190 | if (!e.program) | ||
191 | goto out; | ||
192 | } | ||
189 | if (domainname) { | 193 | if (domainname) { |
190 | if (!tomoyo_domain_def(domainname) && | 194 | if (!tomoyo_correct_domain(domainname)) { |
191 | tomoyo_correct_path(domainname)) | 195 | if (!tomoyo_correct_path(domainname)) |
196 | goto out; | ||
192 | e.is_last_name = true; | 197 | e.is_last_name = true; |
193 | else if (!tomoyo_correct_domain(domainname)) | 198 | } |
194 | return -EINVAL; | ||
195 | e.domainname = tomoyo_get_name(domainname); | 199 | e.domainname = tomoyo_get_name(domainname); |
196 | if (!e.domainname) | 200 | if (!e.domainname) |
197 | goto out; | 201 | goto out; |
198 | } | 202 | } |
199 | e.program = tomoyo_get_name(program); | ||
200 | if (!e.program) | ||
201 | goto out; | ||
202 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 203 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, |
203 | &tomoyo_policy_list | 204 | &tomoyo_policy_list |
204 | [TOMOYO_ID_DOMAIN_INITIALIZER], | 205 | [TOMOYO_ID_TRANSITION_CONTROL], |
205 | tomoyo_same_domain_initializer_entry); | 206 | tomoyo_same_transition_control_entry); |
206 | out: | 207 | out: |
207 | tomoyo_put_name(e.domainname); | 208 | tomoyo_put_name(e.domainname); |
208 | tomoyo_put_name(e.program); | 209 | tomoyo_put_name(e.program); |
@@ -210,195 +211,85 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
210 | } | 211 | } |
211 | 212 | ||
212 | /** | 213 | /** |
213 | * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list. | 214 | * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. |
214 | * | 215 | * |
215 | * @data: String to parse. | 216 | * @data: String to parse. |
216 | * @is_not: True if it is "no_initialize_domain" entry. | ||
217 | * @is_delete: True if it is a delete request. | 217 | * @is_delete: True if it is a delete request. |
218 | * @type: Type of this entry. | ||
218 | * | 219 | * |
219 | * Returns 0 on success, negative value otherwise. | 220 | * Returns 0 on success, negative value otherwise. |
220 | * | ||
221 | * Caller holds tomoyo_read_lock(). | ||
222 | */ | 221 | */ |
223 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | 222 | int tomoyo_write_transition_control(char *data, const bool is_delete, |
224 | const bool is_delete) | 223 | const u8 type) |
225 | { | 224 | { |
226 | char *cp = strstr(data, " from "); | 225 | char *domainname = strstr(data, " from "); |
227 | 226 | if (domainname) { | |
228 | if (cp) { | 227 | *domainname = '\0'; |
229 | *cp = '\0'; | 228 | domainname += 6; |
230 | return tomoyo_update_domain_initializer_entry(cp + 6, data, | 229 | } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || |
231 | is_not, | 230 | type == TOMOYO_TRANSITION_CONTROL_KEEP) { |
232 | is_delete); | 231 | domainname = data; |
232 | data = NULL; | ||
233 | } | 233 | } |
234 | return tomoyo_update_domain_initializer_entry(NULL, data, is_not, | 234 | return tomoyo_update_transition_control_entry(domainname, data, type, |
235 | is_delete); | 235 | is_delete); |
236 | } | 236 | } |
237 | 237 | ||
238 | /** | 238 | /** |
239 | * tomoyo_domain_initializer - Check whether the given program causes domainname reinitialization. | 239 | * tomoyo_transition_type - Get domain transition type. |
240 | * | 240 | * |
241 | * @domainname: The name of domain. | 241 | * @domainname: The name of domain. |
242 | * @program: The name of program. | 242 | * @program: The name of program. |
243 | * @last_name: The last component of @domainname. | ||
244 | * | 243 | * |
245 | * Returns true if executing @program reinitializes domain transition, | 244 | * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program |
246 | * false otherwise. | 245 | * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing |
246 | * @program suppresses domain transition, others otherwise. | ||
247 | * | 247 | * |
248 | * Caller holds tomoyo_read_lock(). | 248 | * Caller holds tomoyo_read_lock(). |
249 | */ | 249 | */ |
250 | static bool tomoyo_domain_initializer(const struct tomoyo_path_info * | 250 | static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, |
251 | domainname, | 251 | const struct tomoyo_path_info *program) |
252 | const struct tomoyo_path_info *program, | ||
253 | const struct tomoyo_path_info * | ||
254 | last_name) | ||
255 | { | 252 | { |
256 | struct tomoyo_domain_initializer_entry *ptr; | 253 | const struct tomoyo_transition_control *ptr; |
257 | bool flag = false; | 254 | const char *last_name = tomoyo_last_word(domainname->name); |
258 | 255 | u8 type; | |
259 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list | 256 | for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) { |
260 | [TOMOYO_ID_DOMAIN_INITIALIZER], head.list) { | 257 | next: |
261 | if (ptr->head.is_deleted) | 258 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list |
262 | continue; | 259 | [TOMOYO_ID_TRANSITION_CONTROL], |
263 | if (ptr->domainname) { | 260 | head.list) { |
264 | if (!ptr->is_last_name) { | 261 | if (ptr->head.is_deleted || ptr->type != type) |
265 | if (ptr->domainname != domainname) | ||
266 | continue; | ||
267 | } else { | ||
268 | if (tomoyo_pathcmp(ptr->domainname, last_name)) | ||
269 | continue; | ||
270 | } | ||
271 | } | ||
272 | if (tomoyo_pathcmp(ptr->program, program)) | ||
273 | continue; | ||
274 | if (ptr->is_not) { | ||
275 | flag = false; | ||
276 | break; | ||
277 | } | ||
278 | flag = true; | ||
279 | } | ||
280 | return flag; | ||
281 | } | ||
282 | |||
283 | static bool tomoyo_same_domain_keeper_entry(const struct tomoyo_acl_head *a, | ||
284 | const struct tomoyo_acl_head *b) | ||
285 | { | ||
286 | const struct tomoyo_domain_keeper_entry *p1 = | ||
287 | container_of(a, typeof(*p1), head); | ||
288 | const struct tomoyo_domain_keeper_entry *p2 = | ||
289 | container_of(b, typeof(*p2), head); | ||
290 | return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name | ||
291 | && p1->domainname == p2->domainname | ||
292 | && p1->program == p2->program; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. | ||
297 | * | ||
298 | * @domainname: The name of domain. | ||
299 | * @program: The name of program. May be NULL. | ||
300 | * @is_not: True if it is "no_keep_domain" entry. | ||
301 | * @is_delete: True if it is a delete request. | ||
302 | * | ||
303 | * Returns 0 on success, negative value otherwise. | ||
304 | * | ||
305 | * Caller holds tomoyo_read_lock(). | ||
306 | */ | ||
307 | static int tomoyo_update_domain_keeper_entry(const char *domainname, | ||
308 | const char *program, | ||
309 | const bool is_not, | ||
310 | const bool is_delete) | ||
311 | { | ||
312 | struct tomoyo_domain_keeper_entry e = { .is_not = is_not }; | ||
313 | int error = is_delete ? -ENOENT : -ENOMEM; | ||
314 | |||
315 | if (!tomoyo_domain_def(domainname) && | ||
316 | tomoyo_correct_path(domainname)) | ||
317 | e.is_last_name = true; | ||
318 | else if (!tomoyo_correct_domain(domainname)) | ||
319 | return -EINVAL; | ||
320 | if (program) { | ||
321 | if (!tomoyo_correct_path(program)) | ||
322 | return -EINVAL; | ||
323 | e.program = tomoyo_get_name(program); | ||
324 | if (!e.program) | ||
325 | goto out; | ||
326 | } | ||
327 | e.domainname = tomoyo_get_name(domainname); | ||
328 | if (!e.domainname) | ||
329 | goto out; | ||
330 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | ||
331 | &tomoyo_policy_list | ||
332 | [TOMOYO_ID_DOMAIN_KEEPER], | ||
333 | tomoyo_same_domain_keeper_entry); | ||
334 | out: | ||
335 | tomoyo_put_name(e.domainname); | ||
336 | tomoyo_put_name(e.program); | ||
337 | return error; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list. | ||
342 | * | ||
343 | * @data: String to parse. | ||
344 | * @is_not: True if it is "no_keep_domain" entry. | ||
345 | * @is_delete: True if it is a delete request. | ||
346 | * | ||
347 | * Caller holds tomoyo_read_lock(). | ||
348 | */ | ||
349 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | ||
350 | const bool is_delete) | ||
351 | { | ||
352 | char *cp = strstr(data, " from "); | ||
353 | |||
354 | if (cp) { | ||
355 | *cp = '\0'; | ||
356 | return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not, | ||
357 | is_delete); | ||
358 | } | ||
359 | return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete); | ||
360 | } | ||
361 | |||
362 | /** | ||
363 | * tomoyo_domain_keeper - Check whether the given program causes domain transition suppression. | ||
364 | * | ||
365 | * @domainname: The name of domain. | ||
366 | * @program: The name of program. | ||
367 | * @last_name: The last component of @domainname. | ||
368 | * | ||
369 | * Returns true if executing @program supresses domain transition, | ||
370 | * false otherwise. | ||
371 | * | ||
372 | * Caller holds tomoyo_read_lock(). | ||
373 | */ | ||
374 | static bool tomoyo_domain_keeper(const struct tomoyo_path_info *domainname, | ||
375 | const struct tomoyo_path_info *program, | ||
376 | const struct tomoyo_path_info *last_name) | ||
377 | { | ||
378 | struct tomoyo_domain_keeper_entry *ptr; | ||
379 | bool flag = false; | ||
380 | |||
381 | list_for_each_entry_rcu(ptr, | ||
382 | &tomoyo_policy_list[TOMOYO_ID_DOMAIN_KEEPER], | ||
383 | head.list) { | ||
384 | if (ptr->head.is_deleted) | ||
385 | continue; | ||
386 | if (!ptr->is_last_name) { | ||
387 | if (ptr->domainname != domainname) | ||
388 | continue; | 262 | continue; |
389 | } else { | 263 | if (ptr->domainname) { |
390 | if (tomoyo_pathcmp(ptr->domainname, last_name)) | 264 | if (!ptr->is_last_name) { |
265 | if (ptr->domainname != domainname) | ||
266 | continue; | ||
267 | } else { | ||
268 | /* | ||
269 | * Use direct strcmp() since this is | ||
270 | * unlikely used. | ||
271 | */ | ||
272 | if (strcmp(ptr->domainname->name, | ||
273 | last_name)) | ||
274 | continue; | ||
275 | } | ||
276 | } | ||
277 | if (ptr->program && | ||
278 | tomoyo_pathcmp(ptr->program, program)) | ||
391 | continue; | 279 | continue; |
280 | if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) { | ||
281 | /* | ||
282 | * Do not check for initialize_domain if | ||
283 | * no_initialize_domain matched. | ||
284 | */ | ||
285 | type = TOMOYO_TRANSITION_CONTROL_NO_KEEP; | ||
286 | goto next; | ||
287 | } | ||
288 | goto done; | ||
392 | } | 289 | } |
393 | if (ptr->program && tomoyo_pathcmp(ptr->program, program)) | ||
394 | continue; | ||
395 | if (ptr->is_not) { | ||
396 | flag = false; | ||
397 | break; | ||
398 | } | ||
399 | flag = true; | ||
400 | } | 290 | } |
401 | return flag; | 291 | done: |
292 | return type; | ||
402 | } | 293 | } |
403 | 294 | ||
404 | static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a, | 295 | static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a, |
@@ -533,7 +424,6 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
533 | char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); | 424 | char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); |
534 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 425 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
535 | struct tomoyo_domain_info *domain = NULL; | 426 | struct tomoyo_domain_info *domain = NULL; |
536 | const char *old_domain_name = old_domain->domainname->name; | ||
537 | const char *original_name = bprm->filename; | 427 | const char *original_name = bprm->filename; |
538 | u8 mode; | 428 | u8 mode; |
539 | bool is_enforce; | 429 | bool is_enforce; |
@@ -586,25 +476,33 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
586 | if (retval < 0) | 476 | if (retval < 0) |
587 | goto out; | 477 | goto out; |
588 | 478 | ||
589 | if (tomoyo_domain_initializer(old_domain->domainname, &rn, &ln)) { | 479 | /* Calculate domain to transit to. */ |
480 | switch (tomoyo_transition_type(old_domain->domainname, &rn)) { | ||
481 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: | ||
590 | /* Transit to the child of tomoyo_kernel_domain domain. */ | 482 | /* Transit to the child of tomoyo_kernel_domain domain. */ |
591 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, | 483 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " " |
592 | TOMOYO_ROOT_NAME " " "%s", rn.name); | 484 | "%s", rn.name); |
593 | } else if (old_domain == &tomoyo_kernel_domain && | 485 | break; |
594 | !tomoyo_policy_loaded) { | 486 | case TOMOYO_TRANSITION_CONTROL_KEEP: |
595 | /* | ||
596 | * Needn't to transit from kernel domain before starting | ||
597 | * /sbin/init. But transit from kernel domain if executing | ||
598 | * initializers because they might start before /sbin/init. | ||
599 | */ | ||
600 | domain = old_domain; | ||
601 | } else if (tomoyo_domain_keeper(old_domain->domainname, &rn, &ln)) { | ||
602 | /* Keep current domain. */ | 487 | /* Keep current domain. */ |
603 | domain = old_domain; | 488 | domain = old_domain; |
604 | } else { | 489 | break; |
605 | /* Normal domain transition. */ | 490 | default: |
606 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, | 491 | if (old_domain == &tomoyo_kernel_domain && |
607 | "%s %s", old_domain_name, rn.name); | 492 | !tomoyo_policy_loaded) { |
493 | /* | ||
494 | * Needn't to transit from kernel domain before | ||
495 | * starting /sbin/init. But transit from kernel domain | ||
496 | * if executing initializers because they might start | ||
497 | * before /sbin/init. | ||
498 | */ | ||
499 | domain = old_domain; | ||
500 | } else { | ||
501 | /* Normal domain transition. */ | ||
502 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | ||
503 | old_domain->domainname->name, rn.name); | ||
504 | } | ||
505 | break; | ||
608 | } | 506 | } |
609 | if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) | 507 | if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) |
610 | goto done; | 508 | goto done; |