| .. | .. |
|---|
| 9 | 9 | #include "common.h" |
|---|
| 10 | 10 | |
|---|
| 11 | 11 | /** |
|---|
| 12 | | - * tomoyo_cred_alloc_blank - Target for security_cred_alloc_blank(). |
|---|
| 12 | + * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread. |
|---|
| 13 | 13 | * |
|---|
| 14 | | - * @new: Pointer to "struct cred". |
|---|
| 15 | | - * @gfp: Memory allocation flags. |
|---|
| 16 | | - * |
|---|
| 17 | | - * Returns 0. |
|---|
| 14 | + * Returns pointer to "struct tomoyo_domain_info" for current thread. |
|---|
| 18 | 15 | */ |
|---|
| 19 | | -static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) |
|---|
| 16 | +struct tomoyo_domain_info *tomoyo_domain(void) |
|---|
| 20 | 17 | { |
|---|
| 21 | | - new->security = NULL; |
|---|
| 22 | | - return 0; |
|---|
| 18 | + struct tomoyo_task *s = tomoyo_task(current); |
|---|
| 19 | + |
|---|
| 20 | + if (s->old_domain_info && !current->in_execve) { |
|---|
| 21 | + atomic_dec(&s->old_domain_info->users); |
|---|
| 22 | + s->old_domain_info = NULL; |
|---|
| 23 | + } |
|---|
| 24 | + return s->domain_info; |
|---|
| 23 | 25 | } |
|---|
| 24 | 26 | |
|---|
| 25 | 27 | /** |
|---|
| .. | .. |
|---|
| 34 | 36 | static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, |
|---|
| 35 | 37 | gfp_t gfp) |
|---|
| 36 | 38 | { |
|---|
| 37 | | - struct tomoyo_domain_info *domain = old->security; |
|---|
| 38 | | - new->security = domain; |
|---|
| 39 | | - if (domain) |
|---|
| 40 | | - atomic_inc(&domain->users); |
|---|
| 39 | + /* Restore old_domain_info saved by previous execve() request. */ |
|---|
| 40 | + struct tomoyo_task *s = tomoyo_task(current); |
|---|
| 41 | + |
|---|
| 42 | + if (s->old_domain_info && !current->in_execve) { |
|---|
| 43 | + atomic_dec(&s->domain_info->users); |
|---|
| 44 | + s->domain_info = s->old_domain_info; |
|---|
| 45 | + s->old_domain_info = NULL; |
|---|
| 46 | + } |
|---|
| 41 | 47 | return 0; |
|---|
| 42 | 48 | } |
|---|
| 43 | 49 | |
|---|
| 44 | 50 | /** |
|---|
| 45 | | - * tomoyo_cred_transfer - Target for security_transfer_creds(). |
|---|
| 51 | + * tomoyo_bprm_committed_creds - Target for security_bprm_committed_creds(). |
|---|
| 46 | 52 | * |
|---|
| 47 | | - * @new: Pointer to "struct cred". |
|---|
| 48 | | - * @old: Pointer to "struct cred". |
|---|
| 53 | + * @bprm: Pointer to "struct linux_binprm". |
|---|
| 49 | 54 | */ |
|---|
| 50 | | -static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) |
|---|
| 55 | +static void tomoyo_bprm_committed_creds(struct linux_binprm *bprm) |
|---|
| 51 | 56 | { |
|---|
| 52 | | - tomoyo_cred_prepare(new, old, 0); |
|---|
| 57 | + /* Clear old_domain_info saved by execve() request. */ |
|---|
| 58 | + struct tomoyo_task *s = tomoyo_task(current); |
|---|
| 59 | + |
|---|
| 60 | + atomic_dec(&s->old_domain_info->users); |
|---|
| 61 | + s->old_domain_info = NULL; |
|---|
| 53 | 62 | } |
|---|
| 54 | 63 | |
|---|
| 64 | +#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER |
|---|
| 55 | 65 | /** |
|---|
| 56 | | - * tomoyo_cred_free - Target for security_cred_free(). |
|---|
| 57 | | - * |
|---|
| 58 | | - * @cred: Pointer to "struct cred". |
|---|
| 59 | | - */ |
|---|
| 60 | | -static void tomoyo_cred_free(struct cred *cred) |
|---|
| 61 | | -{ |
|---|
| 62 | | - struct tomoyo_domain_info *domain = cred->security; |
|---|
| 63 | | - if (domain) |
|---|
| 64 | | - atomic_dec(&domain->users); |
|---|
| 65 | | -} |
|---|
| 66 | | - |
|---|
| 67 | | -/** |
|---|
| 68 | | - * tomoyo_bprm_set_creds - Target for security_bprm_set_creds(). |
|---|
| 66 | + * tomoyo_bprm_for_exec - Target for security_bprm_creds_for_exec(). |
|---|
| 69 | 67 | * |
|---|
| 70 | 68 | * @bprm: Pointer to "struct linux_binprm". |
|---|
| 71 | 69 | * |
|---|
| 72 | | - * Returns 0 on success, negative value otherwise. |
|---|
| 70 | + * Returns 0. |
|---|
| 73 | 71 | */ |
|---|
| 74 | | -static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
|---|
| 72 | +static int tomoyo_bprm_creds_for_exec(struct linux_binprm *bprm) |
|---|
| 75 | 73 | { |
|---|
| 76 | | - /* |
|---|
| 77 | | - * Do only if this function is called for the first time of an execve |
|---|
| 78 | | - * operation. |
|---|
| 79 | | - */ |
|---|
| 80 | | - if (bprm->called_set_creds) |
|---|
| 81 | | - return 0; |
|---|
| 82 | | -#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER |
|---|
| 83 | 74 | /* |
|---|
| 84 | 75 | * Load policy if /sbin/tomoyo-init exists and /sbin/init is requested |
|---|
| 85 | 76 | * for the first time. |
|---|
| 86 | 77 | */ |
|---|
| 87 | 78 | if (!tomoyo_policy_loaded) |
|---|
| 88 | 79 | tomoyo_load_policy(bprm->filename); |
|---|
| 89 | | -#endif |
|---|
| 90 | | - /* |
|---|
| 91 | | - * Release reference to "struct tomoyo_domain_info" stored inside |
|---|
| 92 | | - * "bprm->cred->security". New reference to "struct tomoyo_domain_info" |
|---|
| 93 | | - * stored inside "bprm->cred->security" will be acquired later inside |
|---|
| 94 | | - * tomoyo_find_next_domain(). |
|---|
| 95 | | - */ |
|---|
| 96 | | - atomic_dec(&((struct tomoyo_domain_info *) |
|---|
| 97 | | - bprm->cred->security)->users); |
|---|
| 98 | | - /* |
|---|
| 99 | | - * Tell tomoyo_bprm_check_security() is called for the first time of an |
|---|
| 100 | | - * execve operation. |
|---|
| 101 | | - */ |
|---|
| 102 | | - bprm->cred->security = NULL; |
|---|
| 103 | 80 | return 0; |
|---|
| 104 | 81 | } |
|---|
| 82 | +#endif |
|---|
| 105 | 83 | |
|---|
| 106 | 84 | /** |
|---|
| 107 | 85 | * tomoyo_bprm_check_security - Target for security_bprm_check(). |
|---|
| .. | .. |
|---|
| 112 | 90 | */ |
|---|
| 113 | 91 | static int tomoyo_bprm_check_security(struct linux_binprm *bprm) |
|---|
| 114 | 92 | { |
|---|
| 115 | | - struct tomoyo_domain_info *domain = bprm->cred->security; |
|---|
| 93 | + struct tomoyo_task *s = tomoyo_task(current); |
|---|
| 116 | 94 | |
|---|
| 117 | 95 | /* |
|---|
| 118 | | - * Execute permission is checked against pathname passed to do_execve() |
|---|
| 96 | + * Execute permission is checked against pathname passed to execve() |
|---|
| 119 | 97 | * using current domain. |
|---|
| 120 | 98 | */ |
|---|
| 121 | | - if (!domain) { |
|---|
| 99 | + if (!s->old_domain_info) { |
|---|
| 122 | 100 | const int idx = tomoyo_read_lock(); |
|---|
| 123 | 101 | const int err = tomoyo_find_next_domain(bprm); |
|---|
| 102 | + |
|---|
| 124 | 103 | tomoyo_read_unlock(idx); |
|---|
| 125 | 104 | return err; |
|---|
| 126 | 105 | } |
|---|
| 127 | 106 | /* |
|---|
| 128 | 107 | * Read permission is checked against interpreters using next domain. |
|---|
| 129 | 108 | */ |
|---|
| 130 | | - return tomoyo_check_open_permission(domain, &bprm->file->f_path, |
|---|
| 131 | | - O_RDONLY); |
|---|
| 109 | + return tomoyo_check_open_permission(s->domain_info, |
|---|
| 110 | + &bprm->file->f_path, O_RDONLY); |
|---|
| 132 | 111 | } |
|---|
| 133 | 112 | |
|---|
| 134 | 113 | /** |
|---|
| .. | .. |
|---|
| 167 | 146 | static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry) |
|---|
| 168 | 147 | { |
|---|
| 169 | 148 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; |
|---|
| 149 | + |
|---|
| 170 | 150 | return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL); |
|---|
| 171 | 151 | } |
|---|
| 172 | 152 | |
|---|
| .. | .. |
|---|
| 183 | 163 | umode_t mode) |
|---|
| 184 | 164 | { |
|---|
| 185 | 165 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; |
|---|
| 166 | + |
|---|
| 186 | 167 | return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path, |
|---|
| 187 | 168 | mode & S_IALLUGO); |
|---|
| 188 | 169 | } |
|---|
| .. | .. |
|---|
| 198 | 179 | static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry) |
|---|
| 199 | 180 | { |
|---|
| 200 | 181 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; |
|---|
| 182 | + |
|---|
| 201 | 183 | return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL); |
|---|
| 202 | 184 | } |
|---|
| 203 | 185 | |
|---|
| .. | .. |
|---|
| 214 | 196 | const char *old_name) |
|---|
| 215 | 197 | { |
|---|
| 216 | 198 | struct path path = { .mnt = parent->mnt, .dentry = dentry }; |
|---|
| 199 | + |
|---|
| 217 | 200 | return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name); |
|---|
| 218 | 201 | } |
|---|
| 219 | 202 | |
|---|
| .. | .. |
|---|
| 271 | 254 | { |
|---|
| 272 | 255 | struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry }; |
|---|
| 273 | 256 | struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry }; |
|---|
| 257 | + |
|---|
| 274 | 258 | return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); |
|---|
| 275 | 259 | } |
|---|
| 276 | 260 | |
|---|
| .. | .. |
|---|
| 291 | 275 | { |
|---|
| 292 | 276 | struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry }; |
|---|
| 293 | 277 | struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry }; |
|---|
| 278 | + |
|---|
| 294 | 279 | return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); |
|---|
| 295 | 280 | } |
|---|
| 296 | 281 | |
|---|
| .. | .. |
|---|
| 322 | 307 | */ |
|---|
| 323 | 308 | static int tomoyo_file_open(struct file *f) |
|---|
| 324 | 309 | { |
|---|
| 325 | | - int flags = f->f_flags; |
|---|
| 326 | | - /* Don't check read permission here if called from do_execve(). */ |
|---|
| 310 | + /* Don't check read permission here if called from execve(). */ |
|---|
| 327 | 311 | if (current->in_execve) |
|---|
| 328 | 312 | return 0; |
|---|
| 329 | | - return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); |
|---|
| 313 | + return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, |
|---|
| 314 | + f->f_flags); |
|---|
| 330 | 315 | } |
|---|
| 331 | 316 | |
|---|
| 332 | 317 | /** |
|---|
| .. | .. |
|---|
| 370 | 355 | static int tomoyo_path_chown(const struct path *path, kuid_t uid, kgid_t gid) |
|---|
| 371 | 356 | { |
|---|
| 372 | 357 | int error = 0; |
|---|
| 358 | + |
|---|
| 373 | 359 | if (uid_valid(uid)) |
|---|
| 374 | 360 | error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, |
|---|
| 375 | 361 | from_kuid(&init_user_ns, uid)); |
|---|
| .. | .. |
|---|
| 419 | 405 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) |
|---|
| 420 | 406 | { |
|---|
| 421 | 407 | struct path path = { .mnt = mnt, .dentry = mnt->mnt_root }; |
|---|
| 408 | + |
|---|
| 422 | 409 | return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL); |
|---|
| 423 | 410 | } |
|---|
| 424 | 411 | |
|---|
| .. | .. |
|---|
| 493 | 480 | return tomoyo_socket_sendmsg_permission(sock, msg, size); |
|---|
| 494 | 481 | } |
|---|
| 495 | 482 | |
|---|
| 483 | +struct lsm_blob_sizes tomoyo_blob_sizes __lsm_ro_after_init = { |
|---|
| 484 | + .lbs_task = sizeof(struct tomoyo_task), |
|---|
| 485 | +}; |
|---|
| 486 | + |
|---|
| 487 | +/** |
|---|
| 488 | + * tomoyo_task_alloc - Target for security_task_alloc(). |
|---|
| 489 | + * |
|---|
| 490 | + * @task: Pointer to "struct task_struct". |
|---|
| 491 | + * @flags: clone() flags. |
|---|
| 492 | + * |
|---|
| 493 | + * Returns 0. |
|---|
| 494 | + */ |
|---|
| 495 | +static int tomoyo_task_alloc(struct task_struct *task, |
|---|
| 496 | + unsigned long clone_flags) |
|---|
| 497 | +{ |
|---|
| 498 | + struct tomoyo_task *old = tomoyo_task(current); |
|---|
| 499 | + struct tomoyo_task *new = tomoyo_task(task); |
|---|
| 500 | + |
|---|
| 501 | + new->domain_info = old->domain_info; |
|---|
| 502 | + atomic_inc(&new->domain_info->users); |
|---|
| 503 | + new->old_domain_info = NULL; |
|---|
| 504 | + return 0; |
|---|
| 505 | +} |
|---|
| 506 | + |
|---|
| 507 | +/** |
|---|
| 508 | + * tomoyo_task_free - Target for security_task_free(). |
|---|
| 509 | + * |
|---|
| 510 | + * @task: Pointer to "struct task_struct". |
|---|
| 511 | + */ |
|---|
| 512 | +static void tomoyo_task_free(struct task_struct *task) |
|---|
| 513 | +{ |
|---|
| 514 | + struct tomoyo_task *s = tomoyo_task(task); |
|---|
| 515 | + |
|---|
| 516 | + if (s->domain_info) { |
|---|
| 517 | + atomic_dec(&s->domain_info->users); |
|---|
| 518 | + s->domain_info = NULL; |
|---|
| 519 | + } |
|---|
| 520 | + if (s->old_domain_info) { |
|---|
| 521 | + atomic_dec(&s->old_domain_info->users); |
|---|
| 522 | + s->old_domain_info = NULL; |
|---|
| 523 | + } |
|---|
| 524 | +} |
|---|
| 525 | + |
|---|
| 496 | 526 | /* |
|---|
| 497 | 527 | * tomoyo_security_ops is a "struct security_operations" which is used for |
|---|
| 498 | 528 | * registering TOMOYO. |
|---|
| 499 | 529 | */ |
|---|
| 500 | 530 | static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { |
|---|
| 501 | | - LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank), |
|---|
| 502 | 531 | LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare), |
|---|
| 503 | | - LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer), |
|---|
| 504 | | - LSM_HOOK_INIT(cred_free, tomoyo_cred_free), |
|---|
| 505 | | - LSM_HOOK_INIT(bprm_set_creds, tomoyo_bprm_set_creds), |
|---|
| 532 | + LSM_HOOK_INIT(bprm_committed_creds, tomoyo_bprm_committed_creds), |
|---|
| 533 | + LSM_HOOK_INIT(task_alloc, tomoyo_task_alloc), |
|---|
| 534 | + LSM_HOOK_INIT(task_free, tomoyo_task_free), |
|---|
| 535 | +#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER |
|---|
| 536 | + LSM_HOOK_INIT(bprm_creds_for_exec, tomoyo_bprm_creds_for_exec), |
|---|
| 537 | +#endif |
|---|
| 506 | 538 | LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security), |
|---|
| 507 | 539 | LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl), |
|---|
| 508 | 540 | LSM_HOOK_INIT(file_open, tomoyo_file_open), |
|---|
| .. | .. |
|---|
| 531 | 563 | /* Lock for GC. */ |
|---|
| 532 | 564 | DEFINE_SRCU(tomoyo_ss); |
|---|
| 533 | 565 | |
|---|
| 566 | +int tomoyo_enabled __lsm_ro_after_init = 1; |
|---|
| 567 | + |
|---|
| 534 | 568 | /** |
|---|
| 535 | 569 | * tomoyo_init - Register TOMOYO Linux as a LSM module. |
|---|
| 536 | 570 | * |
|---|
| .. | .. |
|---|
| 538 | 572 | */ |
|---|
| 539 | 573 | static int __init tomoyo_init(void) |
|---|
| 540 | 574 | { |
|---|
| 541 | | - struct cred *cred = (struct cred *) current_cred(); |
|---|
| 575 | + struct tomoyo_task *s = tomoyo_task(current); |
|---|
| 542 | 576 | |
|---|
| 543 | | - if (!security_module_enable("tomoyo")) |
|---|
| 544 | | - return 0; |
|---|
| 545 | 577 | /* register ourselves with the security framework */ |
|---|
| 546 | 578 | security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo"); |
|---|
| 547 | | - printk(KERN_INFO "TOMOYO Linux initialized\n"); |
|---|
| 548 | | - cred->security = &tomoyo_kernel_domain; |
|---|
| 579 | + pr_info("TOMOYO Linux initialized\n"); |
|---|
| 580 | + s->domain_info = &tomoyo_kernel_domain; |
|---|
| 581 | + atomic_inc(&tomoyo_kernel_domain.users); |
|---|
| 582 | + s->old_domain_info = NULL; |
|---|
| 549 | 583 | tomoyo_mm_init(); |
|---|
| 584 | + |
|---|
| 550 | 585 | return 0; |
|---|
| 551 | 586 | } |
|---|
| 552 | 587 | |
|---|
| 553 | | -security_initcall(tomoyo_init); |
|---|
| 588 | +DEFINE_LSM(tomoyo) = { |
|---|
| 589 | + .name = "tomoyo", |
|---|
| 590 | + .enabled = &tomoyo_enabled, |
|---|
| 591 | + .flags = LSM_FLAG_LEGACY_MAJOR, |
|---|
| 592 | + .blobs = &tomoyo_blob_sizes, |
|---|
| 593 | + .init = tomoyo_init, |
|---|
| 594 | +}; |
|---|