domain.c revision 0d2171d711cbfca84cc0001121be8a6cc8e4d148
1/* 2 * security/tomoyo/domain.c 3 * 4 * Domain transition functions for TOMOYO. 5 * 6 * Copyright (C) 2005-2010 NTT DATA CORPORATION 7 */ 8 9#include "common.h" 10#include <linux/binfmts.h> 11#include <linux/slab.h> 12 13/* Variables definitions.*/ 14 15/* The initial domain. */ 16struct tomoyo_domain_info tomoyo_kernel_domain; 17 18/** 19 * tomoyo_update_policy - Update an entry for exception policy. 20 * 21 * @new_entry: Pointer to "struct tomoyo_acl_info". 22 * @size: Size of @new_entry in bytes. 23 * @param: Pointer to "struct tomoyo_acl_param". 24 * @check_duplicate: Callback function to find duplicated entry. 25 * 26 * Returns 0 on success, negative value otherwise. 27 * 28 * Caller holds tomoyo_read_lock(). 29 */ 30int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, 31 struct tomoyo_acl_param *param, 32 bool (*check_duplicate) (const struct tomoyo_acl_head 33 *, 34 const struct tomoyo_acl_head 35 *)) 36{ 37 int error = param->is_delete ? -ENOENT : -ENOMEM; 38 struct tomoyo_acl_head *entry; 39 struct list_head *list = param->list; 40 41 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 42 return -ENOMEM; 43 list_for_each_entry_rcu(entry, list, list) { 44 if (!check_duplicate(entry, new_entry)) 45 continue; 46 entry->is_deleted = param->is_delete; 47 error = 0; 48 break; 49 } 50 if (error && !param->is_delete) { 51 entry = tomoyo_commit_ok(new_entry, size); 52 if (entry) { 53 list_add_tail_rcu(&entry->list, list); 54 error = 0; 55 } 56 } 57 mutex_unlock(&tomoyo_policy_lock); 58 return error; 59} 60 61/** 62 * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry. 63 * 64 * @a: Pointer to "struct tomoyo_acl_info". 65 * @b: Pointer to "struct tomoyo_acl_info". 66 * 67 * Returns true if @a == @b, false otherwise. 68 */ 69static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, 70 const struct tomoyo_acl_info *b) 71{ 72 return a->type == b->type; 73} 74 75/** 76 * tomoyo_update_domain - Update an entry for domain policy. 77 * 78 * @new_entry: Pointer to "struct tomoyo_acl_info". 79 * @size: Size of @new_entry in bytes. 80 * @param: Pointer to "struct tomoyo_acl_param". 81 * @check_duplicate: Callback function to find duplicated entry. 82 * @merge_duplicate: Callback function to merge duplicated entry. 83 * 84 * Returns 0 on success, negative value otherwise. 85 * 86 * Caller holds tomoyo_read_lock(). 87 */ 88int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, 89 struct tomoyo_acl_param *param, 90 bool (*check_duplicate) (const struct tomoyo_acl_info 91 *, 92 const struct tomoyo_acl_info 93 *), 94 bool (*merge_duplicate) (struct tomoyo_acl_info *, 95 struct tomoyo_acl_info *, 96 const bool)) 97{ 98 const bool is_delete = param->is_delete; 99 int error = is_delete ? -ENOENT : -ENOMEM; 100 struct tomoyo_acl_info *entry; 101 struct list_head * const list = param->list; 102 103 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 104 return error; 105 list_for_each_entry_rcu(entry, list, list) { 106 if (!tomoyo_same_acl_head(entry, new_entry) || 107 !check_duplicate(entry, new_entry)) 108 continue; 109 if (merge_duplicate) 110 entry->is_deleted = merge_duplicate(entry, new_entry, 111 is_delete); 112 else 113 entry->is_deleted = is_delete; 114 error = 0; 115 break; 116 } 117 if (error && !is_delete) { 118 entry = tomoyo_commit_ok(new_entry, size); 119 if (entry) { 120 list_add_tail_rcu(&entry->list, list); 121 error = 0; 122 } 123 } 124 mutex_unlock(&tomoyo_policy_lock); 125 return error; 126} 127 128void tomoyo_check_acl(struct tomoyo_request_info *r, 129 bool (*check_entry) (struct tomoyo_request_info *, 130 const struct tomoyo_acl_info *)) 131{ 132 const struct tomoyo_domain_info *domain = r->domain; 133 struct tomoyo_acl_info *ptr; 134 135 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { 136 if (ptr->is_deleted || ptr->type != r->param_type) 137 continue; 138 if (check_entry(r, ptr)) { 139 r->granted = true; 140 return; 141 } 142 } 143 r->granted = false; 144} 145 146/* The list for "struct tomoyo_domain_info". */ 147LIST_HEAD(tomoyo_domain_list); 148 149struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY]; 150struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP]; 151 152/** 153 * tomoyo_last_word - Get last component of a domainname. 154 * 155 * @domainname: Domainname to check. 156 * 157 * Returns the last word of @domainname. 158 */ 159static const char *tomoyo_last_word(const char *name) 160{ 161 const char *cp = strrchr(name, ' '); 162 if (cp) 163 return cp + 1; 164 return name; 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 */ 175static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, 176 const struct tomoyo_acl_head *b) 177{ 178 const struct tomoyo_transition_control *p1 = container_of(a, 179 typeof(*p1), 180 head); 181 const struct tomoyo_transition_control *p2 = container_of(b, 182 typeof(*p2), 183 head); 184 return p1->type == p2->type && p1->is_last_name == p2->is_last_name 185 && p1->domainname == p2->domainname 186 && p1->program == p2->program; 187} 188 189/** 190 * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. 191 * 192 * @param: Pointer to "struct tomoyo_acl_param". 193 * @type: Type of this entry. 194 * 195 * Returns 0 on success, negative value otherwise. 196 */ 197int tomoyo_write_transition_control(struct tomoyo_acl_param *param, 198 const u8 type) 199{ 200 struct tomoyo_transition_control e = { .type = type }; 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 } 212 if (program && strcmp(program, "any")) { 213 if (!tomoyo_correct_path(program)) 214 return -EINVAL; 215 e.program = tomoyo_get_name(program); 216 if (!e.program) 217 goto out; 218 } 219 if (domainname && strcmp(domainname, "any")) { 220 if (!tomoyo_correct_domain(domainname)) { 221 if (!tomoyo_correct_path(domainname)) 222 goto out; 223 e.is_last_name = true; 224 } 225 e.domainname = tomoyo_get_name(domainname); 226 if (!e.domainname) 227 goto out; 228 } 229 param->list = &tomoyo_policy_list[TOMOYO_ID_TRANSITION_CONTROL]; 230 error = tomoyo_update_policy(&e.head, sizeof(e), param, 231 tomoyo_same_transition_control); 232out: 233 tomoyo_put_name(e.domainname); 234 tomoyo_put_name(e.program); 235 return error; 236} 237 238/** 239 * tomoyo_transition_type - Get domain transition type. 240 * 241 * @domainname: The name of domain. 242 * @program: The name of program. 243 * 244 * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program 245 * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing 246 * @program suppresses domain transition, others otherwise. 247 * 248 * Caller holds tomoyo_read_lock(). 249 */ 250static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, 251 const struct tomoyo_path_info *program) 252{ 253 const struct tomoyo_transition_control *ptr; 254 const char *last_name = tomoyo_last_word(domainname->name); 255 u8 type; 256 for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) { 257 next: 258 list_for_each_entry_rcu(ptr, &tomoyo_policy_list 259 [TOMOYO_ID_TRANSITION_CONTROL], 260 head.list) { 261 if (ptr->head.is_deleted || ptr->type != type) 262 continue; 263 if (ptr->domainname) { 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)) 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; 289 } 290 } 291 done: 292 return type; 293} 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 */ 303static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, 304 const struct tomoyo_acl_head *b) 305{ 306 const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), 307 head); 308 const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), 309 head); 310 return p1->original_name == p2->original_name && 311 p1->aggregated_name == p2->aggregated_name; 312} 313 314/** 315 * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. 316 * 317 * @param: Pointer to "struct tomoyo_acl_param". 318 * 319 * Returns 0 on success, negative value otherwise. 320 * 321 * Caller holds tomoyo_read_lock(). 322 */ 323int tomoyo_write_aggregator(struct tomoyo_acl_param *param) 324{ 325 struct tomoyo_aggregator e = { }; 326 int error = param->is_delete ? -ENOENT : -ENOMEM; 327 const char *original_name = tomoyo_read_token(param); 328 const char *aggregated_name = tomoyo_read_token(param); 329 if (!tomoyo_correct_word(original_name) || 330 !tomoyo_correct_path(aggregated_name)) 331 return -EINVAL; 332 e.original_name = tomoyo_get_name(original_name); 333 e.aggregated_name = tomoyo_get_name(aggregated_name); 334 if (!e.original_name || !e.aggregated_name || 335 e.aggregated_name->is_patterned) /* No patterns allowed. */ 336 goto out; 337 param->list = &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR]; 338 error = tomoyo_update_policy(&e.head, sizeof(e), param, 339 tomoyo_same_aggregator); 340out: 341 tomoyo_put_name(e.original_name); 342 tomoyo_put_name(e.aggregated_name); 343 return error; 344} 345 346/** 347 * tomoyo_assign_domain - Create a domain. 348 * 349 * @domainname: The name of domain. 350 * @profile: Profile number to assign if the domain was newly created. 351 * 352 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. 353 * 354 * Caller holds tomoyo_read_lock(). 355 */ 356struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, 357 const u8 profile) 358{ 359 struct tomoyo_domain_info *entry; 360 struct tomoyo_domain_info *domain = NULL; 361 const struct tomoyo_path_info *saved_domainname; 362 bool found = false; 363 364 if (!tomoyo_correct_domain(domainname)) 365 return NULL; 366 saved_domainname = tomoyo_get_name(domainname); 367 if (!saved_domainname) 368 return NULL; 369 entry = kzalloc(sizeof(*entry), GFP_NOFS); 370 if (mutex_lock_interruptible(&tomoyo_policy_lock)) 371 goto out; 372 list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { 373 if (domain->is_deleted || 374 tomoyo_pathcmp(saved_domainname, domain->domainname)) 375 continue; 376 found = true; 377 break; 378 } 379 if (!found && tomoyo_memory_ok(entry)) { 380 INIT_LIST_HEAD(&entry->acl_info_list); 381 entry->domainname = saved_domainname; 382 saved_domainname = NULL; 383 entry->profile = profile; 384 list_add_tail_rcu(&entry->list, &tomoyo_domain_list); 385 domain = entry; 386 entry = NULL; 387 found = true; 388 } 389 mutex_unlock(&tomoyo_policy_lock); 390 out: 391 tomoyo_put_name(saved_domainname); 392 kfree(entry); 393 return found ? domain : NULL; 394} 395 396/** 397 * tomoyo_find_next_domain - Find a domain. 398 * 399 * @bprm: Pointer to "struct linux_binprm". 400 * 401 * Returns 0 on success, negative value otherwise. 402 * 403 * Caller holds tomoyo_read_lock(). 404 */ 405int tomoyo_find_next_domain(struct linux_binprm *bprm) 406{ 407 struct tomoyo_request_info r; 408 char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); 409 struct tomoyo_domain_info *old_domain = tomoyo_domain(); 410 struct tomoyo_domain_info *domain = NULL; 411 const char *original_name = bprm->filename; 412 u8 mode; 413 bool is_enforce; 414 int retval = -ENOMEM; 415 bool need_kfree = false; 416 struct tomoyo_path_info rn = { }; /* real name */ 417 418 mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); 419 is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); 420 if (!tmp) 421 goto out; 422 423 retry: 424 if (need_kfree) { 425 kfree(rn.name); 426 need_kfree = false; 427 } 428 /* Get symlink's pathname of program. */ 429 retval = -ENOENT; 430 rn.name = tomoyo_realpath_nofollow(original_name); 431 if (!rn.name) 432 goto out; 433 tomoyo_fill_path_info(&rn); 434 need_kfree = true; 435 436 /* Check 'aggregator' directive. */ 437 { 438 struct tomoyo_aggregator *ptr; 439 list_for_each_entry_rcu(ptr, &tomoyo_policy_list 440 [TOMOYO_ID_AGGREGATOR], head.list) { 441 if (ptr->head.is_deleted || 442 !tomoyo_path_matches_pattern(&rn, 443 ptr->original_name)) 444 continue; 445 kfree(rn.name); 446 need_kfree = false; 447 /* This is OK because it is read only. */ 448 rn = *ptr->aggregated_name; 449 break; 450 } 451 } 452 453 /* Check execute permission. */ 454 retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn); 455 if (retval == TOMOYO_RETRY_REQUEST) 456 goto retry; 457 if (retval < 0) 458 goto out; 459 /* 460 * To be able to specify domainnames with wildcards, use the 461 * pathname specified in the policy (which may contain 462 * wildcard) rather than the pathname passed to execve() 463 * (which never contains wildcard). 464 */ 465 if (r.param.path.matched_path) { 466 if (need_kfree) 467 kfree(rn.name); 468 need_kfree = false; 469 /* This is OK because it is read only. */ 470 rn = *r.param.path.matched_path; 471 } 472 473 /* Calculate domain to transit to. */ 474 switch (tomoyo_transition_type(old_domain->domainname, &rn)) { 475 case TOMOYO_TRANSITION_CONTROL_INITIALIZE: 476 /* Transit to the child of tomoyo_kernel_domain domain. */ 477 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " " 478 "%s", rn.name); 479 break; 480 case TOMOYO_TRANSITION_CONTROL_KEEP: 481 /* Keep current domain. */ 482 domain = old_domain; 483 break; 484 default: 485 if (old_domain == &tomoyo_kernel_domain && 486 !tomoyo_policy_loaded) { 487 /* 488 * Needn't to transit from kernel domain before 489 * starting /sbin/init. But transit from kernel domain 490 * if executing initializers because they might start 491 * before /sbin/init. 492 */ 493 domain = old_domain; 494 } else { 495 /* Normal domain transition. */ 496 snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", 497 old_domain->domainname->name, rn.name); 498 } 499 break; 500 } 501 if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) 502 goto done; 503 domain = tomoyo_find_domain(tmp); 504 if (!domain) 505 domain = tomoyo_assign_domain(tmp, old_domain->profile); 506 done: 507 if (domain) 508 goto out; 509 printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp); 510 if (is_enforce) 511 retval = -EPERM; 512 else 513 old_domain->transition_failed = true; 514 out: 515 if (!domain) 516 domain = old_domain; 517 /* Update reference count on "struct tomoyo_domain_info". */ 518 atomic_inc(&domain->users); 519 bprm->cred->security = domain; 520 if (need_kfree) 521 kfree(rn.name); 522 kfree(tmp); 523 return retval; 524} 525