diff options
Diffstat (limited to 'security')
44 files changed, 1204 insertions, 826 deletions
diff --git a/security/capability.c b/security/capability.c index 4875142b858d..8168e3ecd5bf 100644 --- a/security/capability.c +++ b/security/capability.c | |||
| @@ -12,11 +12,6 @@ | |||
| 12 | 12 | ||
| 13 | #include <linux/security.h> | 13 | #include <linux/security.h> |
| 14 | 14 | ||
| 15 | static int cap_acct(struct file *file) | ||
| 16 | { | ||
| 17 | return 0; | ||
| 18 | } | ||
| 19 | |||
| 20 | static int cap_sysctl(ctl_table *table, int op) | 15 | static int cap_sysctl(ctl_table *table, int op) |
| 21 | { | 16 | { |
| 22 | return 0; | 17 | return 0; |
| @@ -80,42 +75,16 @@ static int cap_sb_mount(char *dev_name, struct path *path, char *type, | |||
| 80 | return 0; | 75 | return 0; |
| 81 | } | 76 | } |
| 82 | 77 | ||
| 83 | static int cap_sb_check_sb(struct vfsmount *mnt, struct path *path) | ||
| 84 | { | ||
| 85 | return 0; | ||
| 86 | } | ||
| 87 | |||
| 88 | static int cap_sb_umount(struct vfsmount *mnt, int flags) | 78 | static int cap_sb_umount(struct vfsmount *mnt, int flags) |
| 89 | { | 79 | { |
| 90 | return 0; | 80 | return 0; |
| 91 | } | 81 | } |
| 92 | 82 | ||
| 93 | static void cap_sb_umount_close(struct vfsmount *mnt) | ||
| 94 | { | ||
| 95 | } | ||
| 96 | |||
| 97 | static void cap_sb_umount_busy(struct vfsmount *mnt) | ||
| 98 | { | ||
| 99 | } | ||
| 100 | |||
| 101 | static void cap_sb_post_remount(struct vfsmount *mnt, unsigned long flags, | ||
| 102 | void *data) | ||
| 103 | { | ||
| 104 | } | ||
| 105 | |||
| 106 | static void cap_sb_post_addmount(struct vfsmount *mnt, struct path *path) | ||
| 107 | { | ||
| 108 | } | ||
| 109 | |||
| 110 | static int cap_sb_pivotroot(struct path *old_path, struct path *new_path) | 83 | static int cap_sb_pivotroot(struct path *old_path, struct path *new_path) |
| 111 | { | 84 | { |
| 112 | return 0; | 85 | return 0; |
| 113 | } | 86 | } |
| 114 | 87 | ||
| 115 | static void cap_sb_post_pivotroot(struct path *old_path, struct path *new_path) | ||
| 116 | { | ||
| 117 | } | ||
| 118 | |||
| 119 | static int cap_sb_set_mnt_opts(struct super_block *sb, | 88 | static int cap_sb_set_mnt_opts(struct super_block *sb, |
| 120 | struct security_mnt_opts *opts) | 89 | struct security_mnt_opts *opts) |
| 121 | { | 90 | { |
| @@ -221,10 +190,6 @@ static int cap_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
| 221 | return 0; | 190 | return 0; |
| 222 | } | 191 | } |
| 223 | 192 | ||
| 224 | static void cap_inode_delete(struct inode *ino) | ||
| 225 | { | ||
| 226 | } | ||
| 227 | |||
| 228 | static void cap_inode_post_setxattr(struct dentry *dentry, const char *name, | 193 | static void cap_inode_post_setxattr(struct dentry *dentry, const char *name, |
| 229 | const void *value, size_t size, int flags) | 194 | const void *value, size_t size, int flags) |
| 230 | { | 195 | { |
| @@ -403,10 +368,6 @@ static int cap_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) | |||
| 403 | return 0; | 368 | return 0; |
| 404 | } | 369 | } |
| 405 | 370 | ||
| 406 | static void cap_cred_commit(struct cred *new, const struct cred *old) | ||
| 407 | { | ||
| 408 | } | ||
| 409 | |||
| 410 | static void cap_cred_transfer(struct cred *new, const struct cred *old) | 371 | static void cap_cred_transfer(struct cred *new, const struct cred *old) |
| 411 | { | 372 | { |
| 412 | } | 373 | } |
| @@ -426,16 +387,6 @@ static int cap_kernel_module_request(char *kmod_name) | |||
| 426 | return 0; | 387 | return 0; |
| 427 | } | 388 | } |
| 428 | 389 | ||
| 429 | static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | ||
| 430 | { | ||
| 431 | return 0; | ||
| 432 | } | ||
| 433 | |||
| 434 | static int cap_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) | ||
| 435 | { | ||
| 436 | return 0; | ||
| 437 | } | ||
| 438 | |||
| 439 | static int cap_task_setpgid(struct task_struct *p, pid_t pgid) | 390 | static int cap_task_setpgid(struct task_struct *p, pid_t pgid) |
| 440 | { | 391 | { |
| 441 | return 0; | 392 | return 0; |
| @@ -456,11 +407,6 @@ static void cap_task_getsecid(struct task_struct *p, u32 *secid) | |||
| 456 | *secid = 0; | 407 | *secid = 0; |
| 457 | } | 408 | } |
| 458 | 409 | ||
| 459 | static int cap_task_setgroups(struct group_info *group_info) | ||
| 460 | { | ||
| 461 | return 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | static int cap_task_getioprio(struct task_struct *p) | 410 | static int cap_task_getioprio(struct task_struct *p) |
| 465 | { | 411 | { |
| 466 | return 0; | 412 | return 0; |
| @@ -875,13 +821,6 @@ static int cap_key_getsecurity(struct key *key, char **_buffer) | |||
| 875 | return 0; | 821 | return 0; |
| 876 | } | 822 | } |
| 877 | 823 | ||
| 878 | static int cap_key_session_to_parent(const struct cred *cred, | ||
| 879 | const struct cred *parent_cred, | ||
| 880 | struct key *key) | ||
| 881 | { | ||
| 882 | return 0; | ||
| 883 | } | ||
| 884 | |||
| 885 | #endif /* CONFIG_KEYS */ | 824 | #endif /* CONFIG_KEYS */ |
| 886 | 825 | ||
| 887 | #ifdef CONFIG_AUDIT | 826 | #ifdef CONFIG_AUDIT |
| @@ -915,13 +854,12 @@ static void cap_audit_rule_free(void *lsmrule) | |||
| 915 | } \ | 854 | } \ |
| 916 | } while (0) | 855 | } while (0) |
| 917 | 856 | ||
| 918 | void security_fixup_ops(struct security_operations *ops) | 857 | void __init security_fixup_ops(struct security_operations *ops) |
| 919 | { | 858 | { |
| 920 | set_to_cap_if_null(ops, ptrace_access_check); | 859 | set_to_cap_if_null(ops, ptrace_access_check); |
| 921 | set_to_cap_if_null(ops, ptrace_traceme); | 860 | set_to_cap_if_null(ops, ptrace_traceme); |
| 922 | set_to_cap_if_null(ops, capget); | 861 | set_to_cap_if_null(ops, capget); |
| 923 | set_to_cap_if_null(ops, capset); | 862 | set_to_cap_if_null(ops, capset); |
| 924 | set_to_cap_if_null(ops, acct); | ||
| 925 | set_to_cap_if_null(ops, capable); | 863 | set_to_cap_if_null(ops, capable); |
| 926 | set_to_cap_if_null(ops, quotactl); | 864 | set_to_cap_if_null(ops, quotactl); |
| 927 | set_to_cap_if_null(ops, quota_on); | 865 | set_to_cap_if_null(ops, quota_on); |
| @@ -941,14 +879,8 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 941 | set_to_cap_if_null(ops, sb_show_options); | 879 | set_to_cap_if_null(ops, sb_show_options); |
| 942 | set_to_cap_if_null(ops, sb_statfs); | 880 | set_to_cap_if_null(ops, sb_statfs); |
| 943 | set_to_cap_if_null(ops, sb_mount); | 881 | set_to_cap_if_null(ops, sb_mount); |
| 944 | set_to_cap_if_null(ops, sb_check_sb); | ||
| 945 | set_to_cap_if_null(ops, sb_umount); | 882 | set_to_cap_if_null(ops, sb_umount); |
| 946 | set_to_cap_if_null(ops, sb_umount_close); | ||
| 947 | set_to_cap_if_null(ops, sb_umount_busy); | ||
| 948 | set_to_cap_if_null(ops, sb_post_remount); | ||
| 949 | set_to_cap_if_null(ops, sb_post_addmount); | ||
| 950 | set_to_cap_if_null(ops, sb_pivotroot); | 883 | set_to_cap_if_null(ops, sb_pivotroot); |
| 951 | set_to_cap_if_null(ops, sb_post_pivotroot); | ||
| 952 | set_to_cap_if_null(ops, sb_set_mnt_opts); | 884 | set_to_cap_if_null(ops, sb_set_mnt_opts); |
| 953 | set_to_cap_if_null(ops, sb_clone_mnt_opts); | 885 | set_to_cap_if_null(ops, sb_clone_mnt_opts); |
| 954 | set_to_cap_if_null(ops, sb_parse_opts_str); | 886 | set_to_cap_if_null(ops, sb_parse_opts_str); |
| @@ -968,7 +900,6 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 968 | set_to_cap_if_null(ops, inode_permission); | 900 | set_to_cap_if_null(ops, inode_permission); |
| 969 | set_to_cap_if_null(ops, inode_setattr); | 901 | set_to_cap_if_null(ops, inode_setattr); |
| 970 | set_to_cap_if_null(ops, inode_getattr); | 902 | set_to_cap_if_null(ops, inode_getattr); |
| 971 | set_to_cap_if_null(ops, inode_delete); | ||
| 972 | set_to_cap_if_null(ops, inode_setxattr); | 903 | set_to_cap_if_null(ops, inode_setxattr); |
| 973 | set_to_cap_if_null(ops, inode_post_setxattr); | 904 | set_to_cap_if_null(ops, inode_post_setxattr); |
| 974 | set_to_cap_if_null(ops, inode_getxattr); | 905 | set_to_cap_if_null(ops, inode_getxattr); |
| @@ -1009,19 +940,15 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 1009 | set_to_cap_if_null(ops, cred_alloc_blank); | 940 | set_to_cap_if_null(ops, cred_alloc_blank); |
| 1010 | set_to_cap_if_null(ops, cred_free); | 941 | set_to_cap_if_null(ops, cred_free); |
| 1011 | set_to_cap_if_null(ops, cred_prepare); | 942 | set_to_cap_if_null(ops, cred_prepare); |
| 1012 | set_to_cap_if_null(ops, cred_commit); | ||
| 1013 | set_to_cap_if_null(ops, cred_transfer); | 943 | set_to_cap_if_null(ops, cred_transfer); |
| 1014 | set_to_cap_if_null(ops, kernel_act_as); | 944 | set_to_cap_if_null(ops, kernel_act_as); |
| 1015 | set_to_cap_if_null(ops, kernel_create_files_as); | 945 | set_to_cap_if_null(ops, kernel_create_files_as); |
| 1016 | set_to_cap_if_null(ops, kernel_module_request); | 946 | set_to_cap_if_null(ops, kernel_module_request); |
| 1017 | set_to_cap_if_null(ops, task_setuid); | ||
| 1018 | set_to_cap_if_null(ops, task_fix_setuid); | 947 | set_to_cap_if_null(ops, task_fix_setuid); |
| 1019 | set_to_cap_if_null(ops, task_setgid); | ||
| 1020 | set_to_cap_if_null(ops, task_setpgid); | 948 | set_to_cap_if_null(ops, task_setpgid); |
| 1021 | set_to_cap_if_null(ops, task_getpgid); | 949 | set_to_cap_if_null(ops, task_getpgid); |
| 1022 | set_to_cap_if_null(ops, task_getsid); | 950 | set_to_cap_if_null(ops, task_getsid); |
| 1023 | set_to_cap_if_null(ops, task_getsecid); | 951 | set_to_cap_if_null(ops, task_getsecid); |
| 1024 | set_to_cap_if_null(ops, task_setgroups); | ||
| 1025 | set_to_cap_if_null(ops, task_setnice); | 952 | set_to_cap_if_null(ops, task_setnice); |
| 1026 | set_to_cap_if_null(ops, task_setioprio); | 953 | set_to_cap_if_null(ops, task_setioprio); |
| 1027 | set_to_cap_if_null(ops, task_getioprio); | 954 | set_to_cap_if_null(ops, task_getioprio); |
| @@ -1113,7 +1040,6 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 1113 | set_to_cap_if_null(ops, key_free); | 1040 | set_to_cap_if_null(ops, key_free); |
| 1114 | set_to_cap_if_null(ops, key_permission); | 1041 | set_to_cap_if_null(ops, key_permission); |
| 1115 | set_to_cap_if_null(ops, key_getsecurity); | 1042 | set_to_cap_if_null(ops, key_getsecurity); |
| 1116 | set_to_cap_if_null(ops, key_session_to_parent); | ||
| 1117 | #endif /* CONFIG_KEYS */ | 1043 | #endif /* CONFIG_KEYS */ |
| 1118 | #ifdef CONFIG_AUDIT | 1044 | #ifdef CONFIG_AUDIT |
| 1119 | set_to_cap_if_null(ops, audit_rule_init); | 1045 | set_to_cap_if_null(ops, audit_rule_init); |
diff --git a/security/commoncap.c b/security/commoncap.c index 61669730da98..4e015996dd4d 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
| @@ -570,7 +570,7 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name, | |||
| 570 | } | 570 | } |
| 571 | 571 | ||
| 572 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 572 | if (!strncmp(name, XATTR_SECURITY_PREFIX, |
| 573 | sizeof(XATTR_SECURITY_PREFIX) - 1) && | 573 | sizeof(XATTR_SECURITY_PREFIX) - 1) && |
| 574 | !capable(CAP_SYS_ADMIN)) | 574 | !capable(CAP_SYS_ADMIN)) |
| 575 | return -EPERM; | 575 | return -EPERM; |
| 576 | return 0; | 576 | return 0; |
| @@ -596,7 +596,7 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name) | |||
| 596 | } | 596 | } |
| 597 | 597 | ||
| 598 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | 598 | if (!strncmp(name, XATTR_SECURITY_PREFIX, |
| 599 | sizeof(XATTR_SECURITY_PREFIX) - 1) && | 599 | sizeof(XATTR_SECURITY_PREFIX) - 1) && |
| 600 | !capable(CAP_SYS_ADMIN)) | 600 | !capable(CAP_SYS_ADMIN)) |
| 601 | return -EPERM; | 601 | return -EPERM; |
| 602 | return 0; | 602 | return 0; |
| @@ -931,7 +931,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) | |||
| 931 | * @addr: address attempting to be mapped | 931 | * @addr: address attempting to be mapped |
| 932 | * @addr_only: unused | 932 | * @addr_only: unused |
| 933 | * | 933 | * |
| 934 | * If the process is attempting to map memory below mmap_min_addr they need | 934 | * If the process is attempting to map memory below dac_mmap_min_addr they need |
| 935 | * CAP_SYS_RAWIO. The other parameters to this function are unused by the | 935 | * CAP_SYS_RAWIO. The other parameters to this function are unused by the |
| 936 | * capability security module. Returns 0 if this mapping should be allowed | 936 | * capability security module. Returns 0 if this mapping should be allowed |
| 937 | * -EPERM if not. | 937 | * -EPERM if not. |
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index f77c60423992..8d9c48f13774 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
| @@ -470,7 +470,7 @@ struct cgroup_subsys devices_subsys = { | |||
| 470 | .name = "devices", | 470 | .name = "devices", |
| 471 | .can_attach = devcgroup_can_attach, | 471 | .can_attach = devcgroup_can_attach, |
| 472 | .create = devcgroup_create, | 472 | .create = devcgroup_create, |
| 473 | .destroy = devcgroup_destroy, | 473 | .destroy = devcgroup_destroy, |
| 474 | .populate = devcgroup_populate, | 474 | .populate = devcgroup_populate, |
| 475 | .subsys_id = devices_subsys_id, | 475 | .subsys_id = devices_subsys_id, |
| 476 | }; | 476 | }; |
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 3d7846de8069..b6ecfd4d8d78 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
| @@ -2,15 +2,14 @@ | |||
| 2 | # | 2 | # |
| 3 | config IMA | 3 | config IMA |
| 4 | bool "Integrity Measurement Architecture(IMA)" | 4 | bool "Integrity Measurement Architecture(IMA)" |
| 5 | depends on ACPI | ||
| 6 | depends on SECURITY | 5 | depends on SECURITY |
| 7 | select SECURITYFS | 6 | select SECURITYFS |
| 8 | select CRYPTO | 7 | select CRYPTO |
| 9 | select CRYPTO_HMAC | 8 | select CRYPTO_HMAC |
| 10 | select CRYPTO_MD5 | 9 | select CRYPTO_MD5 |
| 11 | select CRYPTO_SHA1 | 10 | select CRYPTO_SHA1 |
| 12 | select TCG_TPM | 11 | select TCG_TPM if !S390 |
| 13 | select TCG_TIS | 12 | select TCG_TIS if TCG_TPM |
| 14 | help | 13 | help |
| 15 | The Trusted Computing Group(TCG) runtime Integrity | 14 | The Trusted Computing Group(TCG) runtime Integrity |
| 16 | Measurement Architecture(IMA) maintains a list of hash | 15 | Measurement Architecture(IMA) maintains a list of hash |
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 47fb65d1fcbd..16d100d3fc38 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -135,7 +135,7 @@ enum ima_hooks { FILE_CHECK = 1, FILE_MMAP, BPRM_CHECK }; | |||
| 135 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); | 135 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask); |
| 136 | void ima_init_policy(void); | 136 | void ima_init_policy(void); |
| 137 | void ima_update_policy(void); | 137 | void ima_update_policy(void); |
| 138 | int ima_parse_add_rule(char *); | 138 | ssize_t ima_parse_add_rule(char *); |
| 139 | void ima_delete_rules(void); | 139 | void ima_delete_rules(void); |
| 140 | 140 | ||
| 141 | /* LSM based policy rules require audit */ | 141 | /* LSM based policy rules require audit */ |
diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index 5af76340470c..c5c5a72c30be 100644 --- a/security/integrity/ima/ima_audit.c +++ b/security/integrity/ima/ima_audit.c | |||
| @@ -41,7 +41,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, | |||
| 41 | return; | 41 | return; |
| 42 | 42 | ||
| 43 | ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); | 43 | ab = audit_log_start(current->audit_context, GFP_KERNEL, audit_msgno); |
| 44 | audit_log_format(ab, "integrity: pid=%d uid=%u auid=%u ses=%u", | 44 | audit_log_format(ab, "pid=%d uid=%u auid=%u ses=%u", |
| 45 | current->pid, current_cred()->uid, | 45 | current->pid, current_cred()->uid, |
| 46 | audit_get_loginuid(current), | 46 | audit_get_loginuid(current), |
| 47 | audit_get_sessionid(current)); | 47 | audit_get_sessionid(current)); |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 952e51373f58..9b3ade7468b2 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
| @@ -27,7 +27,7 @@ static int init_desc(struct hash_desc *desc) | |||
| 27 | 27 | ||
| 28 | desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC); | 28 | desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC); |
| 29 | if (IS_ERR(desc->tfm)) { | 29 | if (IS_ERR(desc->tfm)) { |
| 30 | pr_info("failed to load %s transform: %ld\n", | 30 | pr_info("IMA: failed to load %s transform: %ld\n", |
| 31 | ima_hash, PTR_ERR(desc->tfm)); | 31 | ima_hash, PTR_ERR(desc->tfm)); |
| 32 | rc = PTR_ERR(desc->tfm); | 32 | rc = PTR_ERR(desc->tfm); |
| 33 | return rc; | 33 | return rc; |
| @@ -112,7 +112,7 @@ static void __init ima_pcrread(int idx, u8 *pcr) | |||
| 112 | return; | 112 | return; |
| 113 | 113 | ||
| 114 | if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) | 114 | if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) |
| 115 | pr_err("Error Communicating to TPM chip\n"); | 115 | pr_err("IMA: Error Communicating to TPM chip\n"); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | /* | 118 | /* |
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index 07cb9c338cc4..8fe736aabe71 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
| @@ -244,32 +244,34 @@ static const struct file_operations ima_ascii_measurements_ops = { | |||
| 244 | static ssize_t ima_write_policy(struct file *file, const char __user *buf, | 244 | static ssize_t ima_write_policy(struct file *file, const char __user *buf, |
| 245 | size_t datalen, loff_t *ppos) | 245 | size_t datalen, loff_t *ppos) |
| 246 | { | 246 | { |
| 247 | char *data; | 247 | char *data = NULL; |
| 248 | int rc; | 248 | ssize_t result; |
| 249 | 249 | ||
| 250 | if (datalen >= PAGE_SIZE) | 250 | if (datalen >= PAGE_SIZE) |
| 251 | return -ENOMEM; | 251 | datalen = PAGE_SIZE - 1; |
| 252 | if (*ppos != 0) { | 252 | |
| 253 | /* No partial writes. */ | 253 | /* No partial writes. */ |
| 254 | return -EINVAL; | 254 | result = -EINVAL; |
| 255 | } | 255 | if (*ppos != 0) |
| 256 | goto out; | ||
| 257 | |||
| 258 | result = -ENOMEM; | ||
| 256 | data = kmalloc(datalen + 1, GFP_KERNEL); | 259 | data = kmalloc(datalen + 1, GFP_KERNEL); |
| 257 | if (!data) | 260 | if (!data) |
| 258 | return -ENOMEM; | 261 | goto out; |
| 259 | 262 | ||
| 260 | if (copy_from_user(data, buf, datalen)) { | ||
| 261 | kfree(data); | ||
| 262 | return -EFAULT; | ||
| 263 | } | ||
| 264 | *(data + datalen) = '\0'; | 263 | *(data + datalen) = '\0'; |
| 265 | rc = ima_parse_add_rule(data); | ||
| 266 | if (rc < 0) { | ||
| 267 | datalen = -EINVAL; | ||
| 268 | valid_policy = 0; | ||
| 269 | } | ||
| 270 | 264 | ||
| 265 | result = -EFAULT; | ||
| 266 | if (copy_from_user(data, buf, datalen)) | ||
| 267 | goto out; | ||
| 268 | |||
| 269 | result = ima_parse_add_rule(data); | ||
| 270 | out: | ||
| 271 | if (result < 0) | ||
| 272 | valid_policy = 0; | ||
| 271 | kfree(data); | 273 | kfree(data); |
| 272 | return datalen; | 274 | return result; |
| 273 | } | 275 | } |
| 274 | 276 | ||
| 275 | static struct dentry *ima_dir; | 277 | static struct dentry *ima_dir; |
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c index 2c744d488014..7625b85c2274 100644 --- a/security/integrity/ima/ima_iint.c +++ b/security/integrity/ima/ima_iint.c | |||
| @@ -80,21 +80,21 @@ void iint_free(struct kref *kref) | |||
| 80 | iint->version = 0; | 80 | iint->version = 0; |
| 81 | iint->flags = 0UL; | 81 | iint->flags = 0UL; |
| 82 | if (iint->readcount != 0) { | 82 | if (iint->readcount != 0) { |
| 83 | printk(KERN_INFO "%s: readcount: %ld\n", __FUNCTION__, | 83 | printk(KERN_INFO "%s: readcount: %ld\n", __func__, |
| 84 | iint->readcount); | 84 | iint->readcount); |
| 85 | iint->readcount = 0; | 85 | iint->readcount = 0; |
| 86 | } | 86 | } |
| 87 | if (iint->writecount != 0) { | 87 | if (iint->writecount != 0) { |
| 88 | printk(KERN_INFO "%s: writecount: %ld\n", __FUNCTION__, | 88 | printk(KERN_INFO "%s: writecount: %ld\n", __func__, |
| 89 | iint->writecount); | 89 | iint->writecount); |
| 90 | iint->writecount = 0; | 90 | iint->writecount = 0; |
| 91 | } | 91 | } |
| 92 | if (iint->opencount != 0) { | 92 | if (iint->opencount != 0) { |
| 93 | printk(KERN_INFO "%s: opencount: %ld\n", __FUNCTION__, | 93 | printk(KERN_INFO "%s: opencount: %ld\n", __func__, |
| 94 | iint->opencount); | 94 | iint->opencount); |
| 95 | iint->opencount = 0; | 95 | iint->opencount = 0; |
| 96 | } | 96 | } |
| 97 | kref_set(&iint->refcount, 1); | 97 | kref_init(&iint->refcount); |
| 98 | kmem_cache_free(iint_cache, iint); | 98 | kmem_cache_free(iint_cache, iint); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| @@ -133,7 +133,7 @@ static void init_once(void *foo) | |||
| 133 | iint->readcount = 0; | 133 | iint->readcount = 0; |
| 134 | iint->writecount = 0; | 134 | iint->writecount = 0; |
| 135 | iint->opencount = 0; | 135 | iint->opencount = 0; |
| 136 | kref_set(&iint->refcount, 1); | 136 | kref_init(&iint->refcount); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | static int __init ima_iintcache_init(void) | 139 | static int __init ima_iintcache_init(void) |
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index b1bcb702a27c..17f1f060306f 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c | |||
| @@ -83,7 +83,7 @@ int __init ima_init(void) | |||
| 83 | ima_used_chip = 1; | 83 | ima_used_chip = 1; |
| 84 | 84 | ||
| 85 | if (!ima_used_chip) | 85 | if (!ima_used_chip) |
| 86 | pr_info("No TPM chip found, activating TPM-bypass!\n"); | 86 | pr_info("IMA: No TPM chip found, activating TPM-bypass!\n"); |
| 87 | 87 | ||
| 88 | ima_add_boot_aggregate(); /* boot aggregate must be first entry */ | 88 | ima_add_boot_aggregate(); /* boot aggregate must be first entry */ |
| 89 | ima_init_policy(); | 89 | ima_init_policy(); |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index b2c89d9de2a4..f93641382e9f 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -195,7 +195,7 @@ static void ima_dec_counts(struct ima_iint_cache *iint, struct inode *inode, | |||
| 195 | (iint->writecount < 0)) && | 195 | (iint->writecount < 0)) && |
| 196 | !ima_limit_imbalance(file)) { | 196 | !ima_limit_imbalance(file)) { |
| 197 | printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n", | 197 | printk(KERN_INFO "%s: open/free imbalance (r:%ld w:%ld o:%ld)\n", |
| 198 | __FUNCTION__, iint->readcount, iint->writecount, | 198 | __func__, iint->readcount, iint->writecount, |
| 199 | iint->opencount); | 199 | iint->opencount); |
| 200 | dump_stack(); | 200 | dump_stack(); |
| 201 | } | 201 | } |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 8643a93c5963..aef8c0a923ab 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
| @@ -246,6 +246,9 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, | |||
| 246 | { | 246 | { |
| 247 | int result; | 247 | int result; |
| 248 | 248 | ||
| 249 | if (entry->lsm[lsm_rule].rule) | ||
| 250 | return -EINVAL; | ||
| 251 | |||
| 249 | entry->lsm[lsm_rule].type = audit_type; | 252 | entry->lsm[lsm_rule].type = audit_type; |
| 250 | result = security_filter_rule_init(entry->lsm[lsm_rule].type, | 253 | result = security_filter_rule_init(entry->lsm[lsm_rule].type, |
| 251 | Audit_equal, args, | 254 | Audit_equal, args, |
| @@ -253,6 +256,13 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, | |||
| 253 | return result; | 256 | return result; |
| 254 | } | 257 | } |
| 255 | 258 | ||
| 259 | static void ima_log_string(struct audit_buffer *ab, char *key, char *value) | ||
| 260 | { | ||
| 261 | audit_log_format(ab, "%s=", key); | ||
| 262 | audit_log_untrustedstring(ab, value); | ||
| 263 | audit_log_format(ab, " "); | ||
| 264 | } | ||
| 265 | |||
| 256 | static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | 266 | static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) |
| 257 | { | 267 | { |
| 258 | struct audit_buffer *ab; | 268 | struct audit_buffer *ab; |
| @@ -261,28 +271,41 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 261 | 271 | ||
| 262 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); | 272 | ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_INTEGRITY_RULE); |
| 263 | 273 | ||
| 264 | entry->action = -1; | 274 | entry->uid = -1; |
| 265 | while ((p = strsep(&rule, " \n")) != NULL) { | 275 | entry->action = UNKNOWN; |
| 276 | while ((p = strsep(&rule, " \t")) != NULL) { | ||
| 266 | substring_t args[MAX_OPT_ARGS]; | 277 | substring_t args[MAX_OPT_ARGS]; |
| 267 | int token; | 278 | int token; |
| 268 | unsigned long lnum; | 279 | unsigned long lnum; |
| 269 | 280 | ||
| 270 | if (result < 0) | 281 | if (result < 0) |
| 271 | break; | 282 | break; |
| 272 | if (!*p) | 283 | if ((*p == '\0') || (*p == ' ') || (*p == '\t')) |
| 273 | continue; | 284 | continue; |
| 274 | token = match_token(p, policy_tokens, args); | 285 | token = match_token(p, policy_tokens, args); |
| 275 | switch (token) { | 286 | switch (token) { |
| 276 | case Opt_measure: | 287 | case Opt_measure: |
| 277 | audit_log_format(ab, "%s ", "measure"); | 288 | ima_log_string(ab, "action", "measure"); |
| 289 | |||
| 290 | if (entry->action != UNKNOWN) | ||
| 291 | result = -EINVAL; | ||
| 292 | |||
| 278 | entry->action = MEASURE; | 293 | entry->action = MEASURE; |
| 279 | break; | 294 | break; |
| 280 | case Opt_dont_measure: | 295 | case Opt_dont_measure: |
| 281 | audit_log_format(ab, "%s ", "dont_measure"); | 296 | ima_log_string(ab, "action", "dont_measure"); |
| 297 | |||
| 298 | if (entry->action != UNKNOWN) | ||
| 299 | result = -EINVAL; | ||
| 300 | |||
| 282 | entry->action = DONT_MEASURE; | 301 | entry->action = DONT_MEASURE; |
| 283 | break; | 302 | break; |
| 284 | case Opt_func: | 303 | case Opt_func: |
| 285 | audit_log_format(ab, "func=%s ", args[0].from); | 304 | ima_log_string(ab, "func", args[0].from); |
| 305 | |||
| 306 | if (entry->func) | ||
| 307 | result = -EINVAL; | ||
| 308 | |||
| 286 | if (strcmp(args[0].from, "FILE_CHECK") == 0) | 309 | if (strcmp(args[0].from, "FILE_CHECK") == 0) |
| 287 | entry->func = FILE_CHECK; | 310 | entry->func = FILE_CHECK; |
| 288 | /* PATH_CHECK is for backwards compat */ | 311 | /* PATH_CHECK is for backwards compat */ |
| @@ -298,7 +321,11 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 298 | entry->flags |= IMA_FUNC; | 321 | entry->flags |= IMA_FUNC; |
| 299 | break; | 322 | break; |
| 300 | case Opt_mask: | 323 | case Opt_mask: |
| 301 | audit_log_format(ab, "mask=%s ", args[0].from); | 324 | ima_log_string(ab, "mask", args[0].from); |
| 325 | |||
| 326 | if (entry->mask) | ||
| 327 | result = -EINVAL; | ||
| 328 | |||
| 302 | if ((strcmp(args[0].from, "MAY_EXEC")) == 0) | 329 | if ((strcmp(args[0].from, "MAY_EXEC")) == 0) |
| 303 | entry->mask = MAY_EXEC; | 330 | entry->mask = MAY_EXEC; |
| 304 | else if (strcmp(args[0].from, "MAY_WRITE") == 0) | 331 | else if (strcmp(args[0].from, "MAY_WRITE") == 0) |
| @@ -313,14 +340,26 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 313 | entry->flags |= IMA_MASK; | 340 | entry->flags |= IMA_MASK; |
| 314 | break; | 341 | break; |
| 315 | case Opt_fsmagic: | 342 | case Opt_fsmagic: |
| 316 | audit_log_format(ab, "fsmagic=%s ", args[0].from); | 343 | ima_log_string(ab, "fsmagic", args[0].from); |
| 344 | |||
| 345 | if (entry->fsmagic) { | ||
| 346 | result = -EINVAL; | ||
| 347 | break; | ||
| 348 | } | ||
| 349 | |||
| 317 | result = strict_strtoul(args[0].from, 16, | 350 | result = strict_strtoul(args[0].from, 16, |
| 318 | &entry->fsmagic); | 351 | &entry->fsmagic); |
| 319 | if (!result) | 352 | if (!result) |
| 320 | entry->flags |= IMA_FSMAGIC; | 353 | entry->flags |= IMA_FSMAGIC; |
| 321 | break; | 354 | break; |
| 322 | case Opt_uid: | 355 | case Opt_uid: |
| 323 | audit_log_format(ab, "uid=%s ", args[0].from); | 356 | ima_log_string(ab, "uid", args[0].from); |
| 357 | |||
| 358 | if (entry->uid != -1) { | ||
| 359 | result = -EINVAL; | ||
| 360 | break; | ||
| 361 | } | ||
| 362 | |||
| 324 | result = strict_strtoul(args[0].from, 10, &lnum); | 363 | result = strict_strtoul(args[0].from, 10, &lnum); |
| 325 | if (!result) { | 364 | if (!result) { |
| 326 | entry->uid = (uid_t) lnum; | 365 | entry->uid = (uid_t) lnum; |
| @@ -331,50 +370,51 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 331 | } | 370 | } |
| 332 | break; | 371 | break; |
| 333 | case Opt_obj_user: | 372 | case Opt_obj_user: |
| 334 | audit_log_format(ab, "obj_user=%s ", args[0].from); | 373 | ima_log_string(ab, "obj_user", args[0].from); |
| 335 | result = ima_lsm_rule_init(entry, args[0].from, | 374 | result = ima_lsm_rule_init(entry, args[0].from, |
| 336 | LSM_OBJ_USER, | 375 | LSM_OBJ_USER, |
| 337 | AUDIT_OBJ_USER); | 376 | AUDIT_OBJ_USER); |
| 338 | break; | 377 | break; |
| 339 | case Opt_obj_role: | 378 | case Opt_obj_role: |
| 340 | audit_log_format(ab, "obj_role=%s ", args[0].from); | 379 | ima_log_string(ab, "obj_role", args[0].from); |
| 341 | result = ima_lsm_rule_init(entry, args[0].from, | 380 | result = ima_lsm_rule_init(entry, args[0].from, |
| 342 | LSM_OBJ_ROLE, | 381 | LSM_OBJ_ROLE, |
| 343 | AUDIT_OBJ_ROLE); | 382 | AUDIT_OBJ_ROLE); |
| 344 | break; | 383 | break; |
| 345 | case Opt_obj_type: | 384 | case Opt_obj_type: |
| 346 | audit_log_format(ab, "obj_type=%s ", args[0].from); | 385 | ima_log_string(ab, "obj_type", args[0].from); |
| 347 | result = ima_lsm_rule_init(entry, args[0].from, | 386 | result = ima_lsm_rule_init(entry, args[0].from, |
| 348 | LSM_OBJ_TYPE, | 387 | LSM_OBJ_TYPE, |
| 349 | AUDIT_OBJ_TYPE); | 388 | AUDIT_OBJ_TYPE); |
| 350 | break; | 389 | break; |
| 351 | case Opt_subj_user: | 390 | case Opt_subj_user: |
| 352 | audit_log_format(ab, "subj_user=%s ", args[0].from); | 391 | ima_log_string(ab, "subj_user", args[0].from); |
| 353 | result = ima_lsm_rule_init(entry, args[0].from, | 392 | result = ima_lsm_rule_init(entry, args[0].from, |
| 354 | LSM_SUBJ_USER, | 393 | LSM_SUBJ_USER, |
| 355 | AUDIT_SUBJ_USER); | 394 | AUDIT_SUBJ_USER); |
| 356 | break; | 395 | break; |
| 357 | case Opt_subj_role: | 396 | case Opt_subj_role: |
| 358 | audit_log_format(ab, "subj_role=%s ", args[0].from); | 397 | ima_log_string(ab, "subj_role", args[0].from); |
| 359 | result = ima_lsm_rule_init(entry, args[0].from, | 398 | result = ima_lsm_rule_init(entry, args[0].from, |
| 360 | LSM_SUBJ_ROLE, | 399 | LSM_SUBJ_ROLE, |
| 361 | AUDIT_SUBJ_ROLE); | 400 | AUDIT_SUBJ_ROLE); |
| 362 | break; | 401 | break; |
| 363 | case Opt_subj_type: | 402 | case Opt_subj_type: |
| 364 | audit_log_format(ab, "subj_type=%s ", args[0].from); | 403 | ima_log_string(ab, "subj_type", args[0].from); |
| 365 | result = ima_lsm_rule_init(entry, args[0].from, | 404 | result = ima_lsm_rule_init(entry, args[0].from, |
| 366 | LSM_SUBJ_TYPE, | 405 | LSM_SUBJ_TYPE, |
| 367 | AUDIT_SUBJ_TYPE); | 406 | AUDIT_SUBJ_TYPE); |
| 368 | break; | 407 | break; |
| 369 | case Opt_err: | 408 | case Opt_err: |
| 370 | audit_log_format(ab, "UNKNOWN=%s ", p); | 409 | ima_log_string(ab, "UNKNOWN", p); |
| 410 | result = -EINVAL; | ||
| 371 | break; | 411 | break; |
| 372 | } | 412 | } |
| 373 | } | 413 | } |
| 374 | if (entry->action == UNKNOWN) | 414 | if (!result && (entry->action == UNKNOWN)) |
| 375 | result = -EINVAL; | 415 | result = -EINVAL; |
| 376 | 416 | ||
| 377 | audit_log_format(ab, "res=%d", !result ? 0 : 1); | 417 | audit_log_format(ab, "res=%d", !!result); |
| 378 | audit_log_end(ab); | 418 | audit_log_end(ab); |
| 379 | return result; | 419 | return result; |
| 380 | } | 420 | } |
| @@ -384,13 +424,14 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) | |||
| 384 | * @rule - ima measurement policy rule | 424 | * @rule - ima measurement policy rule |
| 385 | * | 425 | * |
| 386 | * Uses a mutex to protect the policy list from multiple concurrent writers. | 426 | * Uses a mutex to protect the policy list from multiple concurrent writers. |
| 387 | * Returns 0 on success, an error code on failure. | 427 | * Returns the length of the rule parsed, an error code on failure |
| 388 | */ | 428 | */ |
| 389 | int ima_parse_add_rule(char *rule) | 429 | ssize_t ima_parse_add_rule(char *rule) |
| 390 | { | 430 | { |
| 391 | const char *op = "update_policy"; | 431 | const char *op = "update_policy"; |
| 432 | char *p; | ||
| 392 | struct ima_measure_rule_entry *entry; | 433 | struct ima_measure_rule_entry *entry; |
| 393 | int result = 0; | 434 | ssize_t result, len; |
| 394 | int audit_info = 0; | 435 | int audit_info = 0; |
| 395 | 436 | ||
| 396 | /* Prevent installed policy from changing */ | 437 | /* Prevent installed policy from changing */ |
| @@ -410,18 +451,28 @@ int ima_parse_add_rule(char *rule) | |||
| 410 | 451 | ||
| 411 | INIT_LIST_HEAD(&entry->list); | 452 | INIT_LIST_HEAD(&entry->list); |
| 412 | 453 | ||
| 413 | result = ima_parse_rule(rule, entry); | 454 | p = strsep(&rule, "\n"); |
| 414 | if (!result) { | 455 | len = strlen(p) + 1; |
| 415 | mutex_lock(&ima_measure_mutex); | 456 | |
| 416 | list_add_tail(&entry->list, &measure_policy_rules); | 457 | if (*p == '#') { |
| 417 | mutex_unlock(&ima_measure_mutex); | 458 | kfree(entry); |
| 418 | } else { | 459 | return len; |
| 460 | } | ||
| 461 | |||
| 462 | result = ima_parse_rule(p, entry); | ||
| 463 | if (result) { | ||
| 419 | kfree(entry); | 464 | kfree(entry); |
| 420 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | 465 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
| 421 | NULL, op, "invalid policy", result, | 466 | NULL, op, "invalid policy", result, |
| 422 | audit_info); | 467 | audit_info); |
| 468 | return result; | ||
| 423 | } | 469 | } |
| 424 | return result; | 470 | |
| 471 | mutex_lock(&ima_measure_mutex); | ||
| 472 | list_add_tail(&entry->list, &measure_policy_rules); | ||
| 473 | mutex_unlock(&ima_measure_mutex); | ||
| 474 | |||
| 475 | return len; | ||
| 425 | } | 476 | } |
| 426 | 477 | ||
| 427 | /* ima_delete_rules called to cleanup invalid policy */ | 478 | /* ima_delete_rules called to cleanup invalid policy */ |
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 46ba62b1adf5..8e28f04a5e2e 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c | |||
| @@ -71,7 +71,7 @@ static int ima_add_digest_entry(struct ima_template_entry *entry) | |||
| 71 | 71 | ||
| 72 | qe = kmalloc(sizeof(*qe), GFP_KERNEL); | 72 | qe = kmalloc(sizeof(*qe), GFP_KERNEL); |
| 73 | if (qe == NULL) { | 73 | if (qe == NULL) { |
| 74 | pr_err("OUT OF MEMORY ERROR creating queue entry.\n"); | 74 | pr_err("IMA: OUT OF MEMORY ERROR creating queue entry.\n"); |
| 75 | return -ENOMEM; | 75 | return -ENOMEM; |
| 76 | } | 76 | } |
| 77 | qe->entry = entry; | 77 | qe->entry = entry; |
| @@ -94,7 +94,7 @@ static int ima_pcr_extend(const u8 *hash) | |||
| 94 | 94 | ||
| 95 | result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); | 95 | result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); |
| 96 | if (result != 0) | 96 | if (result != 0) |
| 97 | pr_err("Error Communicating to TPM chip\n"); | 97 | pr_err("IMA: Error Communicating to TPM chip\n"); |
| 98 | return result; | 98 | return result; |
| 99 | } | 99 | } |
| 100 | 100 | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 24ba0307b7ad..38783dcf6c61 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -87,7 +87,16 @@ extern wait_queue_head_t request_key_conswq; | |||
| 87 | extern struct key_type *key_type_lookup(const char *type); | 87 | extern struct key_type *key_type_lookup(const char *type); |
| 88 | extern void key_type_put(struct key_type *ktype); | 88 | extern void key_type_put(struct key_type *ktype); |
| 89 | 89 | ||
| 90 | extern int __key_link(struct key *keyring, struct key *key); | 90 | extern int __key_link_begin(struct key *keyring, |
| 91 | const struct key_type *type, | ||
| 92 | const char *description, | ||
| 93 | struct keyring_list **_prealloc); | ||
| 94 | extern int __key_link_check_live_key(struct key *keyring, struct key *key); | ||
| 95 | extern void __key_link(struct key *keyring, struct key *key, | ||
| 96 | struct keyring_list **_prealloc); | ||
| 97 | extern void __key_link_end(struct key *keyring, | ||
| 98 | struct key_type *type, | ||
| 99 | struct keyring_list *prealloc); | ||
| 91 | 100 | ||
| 92 | extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, | 101 | extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, |
| 93 | const struct key_type *type, | 102 | const struct key_type *type, |
| @@ -115,6 +124,7 @@ extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); | |||
| 115 | extern int install_user_keyrings(void); | 124 | extern int install_user_keyrings(void); |
| 116 | extern int install_thread_keyring_to_cred(struct cred *); | 125 | extern int install_thread_keyring_to_cred(struct cred *); |
| 117 | extern int install_process_keyring_to_cred(struct cred *); | 126 | extern int install_process_keyring_to_cred(struct cred *); |
| 127 | extern int install_session_keyring_to_cred(struct cred *, struct key *); | ||
| 118 | 128 | ||
| 119 | extern struct key *request_key_and_link(struct key_type *type, | 129 | extern struct key *request_key_and_link(struct key_type *type, |
| 120 | const char *description, | 130 | const char *description, |
diff --git a/security/keys/key.c b/security/keys/key.c index e50d264c9ad1..c1eac8084ade 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -355,7 +355,7 @@ EXPORT_SYMBOL(key_alloc); | |||
| 355 | */ | 355 | */ |
| 356 | int key_payload_reserve(struct key *key, size_t datalen) | 356 | int key_payload_reserve(struct key *key, size_t datalen) |
| 357 | { | 357 | { |
| 358 | int delta = (int) datalen - key->datalen; | 358 | int delta = (int)datalen - key->datalen; |
| 359 | int ret = 0; | 359 | int ret = 0; |
| 360 | 360 | ||
| 361 | key_check(key); | 361 | key_check(key); |
| @@ -398,7 +398,8 @@ static int __key_instantiate_and_link(struct key *key, | |||
| 398 | const void *data, | 398 | const void *data, |
| 399 | size_t datalen, | 399 | size_t datalen, |
| 400 | struct key *keyring, | 400 | struct key *keyring, |
| 401 | struct key *authkey) | 401 | struct key *authkey, |
| 402 | struct keyring_list **_prealloc) | ||
| 402 | { | 403 | { |
| 403 | int ret, awaken; | 404 | int ret, awaken; |
| 404 | 405 | ||
| @@ -425,7 +426,7 @@ static int __key_instantiate_and_link(struct key *key, | |||
| 425 | 426 | ||
| 426 | /* and link it into the destination keyring */ | 427 | /* and link it into the destination keyring */ |
| 427 | if (keyring) | 428 | if (keyring) |
| 428 | ret = __key_link(keyring, key); | 429 | __key_link(keyring, key, _prealloc); |
| 429 | 430 | ||
| 430 | /* disable the authorisation key */ | 431 | /* disable the authorisation key */ |
| 431 | if (authkey) | 432 | if (authkey) |
| @@ -453,15 +454,21 @@ int key_instantiate_and_link(struct key *key, | |||
| 453 | struct key *keyring, | 454 | struct key *keyring, |
| 454 | struct key *authkey) | 455 | struct key *authkey) |
| 455 | { | 456 | { |
| 457 | struct keyring_list *prealloc; | ||
| 456 | int ret; | 458 | int ret; |
| 457 | 459 | ||
| 458 | if (keyring) | 460 | if (keyring) { |
| 459 | down_write(&keyring->sem); | 461 | ret = __key_link_begin(keyring, key->type, key->description, |
| 462 | &prealloc); | ||
| 463 | if (ret < 0) | ||
| 464 | return ret; | ||
| 465 | } | ||
| 460 | 466 | ||
| 461 | ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey); | 467 | ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey, |
| 468 | &prealloc); | ||
| 462 | 469 | ||
| 463 | if (keyring) | 470 | if (keyring) |
| 464 | up_write(&keyring->sem); | 471 | __key_link_end(keyring, key->type, prealloc); |
| 465 | 472 | ||
| 466 | return ret; | 473 | return ret; |
| 467 | 474 | ||
| @@ -478,8 +485,9 @@ int key_negate_and_link(struct key *key, | |||
| 478 | struct key *keyring, | 485 | struct key *keyring, |
| 479 | struct key *authkey) | 486 | struct key *authkey) |
| 480 | { | 487 | { |
| 488 | struct keyring_list *prealloc; | ||
| 481 | struct timespec now; | 489 | struct timespec now; |
| 482 | int ret, awaken; | 490 | int ret, awaken, link_ret = 0; |
| 483 | 491 | ||
| 484 | key_check(key); | 492 | key_check(key); |
| 485 | key_check(keyring); | 493 | key_check(keyring); |
| @@ -488,7 +496,8 @@ int key_negate_and_link(struct key *key, | |||
| 488 | ret = -EBUSY; | 496 | ret = -EBUSY; |
| 489 | 497 | ||
| 490 | if (keyring) | 498 | if (keyring) |
| 491 | down_write(&keyring->sem); | 499 | link_ret = __key_link_begin(keyring, key->type, |
| 500 | key->description, &prealloc); | ||
| 492 | 501 | ||
| 493 | mutex_lock(&key_construction_mutex); | 502 | mutex_lock(&key_construction_mutex); |
| 494 | 503 | ||
| @@ -508,8 +517,8 @@ int key_negate_and_link(struct key *key, | |||
| 508 | ret = 0; | 517 | ret = 0; |
| 509 | 518 | ||
| 510 | /* and link it into the destination keyring */ | 519 | /* and link it into the destination keyring */ |
| 511 | if (keyring) | 520 | if (keyring && link_ret == 0) |
| 512 | ret = __key_link(keyring, key); | 521 | __key_link(keyring, key, &prealloc); |
| 513 | 522 | ||
| 514 | /* disable the authorisation key */ | 523 | /* disable the authorisation key */ |
| 515 | if (authkey) | 524 | if (authkey) |
| @@ -519,13 +528,13 @@ int key_negate_and_link(struct key *key, | |||
| 519 | mutex_unlock(&key_construction_mutex); | 528 | mutex_unlock(&key_construction_mutex); |
| 520 | 529 | ||
| 521 | if (keyring) | 530 | if (keyring) |
| 522 | up_write(&keyring->sem); | 531 | __key_link_end(keyring, key->type, prealloc); |
| 523 | 532 | ||
| 524 | /* wake up anyone waiting for a key to be constructed */ | 533 | /* wake up anyone waiting for a key to be constructed */ |
| 525 | if (awaken) | 534 | if (awaken) |
| 526 | wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); | 535 | wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT); |
| 527 | 536 | ||
| 528 | return ret; | 537 | return ret == 0 ? link_ret : ret; |
| 529 | 538 | ||
| 530 | } /* end key_negate_and_link() */ | 539 | } /* end key_negate_and_link() */ |
| 531 | 540 | ||
| @@ -749,6 +758,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 749 | key_perm_t perm, | 758 | key_perm_t perm, |
| 750 | unsigned long flags) | 759 | unsigned long flags) |
| 751 | { | 760 | { |
| 761 | struct keyring_list *prealloc; | ||
| 752 | const struct cred *cred = current_cred(); | 762 | const struct cred *cred = current_cred(); |
| 753 | struct key_type *ktype; | 763 | struct key_type *ktype; |
| 754 | struct key *keyring, *key = NULL; | 764 | struct key *keyring, *key = NULL; |
| @@ -775,7 +785,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 775 | if (keyring->type != &key_type_keyring) | 785 | if (keyring->type != &key_type_keyring) |
| 776 | goto error_2; | 786 | goto error_2; |
| 777 | 787 | ||
| 778 | down_write(&keyring->sem); | 788 | ret = __key_link_begin(keyring, ktype, description, &prealloc); |
| 789 | if (ret < 0) | ||
| 790 | goto error_2; | ||
| 779 | 791 | ||
| 780 | /* if we're going to allocate a new key, we're going to have | 792 | /* if we're going to allocate a new key, we're going to have |
| 781 | * to modify the keyring */ | 793 | * to modify the keyring */ |
| @@ -817,7 +829,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 817 | } | 829 | } |
| 818 | 830 | ||
| 819 | /* instantiate it and link it into the target keyring */ | 831 | /* instantiate it and link it into the target keyring */ |
| 820 | ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL); | 832 | ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL, |
| 833 | &prealloc); | ||
| 821 | if (ret < 0) { | 834 | if (ret < 0) { |
| 822 | key_put(key); | 835 | key_put(key); |
| 823 | key_ref = ERR_PTR(ret); | 836 | key_ref = ERR_PTR(ret); |
| @@ -827,7 +840,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 827 | key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); | 840 | key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); |
| 828 | 841 | ||
| 829 | error_3: | 842 | error_3: |
| 830 | up_write(&keyring->sem); | 843 | __key_link_end(keyring, ktype, prealloc); |
| 831 | error_2: | 844 | error_2: |
| 832 | key_type_put(ktype); | 845 | key_type_put(ktype); |
| 833 | error: | 846 | error: |
| @@ -837,7 +850,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 837 | /* we found a matching key, so we're going to try to update it | 850 | /* we found a matching key, so we're going to try to update it |
| 838 | * - we can drop the locks first as we have the key pinned | 851 | * - we can drop the locks first as we have the key pinned |
| 839 | */ | 852 | */ |
| 840 | up_write(&keyring->sem); | 853 | __key_link_end(keyring, ktype, prealloc); |
| 841 | key_type_put(ktype); | 854 | key_type_put(ktype); |
| 842 | 855 | ||
| 843 | key_ref = __key_update(key_ref, payload, plen); | 856 | key_ref = __key_update(key_ref, payload, plen); |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index e9c2e7c584d9..13074b454743 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -212,15 +212,15 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
| 212 | ret = key->serial; | 212 | ret = key->serial; |
| 213 | 213 | ||
| 214 | key_put(key); | 214 | key_put(key); |
| 215 | error5: | 215 | error5: |
| 216 | key_type_put(ktype); | 216 | key_type_put(ktype); |
| 217 | error4: | 217 | error4: |
| 218 | key_ref_put(dest_ref); | 218 | key_ref_put(dest_ref); |
| 219 | error3: | 219 | error3: |
| 220 | kfree(callout_info); | 220 | kfree(callout_info); |
| 221 | error2: | 221 | error2: |
| 222 | kfree(description); | 222 | kfree(description); |
| 223 | error: | 223 | error: |
| 224 | return ret; | 224 | return ret; |
| 225 | 225 | ||
| 226 | } /* end sys_request_key() */ | 226 | } /* end sys_request_key() */ |
| @@ -246,7 +246,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create) | |||
| 246 | 246 | ||
| 247 | ret = key_ref_to_ptr(key_ref)->serial; | 247 | ret = key_ref_to_ptr(key_ref)->serial; |
| 248 | key_ref_put(key_ref); | 248 | key_ref_put(key_ref); |
| 249 | error: | 249 | error: |
| 250 | return ret; | 250 | return ret; |
| 251 | 251 | ||
| 252 | } /* end keyctl_get_keyring_ID() */ | 252 | } /* end keyctl_get_keyring_ID() */ |
| @@ -275,7 +275,7 @@ long keyctl_join_session_keyring(const char __user *_name) | |||
| 275 | ret = join_session_keyring(name); | 275 | ret = join_session_keyring(name); |
| 276 | kfree(name); | 276 | kfree(name); |
| 277 | 277 | ||
| 278 | error: | 278 | error: |
| 279 | return ret; | 279 | return ret; |
| 280 | 280 | ||
| 281 | } /* end keyctl_join_session_keyring() */ | 281 | } /* end keyctl_join_session_keyring() */ |
| @@ -322,9 +322,9 @@ long keyctl_update_key(key_serial_t id, | |||
| 322 | ret = key_update(key_ref, payload, plen); | 322 | ret = key_update(key_ref, payload, plen); |
| 323 | 323 | ||
| 324 | key_ref_put(key_ref); | 324 | key_ref_put(key_ref); |
| 325 | error2: | 325 | error2: |
| 326 | kfree(payload); | 326 | kfree(payload); |
| 327 | error: | 327 | error: |
| 328 | return ret; | 328 | return ret; |
| 329 | 329 | ||
| 330 | } /* end keyctl_update_key() */ | 330 | } /* end keyctl_update_key() */ |
| @@ -356,7 +356,7 @@ long keyctl_revoke_key(key_serial_t id) | |||
| 356 | ret = 0; | 356 | ret = 0; |
| 357 | 357 | ||
| 358 | key_ref_put(key_ref); | 358 | key_ref_put(key_ref); |
| 359 | error: | 359 | error: |
| 360 | return ret; | 360 | return ret; |
| 361 | 361 | ||
| 362 | } /* end keyctl_revoke_key() */ | 362 | } /* end keyctl_revoke_key() */ |
| @@ -381,7 +381,7 @@ long keyctl_keyring_clear(key_serial_t ringid) | |||
| 381 | ret = keyring_clear(key_ref_to_ptr(keyring_ref)); | 381 | ret = keyring_clear(key_ref_to_ptr(keyring_ref)); |
| 382 | 382 | ||
| 383 | key_ref_put(keyring_ref); | 383 | key_ref_put(keyring_ref); |
| 384 | error: | 384 | error: |
| 385 | return ret; | 385 | return ret; |
| 386 | 386 | ||
| 387 | } /* end keyctl_keyring_clear() */ | 387 | } /* end keyctl_keyring_clear() */ |
| @@ -413,9 +413,9 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) | |||
| 413 | ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); | 413 | ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); |
| 414 | 414 | ||
| 415 | key_ref_put(key_ref); | 415 | key_ref_put(key_ref); |
| 416 | error2: | 416 | error2: |
| 417 | key_ref_put(keyring_ref); | 417 | key_ref_put(keyring_ref); |
| 418 | error: | 418 | error: |
| 419 | return ret; | 419 | return ret; |
| 420 | 420 | ||
| 421 | } /* end keyctl_keyring_link() */ | 421 | } /* end keyctl_keyring_link() */ |
| @@ -447,9 +447,9 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) | |||
| 447 | ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); | 447 | ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); |
| 448 | 448 | ||
| 449 | key_ref_put(key_ref); | 449 | key_ref_put(key_ref); |
| 450 | error2: | 450 | error2: |
| 451 | key_ref_put(keyring_ref); | 451 | key_ref_put(keyring_ref); |
| 452 | error: | 452 | error: |
| 453 | return ret; | 453 | return ret; |
| 454 | 454 | ||
| 455 | } /* end keyctl_keyring_unlink() */ | 455 | } /* end keyctl_keyring_unlink() */ |
| @@ -529,9 +529,9 @@ okay: | |||
| 529 | } | 529 | } |
| 530 | 530 | ||
| 531 | kfree(tmpbuf); | 531 | kfree(tmpbuf); |
| 532 | error2: | 532 | error2: |
| 533 | key_ref_put(key_ref); | 533 | key_ref_put(key_ref); |
| 534 | error: | 534 | error: |
| 535 | return ret; | 535 | return ret; |
| 536 | 536 | ||
| 537 | } /* end keyctl_describe_key() */ | 537 | } /* end keyctl_describe_key() */ |
| @@ -616,17 +616,17 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
| 616 | 616 | ||
| 617 | ret = key_ref_to_ptr(key_ref)->serial; | 617 | ret = key_ref_to_ptr(key_ref)->serial; |
| 618 | 618 | ||
| 619 | error6: | 619 | error6: |
| 620 | key_ref_put(key_ref); | 620 | key_ref_put(key_ref); |
| 621 | error5: | 621 | error5: |
| 622 | key_type_put(ktype); | 622 | key_type_put(ktype); |
| 623 | error4: | 623 | error4: |
| 624 | key_ref_put(dest_ref); | 624 | key_ref_put(dest_ref); |
| 625 | error3: | 625 | error3: |
| 626 | key_ref_put(keyring_ref); | 626 | key_ref_put(keyring_ref); |
| 627 | error2: | 627 | error2: |
| 628 | kfree(description); | 628 | kfree(description); |
| 629 | error: | 629 | error: |
| 630 | return ret; | 630 | return ret; |
| 631 | 631 | ||
| 632 | } /* end keyctl_keyring_search() */ | 632 | } /* end keyctl_keyring_search() */ |
| @@ -673,7 +673,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |||
| 673 | } | 673 | } |
| 674 | 674 | ||
| 675 | /* the key is probably readable - now try to read it */ | 675 | /* the key is probably readable - now try to read it */ |
| 676 | can_read_key: | 676 | can_read_key: |
| 677 | ret = key_validate(key); | 677 | ret = key_validate(key); |
| 678 | if (ret == 0) { | 678 | if (ret == 0) { |
| 679 | ret = -EOPNOTSUPP; | 679 | ret = -EOPNOTSUPP; |
| @@ -686,9 +686,9 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |||
| 686 | } | 686 | } |
| 687 | } | 687 | } |
| 688 | 688 | ||
| 689 | error2: | 689 | error2: |
| 690 | key_put(key); | 690 | key_put(key); |
| 691 | error: | 691 | error: |
| 692 | return ret; | 692 | return ret; |
| 693 | 693 | ||
| 694 | } /* end keyctl_read_key() */ | 694 | } /* end keyctl_read_key() */ |
| @@ -1269,7 +1269,7 @@ long keyctl_session_to_parent(void) | |||
| 1269 | goto not_permitted; | 1269 | goto not_permitted; |
| 1270 | 1270 | ||
| 1271 | /* the parent must be single threaded */ | 1271 | /* the parent must be single threaded */ |
| 1272 | if (atomic_read(&parent->signal->count) != 1) | 1272 | if (!thread_group_empty(parent)) |
| 1273 | goto not_permitted; | 1273 | goto not_permitted; |
| 1274 | 1274 | ||
| 1275 | /* the parent and the child must have different session keyrings or | 1275 | /* the parent and the child must have different session keyrings or |
| @@ -1282,26 +1282,19 @@ long keyctl_session_to_parent(void) | |||
| 1282 | 1282 | ||
| 1283 | /* the parent must have the same effective ownership and mustn't be | 1283 | /* the parent must have the same effective ownership and mustn't be |
| 1284 | * SUID/SGID */ | 1284 | * SUID/SGID */ |
| 1285 | if (pcred-> uid != mycred->euid || | 1285 | if (pcred->uid != mycred->euid || |
| 1286 | pcred->euid != mycred->euid || | 1286 | pcred->euid != mycred->euid || |
| 1287 | pcred->suid != mycred->euid || | 1287 | pcred->suid != mycred->euid || |
| 1288 | pcred-> gid != mycred->egid || | 1288 | pcred->gid != mycred->egid || |
| 1289 | pcred->egid != mycred->egid || | 1289 | pcred->egid != mycred->egid || |
| 1290 | pcred->sgid != mycred->egid) | 1290 | pcred->sgid != mycred->egid) |
| 1291 | goto not_permitted; | 1291 | goto not_permitted; |
| 1292 | 1292 | ||
| 1293 | /* the keyrings must have the same UID */ | 1293 | /* the keyrings must have the same UID */ |
| 1294 | if (pcred ->tgcred->session_keyring->uid != mycred->euid || | 1294 | if (pcred->tgcred->session_keyring->uid != mycred->euid || |
| 1295 | mycred->tgcred->session_keyring->uid != mycred->euid) | 1295 | mycred->tgcred->session_keyring->uid != mycred->euid) |
| 1296 | goto not_permitted; | 1296 | goto not_permitted; |
| 1297 | 1297 | ||
| 1298 | /* the LSM must permit the replacement of the parent's keyring with the | ||
| 1299 | * keyring from this process */ | ||
| 1300 | ret = security_key_session_to_parent(mycred, pcred, | ||
| 1301 | key_ref_to_ptr(keyring_r)); | ||
| 1302 | if (ret < 0) | ||
| 1303 | goto not_permitted; | ||
| 1304 | |||
| 1305 | /* if there's an already pending keyring replacement, then we replace | 1298 | /* if there's an already pending keyring replacement, then we replace |
| 1306 | * that */ | 1299 | * that */ |
| 1307 | oldcred = parent->replacement_session_keyring; | 1300 | oldcred = parent->replacement_session_keyring; |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 1e4b0037935c..d37f713e73ce 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | #include <linux/seq_file.h> | 17 | #include <linux/seq_file.h> |
| 18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
| 19 | #include <keys/keyring-type.h> | 19 | #include <keys/keyring-type.h> |
| 20 | #include <asm/uaccess.h> | 20 | #include <linux/uaccess.h> |
| 21 | #include "internal.h" | 21 | #include "internal.h" |
| 22 | 22 | ||
| 23 | #define rcu_dereference_locked_keyring(keyring) \ | 23 | #define rcu_dereference_locked_keyring(keyring) \ |
| @@ -44,7 +44,7 @@ static inline unsigned keyring_hash(const char *desc) | |||
| 44 | unsigned bucket = 0; | 44 | unsigned bucket = 0; |
| 45 | 45 | ||
| 46 | for (; *desc; desc++) | 46 | for (; *desc; desc++) |
| 47 | bucket += (unsigned char) *desc; | 47 | bucket += (unsigned char)*desc; |
| 48 | 48 | ||
| 49 | return bucket & (KEYRING_NAME_HASH_SIZE - 1); | 49 | return bucket & (KEYRING_NAME_HASH_SIZE - 1); |
| 50 | } | 50 | } |
| @@ -175,12 +175,10 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m) | |||
| 175 | { | 175 | { |
| 176 | struct keyring_list *klist; | 176 | struct keyring_list *klist; |
| 177 | 177 | ||
| 178 | if (keyring->description) { | 178 | if (keyring->description) |
| 179 | seq_puts(m, keyring->description); | 179 | seq_puts(m, keyring->description); |
| 180 | } | 180 | else |
| 181 | else { | ||
| 182 | seq_puts(m, "[anon]"); | 181 | seq_puts(m, "[anon]"); |
| 183 | } | ||
| 184 | 182 | ||
| 185 | rcu_read_lock(); | 183 | rcu_read_lock(); |
| 186 | klist = rcu_dereference(keyring->payload.subscriptions); | 184 | klist = rcu_dereference(keyring->payload.subscriptions); |
| @@ -241,7 +239,7 @@ static long keyring_read(const struct key *keyring, | |||
| 241 | ret = qty; | 239 | ret = qty; |
| 242 | } | 240 | } |
| 243 | 241 | ||
| 244 | error: | 242 | error: |
| 245 | return ret; | 243 | return ret; |
| 246 | 244 | ||
| 247 | } /* end keyring_read() */ | 245 | } /* end keyring_read() */ |
| @@ -310,7 +308,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
| 310 | key_check(keyring); | 308 | key_check(keyring); |
| 311 | 309 | ||
| 312 | /* top keyring must have search permission to begin the search */ | 310 | /* top keyring must have search permission to begin the search */ |
| 313 | err = key_task_permission(keyring_ref, cred, KEY_SEARCH); | 311 | err = key_task_permission(keyring_ref, cred, KEY_SEARCH); |
| 314 | if (err < 0) { | 312 | if (err < 0) { |
| 315 | key_ref = ERR_PTR(err); | 313 | key_ref = ERR_PTR(err); |
| 316 | goto error; | 314 | goto error; |
| @@ -512,7 +510,7 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
| 512 | rcu_read_unlock(); | 510 | rcu_read_unlock(); |
| 513 | return ERR_PTR(-ENOKEY); | 511 | return ERR_PTR(-ENOKEY); |
| 514 | 512 | ||
| 515 | found: | 513 | found: |
| 516 | atomic_inc(&key->usage); | 514 | atomic_inc(&key->usage); |
| 517 | rcu_read_unlock(); | 515 | rcu_read_unlock(); |
| 518 | return make_key_ref(key, possessed); | 516 | return make_key_ref(key, possessed); |
| @@ -602,7 +600,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
| 602 | sp = 0; | 600 | sp = 0; |
| 603 | 601 | ||
| 604 | /* start processing a new keyring */ | 602 | /* start processing a new keyring */ |
| 605 | descend: | 603 | descend: |
| 606 | if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) | 604 | if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) |
| 607 | goto not_this_keyring; | 605 | goto not_this_keyring; |
| 608 | 606 | ||
| @@ -611,7 +609,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
| 611 | goto not_this_keyring; | 609 | goto not_this_keyring; |
| 612 | kix = 0; | 610 | kix = 0; |
| 613 | 611 | ||
| 614 | ascend: | 612 | ascend: |
| 615 | /* iterate through the remaining keys in this keyring */ | 613 | /* iterate through the remaining keys in this keyring */ |
| 616 | for (; kix < keylist->nkeys; kix++) { | 614 | for (; kix < keylist->nkeys; kix++) { |
| 617 | key = keylist->keys[kix]; | 615 | key = keylist->keys[kix]; |
| @@ -637,7 +635,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
| 637 | 635 | ||
| 638 | /* the keyring we're looking at was disqualified or didn't contain a | 636 | /* the keyring we're looking at was disqualified or didn't contain a |
| 639 | * matching key */ | 637 | * matching key */ |
| 640 | not_this_keyring: | 638 | not_this_keyring: |
| 641 | if (sp > 0) { | 639 | if (sp > 0) { |
| 642 | /* resume the checking of a keyring higher up in the tree */ | 640 | /* resume the checking of a keyring higher up in the tree */ |
| 643 | sp--; | 641 | sp--; |
| @@ -648,34 +646,20 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
| 648 | 646 | ||
| 649 | ret = 0; /* no cycles detected */ | 647 | ret = 0; /* no cycles detected */ |
| 650 | 648 | ||
| 651 | error: | 649 | error: |
| 652 | rcu_read_unlock(); | 650 | rcu_read_unlock(); |
| 653 | return ret; | 651 | return ret; |
| 654 | 652 | ||
| 655 | too_deep: | 653 | too_deep: |
| 656 | ret = -ELOOP; | 654 | ret = -ELOOP; |
| 657 | goto error; | 655 | goto error; |
| 658 | 656 | ||
| 659 | cycle_detected: | 657 | cycle_detected: |
| 660 | ret = -EDEADLK; | 658 | ret = -EDEADLK; |
| 661 | goto error; | 659 | goto error; |
| 662 | 660 | ||
| 663 | } /* end keyring_detect_cycle() */ | 661 | } /* end keyring_detect_cycle() */ |
| 664 | 662 | ||
| 665 | /*****************************************************************************/ | ||
| 666 | /* | ||
| 667 | * dispose of a keyring list after the RCU grace period | ||
| 668 | */ | ||
| 669 | static void keyring_link_rcu_disposal(struct rcu_head *rcu) | ||
| 670 | { | ||
| 671 | struct keyring_list *klist = | ||
| 672 | container_of(rcu, struct keyring_list, rcu); | ||
| 673 | |||
| 674 | kfree(klist); | ||
| 675 | |||
| 676 | } /* end keyring_link_rcu_disposal() */ | ||
| 677 | |||
| 678 | /*****************************************************************************/ | ||
| 679 | /* | 663 | /* |
| 680 | * dispose of a keyring list after the RCU grace period, freeing the unlinked | 664 | * dispose of a keyring list after the RCU grace period, freeing the unlinked |
| 681 | * key | 665 | * key |
| @@ -685,55 +669,51 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | |||
| 685 | struct keyring_list *klist = | 669 | struct keyring_list *klist = |
| 686 | container_of(rcu, struct keyring_list, rcu); | 670 | container_of(rcu, struct keyring_list, rcu); |
| 687 | 671 | ||
| 688 | key_put(klist->keys[klist->delkey]); | 672 | if (klist->delkey != USHRT_MAX) |
| 673 | key_put(klist->keys[klist->delkey]); | ||
| 689 | kfree(klist); | 674 | kfree(klist); |
| 675 | } | ||
| 690 | 676 | ||
| 691 | } /* end keyring_unlink_rcu_disposal() */ | ||
| 692 | |||
| 693 | /*****************************************************************************/ | ||
| 694 | /* | 677 | /* |
| 695 | * link a key into to a keyring | 678 | * preallocate memory so that a key can be linked into to a keyring |
| 696 | * - must be called with the keyring's semaphore write-locked | ||
| 697 | * - discard already extant link to matching key if there is one | ||
| 698 | */ | 679 | */ |
| 699 | int __key_link(struct key *keyring, struct key *key) | 680 | int __key_link_begin(struct key *keyring, const struct key_type *type, |
| 681 | const char *description, | ||
| 682 | struct keyring_list **_prealloc) | ||
| 683 | __acquires(&keyring->sem) | ||
| 700 | { | 684 | { |
| 701 | struct keyring_list *klist, *nklist; | 685 | struct keyring_list *klist, *nklist; |
| 702 | unsigned max; | 686 | unsigned max; |
| 703 | size_t size; | 687 | size_t size; |
| 704 | int loop, ret; | 688 | int loop, ret; |
| 705 | 689 | ||
| 706 | ret = -EKEYREVOKED; | 690 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); |
| 707 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | ||
| 708 | goto error; | ||
| 709 | 691 | ||
| 710 | ret = -ENOTDIR; | ||
| 711 | if (keyring->type != &key_type_keyring) | 692 | if (keyring->type != &key_type_keyring) |
| 712 | goto error; | 693 | return -ENOTDIR; |
| 713 | 694 | ||
| 714 | /* serialise link/link calls to prevent parallel calls causing a | 695 | down_write(&keyring->sem); |
| 715 | * cycle when applied to two keyring in opposite orders */ | ||
| 716 | down_write(&keyring_serialise_link_sem); | ||
| 717 | 696 | ||
| 718 | /* check that we aren't going to create a cycle adding one keyring to | 697 | ret = -EKEYREVOKED; |
| 719 | * another */ | 698 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
| 720 | if (key->type == &key_type_keyring) { | 699 | goto error_krsem; |
| 721 | ret = keyring_detect_cycle(keyring, key); | 700 | |
| 722 | if (ret < 0) | 701 | /* serialise link/link calls to prevent parallel calls causing a cycle |
| 723 | goto error2; | 702 | * when linking two keyring in opposite orders */ |
| 724 | } | 703 | if (type == &key_type_keyring) |
| 704 | down_write(&keyring_serialise_link_sem); | ||
| 725 | 705 | ||
| 726 | /* see if there's a matching key we can displace */ | ||
| 727 | klist = rcu_dereference_locked_keyring(keyring); | 706 | klist = rcu_dereference_locked_keyring(keyring); |
| 728 | if (klist && klist->nkeys > 0) { | ||
| 729 | struct key_type *type = key->type; | ||
| 730 | 707 | ||
| 708 | /* see if there's a matching key we can displace */ | ||
| 709 | if (klist && klist->nkeys > 0) { | ||
| 731 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 710 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
| 732 | if (klist->keys[loop]->type == type && | 711 | if (klist->keys[loop]->type == type && |
| 733 | strcmp(klist->keys[loop]->description, | 712 | strcmp(klist->keys[loop]->description, |
| 734 | key->description) == 0 | 713 | description) == 0 |
| 735 | ) { | 714 | ) { |
| 736 | /* found a match - replace with new key */ | 715 | /* found a match - we'll replace this one with |
| 716 | * the new key */ | ||
| 737 | size = sizeof(struct key *) * klist->maxkeys; | 717 | size = sizeof(struct key *) * klist->maxkeys; |
| 738 | size += sizeof(*klist); | 718 | size += sizeof(*klist); |
| 739 | BUG_ON(size > PAGE_SIZE); | 719 | BUG_ON(size > PAGE_SIZE); |
| @@ -741,22 +721,10 @@ int __key_link(struct key *keyring, struct key *key) | |||
| 741 | ret = -ENOMEM; | 721 | ret = -ENOMEM; |
| 742 | nklist = kmemdup(klist, size, GFP_KERNEL); | 722 | nklist = kmemdup(klist, size, GFP_KERNEL); |
| 743 | if (!nklist) | 723 | if (!nklist) |
| 744 | goto error2; | 724 | goto error_sem; |
| 745 | |||
| 746 | /* replace matched key */ | ||
| 747 | atomic_inc(&key->usage); | ||
| 748 | nklist->keys[loop] = key; | ||
| 749 | |||
| 750 | rcu_assign_pointer( | ||
| 751 | keyring->payload.subscriptions, | ||
| 752 | nklist); | ||
| 753 | |||
| 754 | /* dispose of the old keyring list and the | ||
| 755 | * displaced key */ | ||
| 756 | klist->delkey = loop; | ||
| 757 | call_rcu(&klist->rcu, | ||
| 758 | keyring_unlink_rcu_disposal); | ||
| 759 | 725 | ||
| 726 | /* note replacement slot */ | ||
| 727 | klist->delkey = nklist->delkey = loop; | ||
| 760 | goto done; | 728 | goto done; |
| 761 | } | 729 | } |
| 762 | } | 730 | } |
| @@ -766,88 +734,167 @@ int __key_link(struct key *keyring, struct key *key) | |||
| 766 | ret = key_payload_reserve(keyring, | 734 | ret = key_payload_reserve(keyring, |
| 767 | keyring->datalen + KEYQUOTA_LINK_BYTES); | 735 | keyring->datalen + KEYQUOTA_LINK_BYTES); |
| 768 | if (ret < 0) | 736 | if (ret < 0) |
| 769 | goto error2; | 737 | goto error_sem; |
| 770 | 738 | ||
| 771 | if (klist && klist->nkeys < klist->maxkeys) { | 739 | if (klist && klist->nkeys < klist->maxkeys) { |
| 772 | /* there's sufficient slack space to add directly */ | 740 | /* there's sufficient slack space to append directly */ |
| 773 | atomic_inc(&key->usage); | 741 | nklist = NULL; |
| 774 | 742 | } else { | |
| 775 | klist->keys[klist->nkeys] = key; | ||
| 776 | smp_wmb(); | ||
| 777 | klist->nkeys++; | ||
| 778 | smp_wmb(); | ||
| 779 | } | ||
| 780 | else { | ||
| 781 | /* grow the key list */ | 743 | /* grow the key list */ |
| 782 | max = 4; | 744 | max = 4; |
| 783 | if (klist) | 745 | if (klist) |
| 784 | max += klist->maxkeys; | 746 | max += klist->maxkeys; |
| 785 | 747 | ||
| 786 | ret = -ENFILE; | 748 | ret = -ENFILE; |
| 787 | if (max > 65535) | 749 | if (max > USHRT_MAX - 1) |
| 788 | goto error3; | 750 | goto error_quota; |
| 789 | size = sizeof(*klist) + sizeof(struct key *) * max; | 751 | size = sizeof(*klist) + sizeof(struct key *) * max; |
| 790 | if (size > PAGE_SIZE) | 752 | if (size > PAGE_SIZE) |
| 791 | goto error3; | 753 | goto error_quota; |
| 792 | 754 | ||
| 793 | ret = -ENOMEM; | 755 | ret = -ENOMEM; |
| 794 | nklist = kmalloc(size, GFP_KERNEL); | 756 | nklist = kmalloc(size, GFP_KERNEL); |
| 795 | if (!nklist) | 757 | if (!nklist) |
| 796 | goto error3; | 758 | goto error_quota; |
| 797 | nklist->maxkeys = max; | ||
| 798 | nklist->nkeys = 0; | ||
| 799 | 759 | ||
| 760 | nklist->maxkeys = max; | ||
| 800 | if (klist) { | 761 | if (klist) { |
| 801 | nklist->nkeys = klist->nkeys; | 762 | memcpy(nklist->keys, klist->keys, |
| 802 | memcpy(nklist->keys, | ||
| 803 | klist->keys, | ||
| 804 | sizeof(struct key *) * klist->nkeys); | 763 | sizeof(struct key *) * klist->nkeys); |
| 764 | nklist->delkey = klist->nkeys; | ||
| 765 | nklist->nkeys = klist->nkeys + 1; | ||
| 766 | klist->delkey = USHRT_MAX; | ||
| 767 | } else { | ||
| 768 | nklist->nkeys = 1; | ||
| 769 | nklist->delkey = 0; | ||
| 805 | } | 770 | } |
| 806 | 771 | ||
| 807 | /* add the key into the new space */ | 772 | /* add the key into the new space */ |
| 808 | atomic_inc(&key->usage); | 773 | nklist->keys[nklist->delkey] = NULL; |
| 809 | nklist->keys[nklist->nkeys++] = key; | ||
| 810 | |||
| 811 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | ||
| 812 | |||
| 813 | /* dispose of the old keyring list */ | ||
| 814 | if (klist) | ||
| 815 | call_rcu(&klist->rcu, keyring_link_rcu_disposal); | ||
| 816 | } | 774 | } |
| 817 | 775 | ||
| 818 | done: | 776 | done: |
| 819 | ret = 0; | 777 | *_prealloc = nklist; |
| 820 | error2: | 778 | kleave(" = 0"); |
| 821 | up_write(&keyring_serialise_link_sem); | 779 | return 0; |
| 822 | error: | ||
| 823 | return ret; | ||
| 824 | 780 | ||
| 825 | error3: | 781 | error_quota: |
| 826 | /* undo the quota changes */ | 782 | /* undo the quota changes */ |
| 827 | key_payload_reserve(keyring, | 783 | key_payload_reserve(keyring, |
| 828 | keyring->datalen - KEYQUOTA_LINK_BYTES); | 784 | keyring->datalen - KEYQUOTA_LINK_BYTES); |
| 829 | goto error2; | 785 | error_sem: |
| 786 | if (type == &key_type_keyring) | ||
| 787 | up_write(&keyring_serialise_link_sem); | ||
| 788 | error_krsem: | ||
| 789 | up_write(&keyring->sem); | ||
| 790 | kleave(" = %d", ret); | ||
| 791 | return ret; | ||
| 792 | } | ||
| 830 | 793 | ||
| 831 | } /* end __key_link() */ | 794 | /* |
| 795 | * check already instantiated keys aren't going to be a problem | ||
| 796 | * - the caller must have called __key_link_begin() | ||
| 797 | * - don't need to call this for keys that were created since __key_link_begin() | ||
| 798 | * was called | ||
| 799 | */ | ||
| 800 | int __key_link_check_live_key(struct key *keyring, struct key *key) | ||
| 801 | { | ||
| 802 | if (key->type == &key_type_keyring) | ||
| 803 | /* check that we aren't going to create a cycle by linking one | ||
| 804 | * keyring to another */ | ||
| 805 | return keyring_detect_cycle(keyring, key); | ||
| 806 | return 0; | ||
| 807 | } | ||
| 808 | |||
| 809 | /* | ||
| 810 | * link a key into to a keyring | ||
| 811 | * - must be called with __key_link_begin() having being called | ||
| 812 | * - discard already extant link to matching key if there is one | ||
| 813 | */ | ||
| 814 | void __key_link(struct key *keyring, struct key *key, | ||
| 815 | struct keyring_list **_prealloc) | ||
| 816 | { | ||
| 817 | struct keyring_list *klist, *nklist; | ||
| 818 | |||
| 819 | nklist = *_prealloc; | ||
| 820 | *_prealloc = NULL; | ||
| 821 | |||
| 822 | kenter("%d,%d,%p", keyring->serial, key->serial, nklist); | ||
| 823 | |||
| 824 | klist = rcu_dereference_protected(keyring->payload.subscriptions, | ||
| 825 | rwsem_is_locked(&keyring->sem)); | ||
| 826 | |||
| 827 | atomic_inc(&key->usage); | ||
| 828 | |||
| 829 | /* there's a matching key we can displace or an empty slot in a newly | ||
| 830 | * allocated list we can fill */ | ||
| 831 | if (nklist) { | ||
| 832 | kdebug("replace %hu/%hu/%hu", | ||
| 833 | nklist->delkey, nklist->nkeys, nklist->maxkeys); | ||
| 834 | |||
| 835 | nklist->keys[nklist->delkey] = key; | ||
| 836 | |||
| 837 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | ||
| 838 | |||
| 839 | /* dispose of the old keyring list and, if there was one, the | ||
| 840 | * displaced key */ | ||
| 841 | if (klist) { | ||
| 842 | kdebug("dispose %hu/%hu/%hu", | ||
| 843 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
| 844 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | ||
| 845 | } | ||
| 846 | } else { | ||
| 847 | /* there's sufficient slack space to append directly */ | ||
| 848 | klist->keys[klist->nkeys] = key; | ||
| 849 | smp_wmb(); | ||
| 850 | klist->nkeys++; | ||
| 851 | } | ||
| 852 | } | ||
| 853 | |||
| 854 | /* | ||
| 855 | * finish linking a key into to a keyring | ||
| 856 | * - must be called with __key_link_begin() having being called | ||
| 857 | */ | ||
| 858 | void __key_link_end(struct key *keyring, struct key_type *type, | ||
| 859 | struct keyring_list *prealloc) | ||
| 860 | __releases(&keyring->sem) | ||
| 861 | { | ||
| 862 | BUG_ON(type == NULL); | ||
| 863 | BUG_ON(type->name == NULL); | ||
| 864 | kenter("%d,%s,%p", keyring->serial, type->name, prealloc); | ||
| 865 | |||
| 866 | if (type == &key_type_keyring) | ||
| 867 | up_write(&keyring_serialise_link_sem); | ||
| 868 | |||
| 869 | if (prealloc) { | ||
| 870 | kfree(prealloc); | ||
| 871 | key_payload_reserve(keyring, | ||
| 872 | keyring->datalen - KEYQUOTA_LINK_BYTES); | ||
| 873 | } | ||
| 874 | up_write(&keyring->sem); | ||
| 875 | } | ||
| 832 | 876 | ||
| 833 | /*****************************************************************************/ | ||
| 834 | /* | 877 | /* |
| 835 | * link a key to a keyring | 878 | * link a key to a keyring |
| 836 | */ | 879 | */ |
| 837 | int key_link(struct key *keyring, struct key *key) | 880 | int key_link(struct key *keyring, struct key *key) |
| 838 | { | 881 | { |
| 882 | struct keyring_list *prealloc; | ||
| 839 | int ret; | 883 | int ret; |
| 840 | 884 | ||
| 841 | key_check(keyring); | 885 | key_check(keyring); |
| 842 | key_check(key); | 886 | key_check(key); |
| 843 | 887 | ||
| 844 | down_write(&keyring->sem); | 888 | ret = __key_link_begin(keyring, key->type, key->description, &prealloc); |
| 845 | ret = __key_link(keyring, key); | 889 | if (ret == 0) { |
| 846 | up_write(&keyring->sem); | 890 | ret = __key_link_check_live_key(keyring, key); |
| 891 | if (ret == 0) | ||
| 892 | __key_link(keyring, key, &prealloc); | ||
| 893 | __key_link_end(keyring, key->type, prealloc); | ||
| 894 | } | ||
| 847 | 895 | ||
| 848 | return ret; | 896 | return ret; |
| 849 | 897 | } | |
| 850 | } /* end key_link() */ | ||
| 851 | 898 | ||
| 852 | EXPORT_SYMBOL(key_link); | 899 | EXPORT_SYMBOL(key_link); |
| 853 | 900 | ||
diff --git a/security/keys/permission.c b/security/keys/permission.c index 0ed802c9e698..28645502cd0d 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
| @@ -109,7 +109,7 @@ int key_validate(struct key *key) | |||
| 109 | } | 109 | } |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | error: | 112 | error: |
| 113 | return ret; | 113 | return ret; |
| 114 | 114 | ||
| 115 | } /* end key_validate() */ | 115 | } /* end key_validate() */ |
diff --git a/security/keys/proc.c b/security/keys/proc.c index 706d63f4f185..068b66ea2f1b 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
| @@ -306,7 +306,7 @@ static void *proc_key_users_start(struct seq_file *p, loff_t *_pos) | |||
| 306 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) | 306 | static void *proc_key_users_next(struct seq_file *p, void *v, loff_t *_pos) |
| 307 | { | 307 | { |
| 308 | (*_pos)++; | 308 | (*_pos)++; |
| 309 | return key_user_next((struct rb_node *) v); | 309 | return key_user_next((struct rb_node *)v); |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | static void proc_key_users_stop(struct seq_file *p, void *v) | 312 | static void proc_key_users_stop(struct seq_file *p, void *v) |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 06c2ccf26ed3..6b8e4ff4cc68 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
| @@ -216,8 +216,7 @@ static int install_process_keyring(void) | |||
| 216 | /* | 216 | /* |
| 217 | * install a session keyring directly to a credentials struct | 217 | * install a session keyring directly to a credentials struct |
| 218 | */ | 218 | */ |
| 219 | static int install_session_keyring_to_cred(struct cred *cred, | 219 | int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) |
| 220 | struct key *keyring) | ||
| 221 | { | 220 | { |
| 222 | unsigned long flags; | 221 | unsigned long flags; |
| 223 | struct key *old; | 222 | struct key *old; |
| @@ -508,7 +507,7 @@ try_again: | |||
| 508 | 507 | ||
| 509 | ret = install_thread_keyring(); | 508 | ret = install_thread_keyring(); |
| 510 | if (ret < 0) { | 509 | if (ret < 0) { |
| 511 | key = ERR_PTR(ret); | 510 | key_ref = ERR_PTR(ret); |
| 512 | goto error; | 511 | goto error; |
| 513 | } | 512 | } |
| 514 | goto reget_creds; | 513 | goto reget_creds; |
| @@ -526,7 +525,7 @@ try_again: | |||
| 526 | 525 | ||
| 527 | ret = install_process_keyring(); | 526 | ret = install_process_keyring(); |
| 528 | if (ret < 0) { | 527 | if (ret < 0) { |
| 529 | key = ERR_PTR(ret); | 528 | key_ref = ERR_PTR(ret); |
| 530 | goto error; | 529 | goto error; |
| 531 | } | 530 | } |
| 532 | goto reget_creds; | 531 | goto reget_creds; |
| @@ -585,7 +584,7 @@ try_again: | |||
| 585 | 584 | ||
| 586 | case KEY_SPEC_GROUP_KEYRING: | 585 | case KEY_SPEC_GROUP_KEYRING: |
| 587 | /* group keyrings are not yet supported */ | 586 | /* group keyrings are not yet supported */ |
| 588 | key = ERR_PTR(-EINVAL); | 587 | key_ref = ERR_PTR(-EINVAL); |
| 589 | goto error; | 588 | goto error; |
| 590 | 589 | ||
| 591 | case KEY_SPEC_REQKEY_AUTH_KEY: | 590 | case KEY_SPEC_REQKEY_AUTH_KEY: |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index d8c1a6a0fb08..f5ec9ac5d57c 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
| @@ -58,6 +58,38 @@ void complete_request_key(struct key_construction *cons, int error) | |||
| 58 | } | 58 | } |
| 59 | EXPORT_SYMBOL(complete_request_key); | 59 | EXPORT_SYMBOL(complete_request_key); |
| 60 | 60 | ||
| 61 | static int umh_keys_init(struct subprocess_info *info) | ||
| 62 | { | ||
| 63 | struct cred *cred = (struct cred*)current_cred(); | ||
| 64 | struct key *keyring = info->data; | ||
| 65 | /* | ||
| 66 | * This is called in context of freshly forked kthread before | ||
| 67 | * kernel_execve(), we can just change our ->session_keyring. | ||
| 68 | */ | ||
| 69 | return install_session_keyring_to_cred(cred, keyring); | ||
| 70 | } | ||
| 71 | |||
| 72 | static void umh_keys_cleanup(struct subprocess_info *info) | ||
| 73 | { | ||
| 74 | struct key *keyring = info->data; | ||
| 75 | key_put(keyring); | ||
| 76 | } | ||
| 77 | |||
| 78 | static int call_usermodehelper_keys(char *path, char **argv, char **envp, | ||
| 79 | struct key *session_keyring, enum umh_wait wait) | ||
| 80 | { | ||
| 81 | gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; | ||
| 82 | struct subprocess_info *info = | ||
| 83 | call_usermodehelper_setup(path, argv, envp, gfp_mask); | ||
| 84 | |||
| 85 | if (!info) | ||
| 86 | return -ENOMEM; | ||
| 87 | |||
| 88 | call_usermodehelper_setfns(info, umh_keys_init, umh_keys_cleanup, | ||
| 89 | key_get(session_keyring)); | ||
| 90 | return call_usermodehelper_exec(info, wait); | ||
| 91 | } | ||
| 92 | |||
| 61 | /* | 93 | /* |
| 62 | * request userspace finish the construction of a key | 94 | * request userspace finish the construction of a key |
| 63 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" | 95 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" |
| @@ -299,12 +331,15 @@ static int construct_alloc_key(struct key_type *type, | |||
| 299 | struct key_user *user, | 331 | struct key_user *user, |
| 300 | struct key **_key) | 332 | struct key **_key) |
| 301 | { | 333 | { |
| 334 | struct keyring_list *prealloc; | ||
| 302 | const struct cred *cred = current_cred(); | 335 | const struct cred *cred = current_cred(); |
| 303 | struct key *key; | 336 | struct key *key; |
| 304 | key_ref_t key_ref; | 337 | key_ref_t key_ref; |
| 338 | int ret; | ||
| 305 | 339 | ||
| 306 | kenter("%s,%s,,,", type->name, description); | 340 | kenter("%s,%s,,,", type->name, description); |
| 307 | 341 | ||
| 342 | *_key = NULL; | ||
| 308 | mutex_lock(&user->cons_lock); | 343 | mutex_lock(&user->cons_lock); |
| 309 | 344 | ||
| 310 | key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, | 345 | key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, |
| @@ -314,8 +349,12 @@ static int construct_alloc_key(struct key_type *type, | |||
| 314 | 349 | ||
| 315 | set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); | 350 | set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); |
| 316 | 351 | ||
| 317 | if (dest_keyring) | 352 | if (dest_keyring) { |
| 318 | down_write(&dest_keyring->sem); | 353 | ret = __key_link_begin(dest_keyring, type, description, |
| 354 | &prealloc); | ||
| 355 | if (ret < 0) | ||
| 356 | goto link_prealloc_failed; | ||
| 357 | } | ||
| 319 | 358 | ||
| 320 | /* attach the key to the destination keyring under lock, but we do need | 359 | /* attach the key to the destination keyring under lock, but we do need |
| 321 | * to do another check just in case someone beat us to it whilst we | 360 | * to do another check just in case someone beat us to it whilst we |
| @@ -327,31 +366,49 @@ static int construct_alloc_key(struct key_type *type, | |||
| 327 | goto key_already_present; | 366 | goto key_already_present; |
| 328 | 367 | ||
| 329 | if (dest_keyring) | 368 | if (dest_keyring) |
| 330 | __key_link(dest_keyring, key); | 369 | __key_link(dest_keyring, key, &prealloc); |
| 331 | 370 | ||
| 332 | mutex_unlock(&key_construction_mutex); | 371 | mutex_unlock(&key_construction_mutex); |
| 333 | if (dest_keyring) | 372 | if (dest_keyring) |
| 334 | up_write(&dest_keyring->sem); | 373 | __key_link_end(dest_keyring, type, prealloc); |
| 335 | mutex_unlock(&user->cons_lock); | 374 | mutex_unlock(&user->cons_lock); |
| 336 | *_key = key; | 375 | *_key = key; |
| 337 | kleave(" = 0 [%d]", key_serial(key)); | 376 | kleave(" = 0 [%d]", key_serial(key)); |
| 338 | return 0; | 377 | return 0; |
| 339 | 378 | ||
| 379 | /* the key is now present - we tell the caller that we found it by | ||
| 380 | * returning -EINPROGRESS */ | ||
| 340 | key_already_present: | 381 | key_already_present: |
| 382 | key_put(key); | ||
| 341 | mutex_unlock(&key_construction_mutex); | 383 | mutex_unlock(&key_construction_mutex); |
| 384 | key = key_ref_to_ptr(key_ref); | ||
| 342 | if (dest_keyring) { | 385 | if (dest_keyring) { |
| 343 | __key_link(dest_keyring, key_ref_to_ptr(key_ref)); | 386 | ret = __key_link_check_live_key(dest_keyring, key); |
| 344 | up_write(&dest_keyring->sem); | 387 | if (ret == 0) |
| 388 | __key_link(dest_keyring, key, &prealloc); | ||
| 389 | __key_link_end(dest_keyring, type, prealloc); | ||
| 390 | if (ret < 0) | ||
| 391 | goto link_check_failed; | ||
| 345 | } | 392 | } |
| 346 | mutex_unlock(&user->cons_lock); | 393 | mutex_unlock(&user->cons_lock); |
| 347 | key_put(key); | 394 | *_key = key; |
| 348 | *_key = key = key_ref_to_ptr(key_ref); | ||
| 349 | kleave(" = -EINPROGRESS [%d]", key_serial(key)); | 395 | kleave(" = -EINPROGRESS [%d]", key_serial(key)); |
| 350 | return -EINPROGRESS; | 396 | return -EINPROGRESS; |
| 351 | 397 | ||
| 398 | link_check_failed: | ||
| 399 | mutex_unlock(&user->cons_lock); | ||
| 400 | key_put(key); | ||
| 401 | kleave(" = %d [linkcheck]", ret); | ||
| 402 | return ret; | ||
| 403 | |||
| 404 | link_prealloc_failed: | ||
| 405 | up_write(&dest_keyring->sem); | ||
| 406 | mutex_unlock(&user->cons_lock); | ||
| 407 | kleave(" = %d [prelink]", ret); | ||
| 408 | return ret; | ||
| 409 | |||
| 352 | alloc_failed: | 410 | alloc_failed: |
| 353 | mutex_unlock(&user->cons_lock); | 411 | mutex_unlock(&user->cons_lock); |
| 354 | *_key = NULL; | ||
| 355 | kleave(" = %ld", PTR_ERR(key)); | 412 | kleave(" = %ld", PTR_ERR(key)); |
| 356 | return PTR_ERR(key); | 413 | return PTR_ERR(key); |
| 357 | } | 414 | } |
| @@ -390,6 +447,10 @@ static struct key *construct_key_and_link(struct key_type *type, | |||
| 390 | kdebug("cons failed"); | 447 | kdebug("cons failed"); |
| 391 | goto construction_failed; | 448 | goto construction_failed; |
| 392 | } | 449 | } |
| 450 | } else if (ret == -EINPROGRESS) { | ||
| 451 | ret = 0; | ||
| 452 | } else { | ||
| 453 | key = ERR_PTR(ret); | ||
| 393 | } | 454 | } |
| 394 | 455 | ||
| 395 | key_put(dest_keyring); | 456 | key_put(dest_keyring); |
| @@ -422,6 +483,7 @@ struct key *request_key_and_link(struct key_type *type, | |||
| 422 | const struct cred *cred = current_cred(); | 483 | const struct cred *cred = current_cred(); |
| 423 | struct key *key; | 484 | struct key *key; |
| 424 | key_ref_t key_ref; | 485 | key_ref_t key_ref; |
| 486 | int ret; | ||
| 425 | 487 | ||
| 426 | kenter("%s,%s,%p,%zu,%p,%p,%lx", | 488 | kenter("%s,%s,%p,%zu,%p,%p,%lx", |
| 427 | type->name, description, callout_info, callout_len, aux, | 489 | type->name, description, callout_info, callout_len, aux, |
| @@ -435,8 +497,13 @@ struct key *request_key_and_link(struct key_type *type, | |||
| 435 | key = key_ref_to_ptr(key_ref); | 497 | key = key_ref_to_ptr(key_ref); |
| 436 | if (dest_keyring) { | 498 | if (dest_keyring) { |
| 437 | construct_get_dest_keyring(&dest_keyring); | 499 | construct_get_dest_keyring(&dest_keyring); |
| 438 | key_link(dest_keyring, key); | 500 | ret = key_link(dest_keyring, key); |
| 439 | key_put(dest_keyring); | 501 | key_put(dest_keyring); |
| 502 | if (ret < 0) { | ||
| 503 | key_put(key); | ||
| 504 | key = ERR_PTR(ret); | ||
| 505 | goto error; | ||
| 506 | } | ||
| 440 | } | 507 | } |
| 441 | } else if (PTR_ERR(key_ref) != -EAGAIN) { | 508 | } else if (PTR_ERR(key_ref) != -EAGAIN) { |
| 442 | key = ERR_CAST(key_ref); | 509 | key = ERR_CAST(key_ref); |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 893365b79a29..908aa712816a 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
| @@ -221,7 +221,7 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | switch (a->type) { | 223 | switch (a->type) { |
| 224 | case LSM_AUDIT_NO_AUDIT: | 224 | case LSM_AUDIT_DATA_NONE: |
| 225 | return; | 225 | return; |
| 226 | case LSM_AUDIT_DATA_IPC: | 226 | case LSM_AUDIT_DATA_IPC: |
| 227 | audit_log_format(ab, " key=%d ", a->u.ipc_id); | 227 | audit_log_format(ab, " key=%d ", a->u.ipc_id); |
diff --git a/security/security.c b/security/security.c index 687c6fd14bb6..351942a4ca0e 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -23,14 +23,14 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = | |||
| 23 | CONFIG_DEFAULT_SECURITY; | 23 | CONFIG_DEFAULT_SECURITY; |
| 24 | 24 | ||
| 25 | /* things that live in capability.c */ | 25 | /* things that live in capability.c */ |
| 26 | extern void security_fixup_ops(struct security_operations *ops); | 26 | extern void __init security_fixup_ops(struct security_operations *ops); |
| 27 | 27 | ||
| 28 | static struct security_operations *security_ops; | 28 | static struct security_operations *security_ops; |
| 29 | static struct security_operations default_security_ops = { | 29 | static struct security_operations default_security_ops = { |
| 30 | .name = "default", | 30 | .name = "default", |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | static inline int verify(struct security_operations *ops) | 33 | static inline int __init verify(struct security_operations *ops) |
| 34 | { | 34 | { |
| 35 | /* verify the security_operations structure exists */ | 35 | /* verify the security_operations structure exists */ |
| 36 | if (!ops) | 36 | if (!ops) |
| @@ -117,7 +117,7 @@ int __init security_module_enable(struct security_operations *ops) | |||
| 117 | * If there is already a security module registered with the kernel, | 117 | * If there is already a security module registered with the kernel, |
| 118 | * an error will be returned. Otherwise %0 is returned on success. | 118 | * an error will be returned. Otherwise %0 is returned on success. |
| 119 | */ | 119 | */ |
| 120 | int register_security(struct security_operations *ops) | 120 | int __init register_security(struct security_operations *ops) |
| 121 | { | 121 | { |
| 122 | if (verify(ops)) { | 122 | if (verify(ops)) { |
| 123 | printk(KERN_DEBUG "%s could not verify " | 123 | printk(KERN_DEBUG "%s could not verify " |
| @@ -190,11 +190,6 @@ int security_real_capable_noaudit(struct task_struct *tsk, int cap) | |||
| 190 | return ret; | 190 | return ret; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | int security_acct(struct file *file) | ||
| 194 | { | ||
| 195 | return security_ops->acct(file); | ||
| 196 | } | ||
| 197 | |||
| 198 | int security_sysctl(struct ctl_table *table, int op) | 193 | int security_sysctl(struct ctl_table *table, int op) |
| 199 | { | 194 | { |
| 200 | return security_ops->sysctl(table, op); | 195 | return security_ops->sysctl(table, op); |
| @@ -306,46 +301,16 @@ int security_sb_mount(char *dev_name, struct path *path, | |||
| 306 | return security_ops->sb_mount(dev_name, path, type, flags, data); | 301 | return security_ops->sb_mount(dev_name, path, type, flags, data); |
| 307 | } | 302 | } |
| 308 | 303 | ||
| 309 | int security_sb_check_sb(struct vfsmount *mnt, struct path *path) | ||
| 310 | { | ||
| 311 | return security_ops->sb_check_sb(mnt, path); | ||
| 312 | } | ||
| 313 | |||
| 314 | int security_sb_umount(struct vfsmount *mnt, int flags) | 304 | int security_sb_umount(struct vfsmount *mnt, int flags) |
| 315 | { | 305 | { |
| 316 | return security_ops->sb_umount(mnt, flags); | 306 | return security_ops->sb_umount(mnt, flags); |
| 317 | } | 307 | } |
| 318 | 308 | ||
| 319 | void security_sb_umount_close(struct vfsmount *mnt) | ||
| 320 | { | ||
| 321 | security_ops->sb_umount_close(mnt); | ||
| 322 | } | ||
| 323 | |||
| 324 | void security_sb_umount_busy(struct vfsmount *mnt) | ||
| 325 | { | ||
| 326 | security_ops->sb_umount_busy(mnt); | ||
| 327 | } | ||
| 328 | |||
| 329 | void security_sb_post_remount(struct vfsmount *mnt, unsigned long flags, void *data) | ||
| 330 | { | ||
| 331 | security_ops->sb_post_remount(mnt, flags, data); | ||
| 332 | } | ||
| 333 | |||
| 334 | void security_sb_post_addmount(struct vfsmount *mnt, struct path *mountpoint) | ||
| 335 | { | ||
| 336 | security_ops->sb_post_addmount(mnt, mountpoint); | ||
| 337 | } | ||
| 338 | |||
| 339 | int security_sb_pivotroot(struct path *old_path, struct path *new_path) | 309 | int security_sb_pivotroot(struct path *old_path, struct path *new_path) |
| 340 | { | 310 | { |
| 341 | return security_ops->sb_pivotroot(old_path, new_path); | 311 | return security_ops->sb_pivotroot(old_path, new_path); |
| 342 | } | 312 | } |
| 343 | 313 | ||
| 344 | void security_sb_post_pivotroot(struct path *old_path, struct path *new_path) | ||
| 345 | { | ||
| 346 | security_ops->sb_post_pivotroot(old_path, new_path); | ||
| 347 | } | ||
| 348 | |||
| 349 | int security_sb_set_mnt_opts(struct super_block *sb, | 314 | int security_sb_set_mnt_opts(struct super_block *sb, |
| 350 | struct security_mnt_opts *opts) | 315 | struct security_mnt_opts *opts) |
| 351 | { | 316 | { |
| @@ -580,13 +545,6 @@ int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
| 580 | return security_ops->inode_getattr(mnt, dentry); | 545 | return security_ops->inode_getattr(mnt, dentry); |
| 581 | } | 546 | } |
| 582 | 547 | ||
| 583 | void security_inode_delete(struct inode *inode) | ||
| 584 | { | ||
| 585 | if (unlikely(IS_PRIVATE(inode))) | ||
| 586 | return; | ||
| 587 | security_ops->inode_delete(inode); | ||
| 588 | } | ||
| 589 | |||
| 590 | int security_inode_setxattr(struct dentry *dentry, const char *name, | 548 | int security_inode_setxattr(struct dentry *dentry, const char *name, |
| 591 | const void *value, size_t size, int flags) | 549 | const void *value, size_t size, int flags) |
| 592 | { | 550 | { |
| @@ -749,11 +707,6 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) | |||
| 749 | return security_ops->cred_prepare(new, old, gfp); | 707 | return security_ops->cred_prepare(new, old, gfp); |
| 750 | } | 708 | } |
| 751 | 709 | ||
| 752 | void security_commit_creds(struct cred *new, const struct cred *old) | ||
| 753 | { | ||
| 754 | security_ops->cred_commit(new, old); | ||
| 755 | } | ||
| 756 | |||
| 757 | void security_transfer_creds(struct cred *new, const struct cred *old) | 710 | void security_transfer_creds(struct cred *new, const struct cred *old) |
| 758 | { | 711 | { |
| 759 | security_ops->cred_transfer(new, old); | 712 | security_ops->cred_transfer(new, old); |
| @@ -774,22 +727,12 @@ int security_kernel_module_request(char *kmod_name) | |||
| 774 | return security_ops->kernel_module_request(kmod_name); | 727 | return security_ops->kernel_module_request(kmod_name); |
| 775 | } | 728 | } |
| 776 | 729 | ||
| 777 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | ||
| 778 | { | ||
| 779 | return security_ops->task_setuid(id0, id1, id2, flags); | ||
| 780 | } | ||
| 781 | |||
| 782 | int security_task_fix_setuid(struct cred *new, const struct cred *old, | 730 | int security_task_fix_setuid(struct cred *new, const struct cred *old, |
| 783 | int flags) | 731 | int flags) |
| 784 | { | 732 | { |
| 785 | return security_ops->task_fix_setuid(new, old, flags); | 733 | return security_ops->task_fix_setuid(new, old, flags); |
| 786 | } | 734 | } |
| 787 | 735 | ||
| 788 | int security_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) | ||
| 789 | { | ||
| 790 | return security_ops->task_setgid(id0, id1, id2, flags); | ||
| 791 | } | ||
| 792 | |||
| 793 | int security_task_setpgid(struct task_struct *p, pid_t pgid) | 736 | int security_task_setpgid(struct task_struct *p, pid_t pgid) |
| 794 | { | 737 | { |
| 795 | return security_ops->task_setpgid(p, pgid); | 738 | return security_ops->task_setpgid(p, pgid); |
| @@ -811,11 +754,6 @@ void security_task_getsecid(struct task_struct *p, u32 *secid) | |||
| 811 | } | 754 | } |
| 812 | EXPORT_SYMBOL(security_task_getsecid); | 755 | EXPORT_SYMBOL(security_task_getsecid); |
| 813 | 756 | ||
| 814 | int security_task_setgroups(struct group_info *group_info) | ||
| 815 | { | ||
| 816 | return security_ops->task_setgroups(group_info); | ||
| 817 | } | ||
| 818 | |||
| 819 | int security_task_setnice(struct task_struct *p, int nice) | 757 | int security_task_setnice(struct task_struct *p, int nice) |
| 820 | { | 758 | { |
| 821 | return security_ops->task_setnice(p, nice); | 759 | return security_ops->task_setnice(p, nice); |
| @@ -1319,13 +1257,6 @@ int security_key_getsecurity(struct key *key, char **_buffer) | |||
| 1319 | return security_ops->key_getsecurity(key, _buffer); | 1257 | return security_ops->key_getsecurity(key, _buffer); |
| 1320 | } | 1258 | } |
| 1321 | 1259 | ||
| 1322 | int security_key_session_to_parent(const struct cred *cred, | ||
| 1323 | const struct cred *parent_cred, | ||
| 1324 | struct key *key) | ||
| 1325 | { | ||
| 1326 | return security_ops->key_session_to_parent(cred, parent_cred, key); | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | #endif /* CONFIG_KEYS */ | 1260 | #endif /* CONFIG_KEYS */ |
| 1330 | 1261 | ||
| 1331 | #ifdef CONFIG_AUDIT | 1262 | #ifdef CONFIG_AUDIT |
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 989fef82563a..7f1a304712a9 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
| @@ -499,8 +499,7 @@ void avc_audit(u32 ssid, u32 tsid, | |||
| 499 | return; | 499 | return; |
| 500 | if (!a) { | 500 | if (!a) { |
| 501 | a = &stack_data; | 501 | a = &stack_data; |
| 502 | memset(a, 0, sizeof(*a)); | 502 | COMMON_AUDIT_DATA_INIT(a, NONE); |
| 503 | a->type = LSM_AUDIT_NO_AUDIT; | ||
| 504 | } | 503 | } |
| 505 | a->selinux_audit_data.tclass = tclass; | 504 | a->selinux_audit_data.tclass = tclass; |
| 506 | a->selinux_audit_data.requested = requested; | 505 | a->selinux_audit_data.requested = requested; |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5feecb41009d..5c9f25ba1c95 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -126,11 +126,6 @@ __setup("selinux=", selinux_enabled_setup); | |||
| 126 | int selinux_enabled = 1; | 126 | int selinux_enabled = 1; |
| 127 | #endif | 127 | #endif |
| 128 | 128 | ||
| 129 | /* Lists of inode and superblock security structures initialized | ||
| 130 | before the policy was loaded. */ | ||
| 131 | static LIST_HEAD(superblock_security_head); | ||
| 132 | static DEFINE_SPINLOCK(sb_security_lock); | ||
| 133 | |||
| 134 | static struct kmem_cache *sel_inode_cache; | 129 | static struct kmem_cache *sel_inode_cache; |
| 135 | 130 | ||
| 136 | /** | 131 | /** |
| @@ -266,7 +261,6 @@ static int superblock_alloc_security(struct super_block *sb) | |||
| 266 | return -ENOMEM; | 261 | return -ENOMEM; |
| 267 | 262 | ||
| 268 | mutex_init(&sbsec->lock); | 263 | mutex_init(&sbsec->lock); |
| 269 | INIT_LIST_HEAD(&sbsec->list); | ||
| 270 | INIT_LIST_HEAD(&sbsec->isec_head); | 264 | INIT_LIST_HEAD(&sbsec->isec_head); |
| 271 | spin_lock_init(&sbsec->isec_lock); | 265 | spin_lock_init(&sbsec->isec_lock); |
| 272 | sbsec->sb = sb; | 266 | sbsec->sb = sb; |
| @@ -281,40 +275,34 @@ static int superblock_alloc_security(struct super_block *sb) | |||
| 281 | static void superblock_free_security(struct super_block *sb) | 275 | static void superblock_free_security(struct super_block *sb) |
| 282 | { | 276 | { |
| 283 | struct superblock_security_struct *sbsec = sb->s_security; | 277 | struct superblock_security_struct *sbsec = sb->s_security; |
| 284 | |||
| 285 | spin_lock(&sb_security_lock); | ||
| 286 | if (!list_empty(&sbsec->list)) | ||
| 287 | list_del_init(&sbsec->list); | ||
| 288 | spin_unlock(&sb_security_lock); | ||
| 289 | |||
| 290 | sb->s_security = NULL; | 278 | sb->s_security = NULL; |
| 291 | kfree(sbsec); | 279 | kfree(sbsec); |
| 292 | } | 280 | } |
| 293 | 281 | ||
| 294 | static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) | 282 | static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) |
| 295 | { | 283 | { |
| 296 | struct sk_security_struct *ssec; | 284 | struct sk_security_struct *sksec; |
| 297 | 285 | ||
| 298 | ssec = kzalloc(sizeof(*ssec), priority); | 286 | sksec = kzalloc(sizeof(*sksec), priority); |
| 299 | if (!ssec) | 287 | if (!sksec) |
| 300 | return -ENOMEM; | 288 | return -ENOMEM; |
| 301 | 289 | ||
| 302 | ssec->peer_sid = SECINITSID_UNLABELED; | 290 | sksec->peer_sid = SECINITSID_UNLABELED; |
| 303 | ssec->sid = SECINITSID_UNLABELED; | 291 | sksec->sid = SECINITSID_UNLABELED; |
| 304 | sk->sk_security = ssec; | 292 | sk->sk_security = sksec; |
| 305 | 293 | ||
| 306 | selinux_netlbl_sk_security_reset(ssec); | 294 | selinux_netlbl_sk_security_reset(sksec); |
| 307 | 295 | ||
| 308 | return 0; | 296 | return 0; |
| 309 | } | 297 | } |
| 310 | 298 | ||
| 311 | static void sk_free_security(struct sock *sk) | 299 | static void sk_free_security(struct sock *sk) |
| 312 | { | 300 | { |
| 313 | struct sk_security_struct *ssec = sk->sk_security; | 301 | struct sk_security_struct *sksec = sk->sk_security; |
| 314 | 302 | ||
| 315 | sk->sk_security = NULL; | 303 | sk->sk_security = NULL; |
| 316 | selinux_netlbl_sk_security_free(ssec); | 304 | selinux_netlbl_sk_security_free(sksec); |
| 317 | kfree(ssec); | 305 | kfree(sksec); |
| 318 | } | 306 | } |
| 319 | 307 | ||
| 320 | /* The security server must be initialized before | 308 | /* The security server must be initialized before |
| @@ -323,7 +311,7 @@ extern int ss_initialized; | |||
| 323 | 311 | ||
| 324 | /* The file system's label must be initialized prior to use. */ | 312 | /* The file system's label must be initialized prior to use. */ |
| 325 | 313 | ||
| 326 | static char *labeling_behaviors[6] = { | 314 | static const char *labeling_behaviors[6] = { |
| 327 | "uses xattr", | 315 | "uses xattr", |
| 328 | "uses transition SIDs", | 316 | "uses transition SIDs", |
| 329 | "uses task SIDs", | 317 | "uses task SIDs", |
| @@ -612,10 +600,6 @@ static int selinux_set_mnt_opts(struct super_block *sb, | |||
| 612 | /* Defer initialization until selinux_complete_init, | 600 | /* Defer initialization until selinux_complete_init, |
| 613 | after the initial policy is loaded and the security | 601 | after the initial policy is loaded and the security |
| 614 | server is ready to handle calls. */ | 602 | server is ready to handle calls. */ |
| 615 | spin_lock(&sb_security_lock); | ||
| 616 | if (list_empty(&sbsec->list)) | ||
| 617 | list_add(&sbsec->list, &superblock_security_head); | ||
| 618 | spin_unlock(&sb_security_lock); | ||
| 619 | goto out; | 603 | goto out; |
| 620 | } | 604 | } |
| 621 | rc = -EINVAL; | 605 | rc = -EINVAL; |
| @@ -806,16 +790,10 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
| 806 | 790 | ||
| 807 | /* | 791 | /* |
| 808 | * if the parent was able to be mounted it clearly had no special lsm | 792 | * if the parent was able to be mounted it clearly had no special lsm |
| 809 | * mount options. thus we can safely put this sb on the list and deal | 793 | * mount options. thus we can safely deal with this superblock later |
| 810 | * with it later | ||
| 811 | */ | 794 | */ |
| 812 | if (!ss_initialized) { | 795 | if (!ss_initialized) |
| 813 | spin_lock(&sb_security_lock); | ||
| 814 | if (list_empty(&newsbsec->list)) | ||
| 815 | list_add(&newsbsec->list, &superblock_security_head); | ||
| 816 | spin_unlock(&sb_security_lock); | ||
| 817 | return; | 796 | return; |
| 818 | } | ||
| 819 | 797 | ||
| 820 | /* how can we clone if the old one wasn't set up?? */ | 798 | /* how can we clone if the old one wasn't set up?? */ |
| 821 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); | 799 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); |
| @@ -2999,13 +2977,15 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, | |||
| 2999 | return file_has_perm(cred, file, av); | 2977 | return file_has_perm(cred, file, av); |
| 3000 | } | 2978 | } |
| 3001 | 2979 | ||
| 2980 | static int default_noexec; | ||
| 2981 | |||
| 3002 | static int file_map_prot_check(struct file *file, unsigned long prot, int shared) | 2982 | static int file_map_prot_check(struct file *file, unsigned long prot, int shared) |
| 3003 | { | 2983 | { |
| 3004 | const struct cred *cred = current_cred(); | 2984 | const struct cred *cred = current_cred(); |
| 3005 | int rc = 0; | 2985 | int rc = 0; |
| 3006 | 2986 | ||
| 3007 | #ifndef CONFIG_PPC32 | 2987 | if (default_noexec && |
| 3008 | if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { | 2988 | (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { |
| 3009 | /* | 2989 | /* |
| 3010 | * We are making executable an anonymous mapping or a | 2990 | * We are making executable an anonymous mapping or a |
| 3011 | * private file mapping that will also be writable. | 2991 | * private file mapping that will also be writable. |
| @@ -3015,7 +2995,6 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared | |||
| 3015 | if (rc) | 2995 | if (rc) |
| 3016 | goto error; | 2996 | goto error; |
| 3017 | } | 2997 | } |
| 3018 | #endif | ||
| 3019 | 2998 | ||
| 3020 | if (file) { | 2999 | if (file) { |
| 3021 | /* read access is always possible with a mapping */ | 3000 | /* read access is always possible with a mapping */ |
| @@ -3076,8 +3055,8 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, | |||
| 3076 | if (selinux_checkreqprot) | 3055 | if (selinux_checkreqprot) |
| 3077 | prot = reqprot; | 3056 | prot = reqprot; |
| 3078 | 3057 | ||
| 3079 | #ifndef CONFIG_PPC32 | 3058 | if (default_noexec && |
| 3080 | if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { | 3059 | (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { |
| 3081 | int rc = 0; | 3060 | int rc = 0; |
| 3082 | if (vma->vm_start >= vma->vm_mm->start_brk && | 3061 | if (vma->vm_start >= vma->vm_mm->start_brk && |
| 3083 | vma->vm_end <= vma->vm_mm->brk) { | 3062 | vma->vm_end <= vma->vm_mm->brk) { |
| @@ -3099,7 +3078,6 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, | |||
| 3099 | if (rc) | 3078 | if (rc) |
| 3100 | return rc; | 3079 | return rc; |
| 3101 | } | 3080 | } |
| 3102 | #endif | ||
| 3103 | 3081 | ||
| 3104 | return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); | 3082 | return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); |
| 3105 | } | 3083 | } |
| @@ -4002,7 +3980,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, | |||
| 4002 | struct socket *other, | 3980 | struct socket *other, |
| 4003 | struct sock *newsk) | 3981 | struct sock *newsk) |
| 4004 | { | 3982 | { |
| 4005 | struct sk_security_struct *ssec; | 3983 | struct sk_security_struct *sksec; |
| 4006 | struct inode_security_struct *isec; | 3984 | struct inode_security_struct *isec; |
| 4007 | struct inode_security_struct *other_isec; | 3985 | struct inode_security_struct *other_isec; |
| 4008 | struct common_audit_data ad; | 3986 | struct common_audit_data ad; |
| @@ -4021,13 +3999,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, | |||
| 4021 | return err; | 3999 | return err; |
| 4022 | 4000 | ||
| 4023 | /* connecting socket */ | 4001 | /* connecting socket */ |
| 4024 | ssec = sock->sk->sk_security; | 4002 | sksec = sock->sk->sk_security; |
| 4025 | ssec->peer_sid = other_isec->sid; | 4003 | sksec->peer_sid = other_isec->sid; |
| 4026 | 4004 | ||
| 4027 | /* server child socket */ | 4005 | /* server child socket */ |
| 4028 | ssec = newsk->sk_security; | 4006 | sksec = newsk->sk_security; |
| 4029 | ssec->peer_sid = isec->sid; | 4007 | sksec->peer_sid = isec->sid; |
| 4030 | err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid); | 4008 | err = security_sid_mls_copy(other_isec->sid, sksec->peer_sid, &sksec->sid); |
| 4031 | 4009 | ||
| 4032 | return err; | 4010 | return err; |
| 4033 | } | 4011 | } |
| @@ -4190,7 +4168,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op | |||
| 4190 | int err = 0; | 4168 | int err = 0; |
| 4191 | char *scontext; | 4169 | char *scontext; |
| 4192 | u32 scontext_len; | 4170 | u32 scontext_len; |
| 4193 | struct sk_security_struct *ssec; | 4171 | struct sk_security_struct *sksec; |
| 4194 | struct inode_security_struct *isec; | 4172 | struct inode_security_struct *isec; |
| 4195 | u32 peer_sid = SECSID_NULL; | 4173 | u32 peer_sid = SECSID_NULL; |
| 4196 | 4174 | ||
| @@ -4198,8 +4176,8 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op | |||
| 4198 | 4176 | ||
| 4199 | if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET || | 4177 | if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET || |
| 4200 | isec->sclass == SECCLASS_TCP_SOCKET) { | 4178 | isec->sclass == SECCLASS_TCP_SOCKET) { |
| 4201 | ssec = sock->sk->sk_security; | 4179 | sksec = sock->sk->sk_security; |
| 4202 | peer_sid = ssec->peer_sid; | 4180 | peer_sid = sksec->peer_sid; |
| 4203 | } | 4181 | } |
| 4204 | if (peer_sid == SECSID_NULL) { | 4182 | if (peer_sid == SECSID_NULL) { |
| 4205 | err = -ENOPROTOOPT; | 4183 | err = -ENOPROTOOPT; |
| @@ -4266,14 +4244,14 @@ static void selinux_sk_free_security(struct sock *sk) | |||
| 4266 | 4244 | ||
| 4267 | static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) | 4245 | static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) |
| 4268 | { | 4246 | { |
| 4269 | struct sk_security_struct *ssec = sk->sk_security; | 4247 | struct sk_security_struct *sksec = sk->sk_security; |
| 4270 | struct sk_security_struct *newssec = newsk->sk_security; | 4248 | struct sk_security_struct *newsksec = newsk->sk_security; |
| 4271 | 4249 | ||
| 4272 | newssec->sid = ssec->sid; | 4250 | newsksec->sid = sksec->sid; |
| 4273 | newssec->peer_sid = ssec->peer_sid; | 4251 | newsksec->peer_sid = sksec->peer_sid; |
| 4274 | newssec->sclass = ssec->sclass; | 4252 | newsksec->sclass = sksec->sclass; |
| 4275 | 4253 | ||
| 4276 | selinux_netlbl_sk_security_reset(newssec); | 4254 | selinux_netlbl_sk_security_reset(newsksec); |
| 4277 | } | 4255 | } |
| 4278 | 4256 | ||
| 4279 | static void selinux_sk_getsecid(struct sock *sk, u32 *secid) | 4257 | static void selinux_sk_getsecid(struct sock *sk, u32 *secid) |
| @@ -5662,6 +5640,8 @@ static __init int selinux_init(void) | |||
| 5662 | /* Set the security state for the initial task. */ | 5640 | /* Set the security state for the initial task. */ |
| 5663 | cred_init_security(); | 5641 | cred_init_security(); |
| 5664 | 5642 | ||
| 5643 | default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC); | ||
| 5644 | |||
| 5665 | sel_inode_cache = kmem_cache_create("selinux_inode_security", | 5645 | sel_inode_cache = kmem_cache_create("selinux_inode_security", |
| 5666 | sizeof(struct inode_security_struct), | 5646 | sizeof(struct inode_security_struct), |
| 5667 | 0, SLAB_PANIC, NULL); | 5647 | 0, SLAB_PANIC, NULL); |
| @@ -5678,35 +5658,18 @@ static __init int selinux_init(void) | |||
| 5678 | return 0; | 5658 | return 0; |
| 5679 | } | 5659 | } |
| 5680 | 5660 | ||
| 5661 | static void delayed_superblock_init(struct super_block *sb, void *unused) | ||
| 5662 | { | ||
| 5663 | superblock_doinit(sb, NULL); | ||
| 5664 | } | ||
| 5665 | |||
| 5681 | void selinux_complete_init(void) | 5666 | void selinux_complete_init(void) |
| 5682 | { | 5667 | { |
| 5683 | printk(KERN_DEBUG "SELinux: Completing initialization.\n"); | 5668 | printk(KERN_DEBUG "SELinux: Completing initialization.\n"); |
| 5684 | 5669 | ||
| 5685 | /* Set up any superblocks initialized prior to the policy load. */ | 5670 | /* Set up any superblocks initialized prior to the policy load. */ |
| 5686 | printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n"); | 5671 | printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n"); |
| 5687 | spin_lock(&sb_lock); | 5672 | iterate_supers(delayed_superblock_init, NULL); |
| 5688 | spin_lock(&sb_security_lock); | ||
| 5689 | next_sb: | ||
| 5690 | if (!list_empty(&superblock_security_head)) { | ||
| 5691 | struct superblock_security_struct *sbsec = | ||
| 5692 | list_entry(superblock_security_head.next, | ||
| 5693 | struct superblock_security_struct, | ||
| 5694 | list); | ||
| 5695 | struct super_block *sb = sbsec->sb; | ||
| 5696 | sb->s_count++; | ||
| 5697 | spin_unlock(&sb_security_lock); | ||
| 5698 | spin_unlock(&sb_lock); | ||
| 5699 | down_read(&sb->s_umount); | ||
| 5700 | if (sb->s_root) | ||
| 5701 | superblock_doinit(sb, NULL); | ||
| 5702 | drop_super(sb); | ||
| 5703 | spin_lock(&sb_lock); | ||
| 5704 | spin_lock(&sb_security_lock); | ||
| 5705 | list_del_init(&sbsec->list); | ||
| 5706 | goto next_sb; | ||
| 5707 | } | ||
| 5708 | spin_unlock(&sb_security_lock); | ||
| 5709 | spin_unlock(&sb_lock); | ||
| 5710 | } | 5673 | } |
| 5711 | 5674 | ||
| 5712 | /* SELinux requires early initialization in order to label | 5675 | /* SELinux requires early initialization in order to label |
diff --git a/security/selinux/include/initial_sid_to_string.h b/security/selinux/include/initial_sid_to_string.h index d4fac82793ae..a59b64e3fd02 100644 --- a/security/selinux/include/initial_sid_to_string.h +++ b/security/selinux/include/initial_sid_to_string.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* This file is automatically generated. Do not edit. */ | 1 | /* This file is automatically generated. Do not edit. */ |
| 2 | static char *initial_sid_to_string[] = | 2 | static const char *initial_sid_to_string[] = |
| 3 | { | 3 | { |
| 4 | "null", | 4 | "null", |
| 5 | "kernel", | 5 | "kernel", |
diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 8d7384280a7a..cf2f628e6e28 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h | |||
| @@ -42,8 +42,8 @@ void selinux_netlbl_cache_invalidate(void); | |||
| 42 | 42 | ||
| 43 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); | 43 | void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); |
| 44 | 44 | ||
| 45 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); | 45 | void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec); |
| 46 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec); | 46 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec); |
| 47 | 47 | ||
| 48 | int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, | 48 | int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, |
| 49 | u16 family, | 49 | u16 family, |
| @@ -79,13 +79,13 @@ static inline void selinux_netlbl_err(struct sk_buff *skb, | |||
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static inline void selinux_netlbl_sk_security_free( | 81 | static inline void selinux_netlbl_sk_security_free( |
| 82 | struct sk_security_struct *ssec) | 82 | struct sk_security_struct *sksec) |
| 83 | { | 83 | { |
| 84 | return; | 84 | return; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | static inline void selinux_netlbl_sk_security_reset( | 87 | static inline void selinux_netlbl_sk_security_reset( |
| 88 | struct sk_security_struct *ssec) | 88 | struct sk_security_struct *sksec) |
| 89 | { | 89 | { |
| 90 | return; | 90 | return; |
| 91 | } | 91 | } |
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index c4e062336ef3..26c7eee1c309 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
| @@ -55,7 +55,6 @@ struct file_security_struct { | |||
| 55 | 55 | ||
| 56 | struct superblock_security_struct { | 56 | struct superblock_security_struct { |
| 57 | struct super_block *sb; /* back pointer to sb object */ | 57 | struct super_block *sb; /* back pointer to sb object */ |
| 58 | struct list_head list; /* list of superblock_security_struct */ | ||
| 59 | u32 sid; /* SID of file system superblock */ | 58 | u32 sid; /* SID of file system superblock */ |
| 60 | u32 def_sid; /* default SID for labeling */ | 59 | u32 def_sid; /* default SID for labeling */ |
| 61 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ | 60 | u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ |
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 628da72ee763..1c2fc46544bf 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c | |||
| @@ -132,21 +132,21 @@ void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) | |||
| 132 | 132 | ||
| 133 | /** | 133 | /** |
| 134 | * selinux_netlbl_sk_security_free - Free the NetLabel fields | 134 | * selinux_netlbl_sk_security_free - Free the NetLabel fields |
| 135 | * @sssec: the sk_security_struct | 135 | * @sksec: the sk_security_struct |
| 136 | * | 136 | * |
| 137 | * Description: | 137 | * Description: |
| 138 | * Free all of the memory in the NetLabel fields of a sk_security_struct. | 138 | * Free all of the memory in the NetLabel fields of a sk_security_struct. |
| 139 | * | 139 | * |
| 140 | */ | 140 | */ |
| 141 | void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) | 141 | void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec) |
| 142 | { | 142 | { |
| 143 | if (ssec->nlbl_secattr != NULL) | 143 | if (sksec->nlbl_secattr != NULL) |
| 144 | netlbl_secattr_free(ssec->nlbl_secattr); | 144 | netlbl_secattr_free(sksec->nlbl_secattr); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | /** | 147 | /** |
| 148 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields | 148 | * selinux_netlbl_sk_security_reset - Reset the NetLabel fields |
| 149 | * @ssec: the sk_security_struct | 149 | * @sksec: the sk_security_struct |
| 150 | * @family: the socket family | 150 | * @family: the socket family |
| 151 | * | 151 | * |
| 152 | * Description: | 152 | * Description: |
| @@ -154,9 +154,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) | |||
| 154 | * The caller is responsibile for all the NetLabel sk_security_struct locking. | 154 | * The caller is responsibile for all the NetLabel sk_security_struct locking. |
| 155 | * | 155 | * |
| 156 | */ | 156 | */ |
| 157 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec) | 157 | void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec) |
| 158 | { | 158 | { |
| 159 | ssec->nlbl_state = NLBL_UNSET; | 159 | sksec->nlbl_state = NLBL_UNSET; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | /** | 162 | /** |
diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c index 0e147b6914ad..36ac257cec9a 100644 --- a/security/selinux/netlink.c +++ b/security/selinux/netlink.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 15 | #include <linux/stddef.h> | 15 | #include <linux/stddef.h> |
| 16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| 17 | #include <linux/list.h> | ||
| 18 | #include <linux/skbuff.h> | 17 | #include <linux/skbuff.h> |
| 19 | #include <linux/netlink.h> | 18 | #include <linux/netlink.h> |
| 20 | #include <linux/selinux_netlink.h> | 19 | #include <linux/selinux_netlink.h> |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index dd7cc6de77f9..75ec0c6ebacd 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
| @@ -11,7 +11,6 @@ | |||
| 11 | */ | 11 | */ |
| 12 | #include <linux/types.h> | 12 | #include <linux/types.h> |
| 13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/netlink.h> | 14 | #include <linux/netlink.h> |
| 16 | #include <linux/rtnetlink.h> | 15 | #include <linux/rtnetlink.h> |
| 17 | #include <linux/if.h> | 16 | #include <linux/if.h> |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index cd191bbec03c..0293843f7eda 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -503,11 +503,11 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
| 503 | return length; | 503 | return length; |
| 504 | 504 | ||
| 505 | length = -ENOMEM; | 505 | length = -ENOMEM; |
| 506 | scon = kzalloc(size+1, GFP_KERNEL); | 506 | scon = kzalloc(size + 1, GFP_KERNEL); |
| 507 | if (!scon) | 507 | if (!scon) |
| 508 | return length; | 508 | return length; |
| 509 | 509 | ||
| 510 | tcon = kzalloc(size+1, GFP_KERNEL); | 510 | tcon = kzalloc(size + 1, GFP_KERNEL); |
| 511 | if (!tcon) | 511 | if (!tcon) |
| 512 | goto out; | 512 | goto out; |
| 513 | 513 | ||
| @@ -515,10 +515,10 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
| 515 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 515 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
| 516 | goto out2; | 516 | goto out2; |
| 517 | 517 | ||
| 518 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); | 518 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
| 519 | if (length < 0) | 519 | if (length < 0) |
| 520 | goto out2; | 520 | goto out2; |
| 521 | length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); | 521 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
| 522 | if (length < 0) | 522 | if (length < 0) |
| 523 | goto out2; | 523 | goto out2; |
| 524 | 524 | ||
| @@ -550,11 +550,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | |||
| 550 | return length; | 550 | return length; |
| 551 | 551 | ||
| 552 | length = -ENOMEM; | 552 | length = -ENOMEM; |
| 553 | scon = kzalloc(size+1, GFP_KERNEL); | 553 | scon = kzalloc(size + 1, GFP_KERNEL); |
| 554 | if (!scon) | 554 | if (!scon) |
| 555 | return length; | 555 | return length; |
| 556 | 556 | ||
| 557 | tcon = kzalloc(size+1, GFP_KERNEL); | 557 | tcon = kzalloc(size + 1, GFP_KERNEL); |
| 558 | if (!tcon) | 558 | if (!tcon) |
| 559 | goto out; | 559 | goto out; |
| 560 | 560 | ||
| @@ -562,10 +562,10 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | |||
| 562 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 562 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
| 563 | goto out2; | 563 | goto out2; |
| 564 | 564 | ||
| 565 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); | 565 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
| 566 | if (length < 0) | 566 | if (length < 0) |
| 567 | goto out2; | 567 | goto out2; |
| 568 | length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); | 568 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
| 569 | if (length < 0) | 569 | if (length < 0) |
| 570 | goto out2; | 570 | goto out2; |
| 571 | 571 | ||
| @@ -609,11 +609,11 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) | |||
| 609 | return length; | 609 | return length; |
| 610 | 610 | ||
| 611 | length = -ENOMEM; | 611 | length = -ENOMEM; |
| 612 | scon = kzalloc(size+1, GFP_KERNEL); | 612 | scon = kzalloc(size + 1, GFP_KERNEL); |
| 613 | if (!scon) | 613 | if (!scon) |
| 614 | return length; | 614 | return length; |
| 615 | 615 | ||
| 616 | tcon = kzalloc(size+1, GFP_KERNEL); | 616 | tcon = kzalloc(size + 1, GFP_KERNEL); |
| 617 | if (!tcon) | 617 | if (!tcon) |
| 618 | goto out; | 618 | goto out; |
| 619 | 619 | ||
| @@ -621,10 +621,10 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) | |||
| 621 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 621 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
| 622 | goto out2; | 622 | goto out2; |
| 623 | 623 | ||
| 624 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); | 624 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
| 625 | if (length < 0) | 625 | if (length < 0) |
| 626 | goto out2; | 626 | goto out2; |
| 627 | length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); | 627 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
| 628 | if (length < 0) | 628 | if (length < 0) |
| 629 | goto out2; | 629 | goto out2; |
| 630 | 630 | ||
| @@ -666,11 +666,11 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) | |||
| 666 | return length; | 666 | return length; |
| 667 | 667 | ||
| 668 | length = -ENOMEM; | 668 | length = -ENOMEM; |
| 669 | con = kzalloc(size+1, GFP_KERNEL); | 669 | con = kzalloc(size + 1, GFP_KERNEL); |
| 670 | if (!con) | 670 | if (!con) |
| 671 | return length; | 671 | return length; |
| 672 | 672 | ||
| 673 | user = kzalloc(size+1, GFP_KERNEL); | 673 | user = kzalloc(size + 1, GFP_KERNEL); |
| 674 | if (!user) | 674 | if (!user) |
| 675 | goto out; | 675 | goto out; |
| 676 | 676 | ||
| @@ -678,7 +678,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) | |||
| 678 | if (sscanf(buf, "%s %s", con, user) != 2) | 678 | if (sscanf(buf, "%s %s", con, user) != 2) |
| 679 | goto out2; | 679 | goto out2; |
| 680 | 680 | ||
| 681 | length = security_context_to_sid(con, strlen(con)+1, &sid); | 681 | length = security_context_to_sid(con, strlen(con) + 1, &sid); |
| 682 | if (length < 0) | 682 | if (length < 0) |
| 683 | goto out2; | 683 | goto out2; |
| 684 | 684 | ||
| @@ -727,11 +727,11 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) | |||
| 727 | return length; | 727 | return length; |
| 728 | 728 | ||
| 729 | length = -ENOMEM; | 729 | length = -ENOMEM; |
| 730 | scon = kzalloc(size+1, GFP_KERNEL); | 730 | scon = kzalloc(size + 1, GFP_KERNEL); |
| 731 | if (!scon) | 731 | if (!scon) |
| 732 | return length; | 732 | return length; |
| 733 | 733 | ||
| 734 | tcon = kzalloc(size+1, GFP_KERNEL); | 734 | tcon = kzalloc(size + 1, GFP_KERNEL); |
| 735 | if (!tcon) | 735 | if (!tcon) |
| 736 | goto out; | 736 | goto out; |
| 737 | 737 | ||
| @@ -739,10 +739,10 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) | |||
| 739 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 739 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
| 740 | goto out2; | 740 | goto out2; |
| 741 | 741 | ||
| 742 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); | 742 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
| 743 | if (length < 0) | 743 | if (length < 0) |
| 744 | goto out2; | 744 | goto out2; |
| 745 | length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); | 745 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
| 746 | if (length < 0) | 746 | if (length < 0) |
| 747 | goto out2; | 747 | goto out2; |
| 748 | 748 | ||
| @@ -1401,7 +1401,7 @@ static int sel_make_perm_files(char *objclass, int classvalue, | |||
| 1401 | } | 1401 | } |
| 1402 | inode->i_fop = &sel_perm_ops; | 1402 | inode->i_fop = &sel_perm_ops; |
| 1403 | /* i+1 since perm values are 1-indexed */ | 1403 | /* i+1 since perm values are 1-indexed */ |
| 1404 | inode->i_ino = sel_perm_to_ino(classvalue, i+1); | 1404 | inode->i_ino = sel_perm_to_ino(classvalue, i + 1); |
| 1405 | d_add(dentry, inode); | 1405 | d_add(dentry, inode); |
| 1406 | } | 1406 | } |
| 1407 | 1407 | ||
| @@ -1489,7 +1489,7 @@ static int sel_make_classes(void) | |||
| 1489 | goto out; | 1489 | goto out; |
| 1490 | 1490 | ||
| 1491 | /* +2 since classes are 1-indexed */ | 1491 | /* +2 since classes are 1-indexed */ |
| 1492 | last_class_ino = sel_class_to_ino(nclasses+2); | 1492 | last_class_ino = sel_class_to_ino(nclasses + 2); |
| 1493 | 1493 | ||
| 1494 | for (i = 0; i < nclasses; i++) { | 1494 | for (i = 0; i < nclasses; i++) { |
| 1495 | struct dentry *class_name_dir; | 1495 | struct dentry *class_name_dir; |
| @@ -1506,7 +1506,7 @@ static int sel_make_classes(void) | |||
| 1506 | goto out1; | 1506 | goto out1; |
| 1507 | 1507 | ||
| 1508 | /* i+1 since class values are 1-indexed */ | 1508 | /* i+1 since class values are 1-indexed */ |
| 1509 | rc = sel_make_class_dir_entries(classes[i], i+1, | 1509 | rc = sel_make_class_dir_entries(classes[i], i + 1, |
| 1510 | class_name_dir); | 1510 | class_name_dir); |
| 1511 | if (rc) | 1511 | if (rc) |
| 1512 | goto out1; | 1512 | goto out1; |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 372b773f8210..b4eff7a60c50 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
| @@ -255,7 +255,7 @@ int mls_context_to_sid(struct policydb *pol, | |||
| 255 | 255 | ||
| 256 | if (!pol->mls_enabled) { | 256 | if (!pol->mls_enabled) { |
| 257 | if (def_sid != SECSID_NULL && oldc) | 257 | if (def_sid != SECSID_NULL && oldc) |
| 258 | *scontext += strlen(*scontext)+1; | 258 | *scontext += strlen(*scontext) + 1; |
| 259 | return 0; | 259 | return 0; |
| 260 | } | 260 | } |
| 261 | 261 | ||
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 23c6e53c102c..c57802a164d5 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -40,7 +40,7 @@ | |||
| 40 | #define _DEBUG_HASHES | 40 | #define _DEBUG_HASHES |
| 41 | 41 | ||
| 42 | #ifdef DEBUG_HASHES | 42 | #ifdef DEBUG_HASHES |
| 43 | static char *symtab_name[SYM_NUM] = { | 43 | static const char *symtab_name[SYM_NUM] = { |
| 44 | "common prefixes", | 44 | "common prefixes", |
| 45 | "classes", | 45 | "classes", |
| 46 | "roles", | 46 | "roles", |
| @@ -156,12 +156,11 @@ static int roles_init(struct policydb *p) | |||
| 156 | rc = -EINVAL; | 156 | rc = -EINVAL; |
| 157 | goto out_free_role; | 157 | goto out_free_role; |
| 158 | } | 158 | } |
| 159 | key = kmalloc(strlen(OBJECT_R)+1, GFP_KERNEL); | 159 | key = kstrdup(OBJECT_R, GFP_KERNEL); |
| 160 | if (!key) { | 160 | if (!key) { |
| 161 | rc = -ENOMEM; | 161 | rc = -ENOMEM; |
| 162 | goto out_free_role; | 162 | goto out_free_role; |
| 163 | } | 163 | } |
| 164 | strcpy(key, OBJECT_R); | ||
| 165 | rc = hashtab_insert(p->p_roles.table, key, role); | 164 | rc = hashtab_insert(p->p_roles.table, key, role); |
| 166 | if (rc) | 165 | if (rc) |
| 167 | goto out_free_key; | 166 | goto out_free_key; |
| @@ -2195,7 +2194,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
| 2195 | rangetr_hash_eval(p->range_tr); | 2194 | rangetr_hash_eval(p->range_tr); |
| 2196 | } | 2195 | } |
| 2197 | 2196 | ||
| 2198 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); | 2197 | p->type_attr_map = kmalloc(p->p_types.nprim * sizeof(struct ebitmap), GFP_KERNEL); |
| 2199 | if (!p->type_attr_map) | 2198 | if (!p->type_attr_map) |
| 2200 | goto bad; | 2199 | goto bad; |
| 2201 | 2200 | ||
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index cf27b3ee1a95..1de60ce90d9a 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -274,15 +274,15 @@ static int constraint_expr_eval(struct context *scontext, | |||
| 274 | case CEXPR_AND: | 274 | case CEXPR_AND: |
| 275 | BUG_ON(sp < 1); | 275 | BUG_ON(sp < 1); |
| 276 | sp--; | 276 | sp--; |
| 277 | s[sp] &= s[sp+1]; | 277 | s[sp] &= s[sp + 1]; |
| 278 | break; | 278 | break; |
| 279 | case CEXPR_OR: | 279 | case CEXPR_OR: |
| 280 | BUG_ON(sp < 1); | 280 | BUG_ON(sp < 1); |
| 281 | sp--; | 281 | sp--; |
| 282 | s[sp] |= s[sp+1]; | 282 | s[sp] |= s[sp + 1]; |
| 283 | break; | 283 | break; |
| 284 | case CEXPR_ATTR: | 284 | case CEXPR_ATTR: |
| 285 | if (sp == (CEXPR_MAXDEPTH-1)) | 285 | if (sp == (CEXPR_MAXDEPTH - 1)) |
| 286 | return 0; | 286 | return 0; |
| 287 | switch (e->attr) { | 287 | switch (e->attr) { |
| 288 | case CEXPR_USER: | 288 | case CEXPR_USER: |
| @@ -1216,7 +1216,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, | |||
| 1216 | *sid = SECSID_NULL; | 1216 | *sid = SECSID_NULL; |
| 1217 | 1217 | ||
| 1218 | /* Copy the string so that we can modify the copy as we parse it. */ | 1218 | /* Copy the string so that we can modify the copy as we parse it. */ |
| 1219 | scontext2 = kmalloc(scontext_len+1, gfp_flags); | 1219 | scontext2 = kmalloc(scontext_len + 1, gfp_flags); |
| 1220 | if (!scontext2) | 1220 | if (!scontext2) |
| 1221 | return -ENOMEM; | 1221 | return -ENOMEM; |
| 1222 | memcpy(scontext2, scontext, scontext_len); | 1222 | memcpy(scontext2, scontext, scontext_len); |
| @@ -1760,22 +1760,28 @@ int security_load_policy(void *data, size_t len) | |||
| 1760 | 1760 | ||
| 1761 | if (!ss_initialized) { | 1761 | if (!ss_initialized) { |
| 1762 | avtab_cache_init(); | 1762 | avtab_cache_init(); |
| 1763 | if (policydb_read(&policydb, fp)) { | 1763 | rc = policydb_read(&policydb, fp); |
| 1764 | if (rc) { | ||
| 1764 | avtab_cache_destroy(); | 1765 | avtab_cache_destroy(); |
| 1765 | return -EINVAL; | 1766 | return rc; |
| 1766 | } | 1767 | } |
| 1767 | if (selinux_set_mapping(&policydb, secclass_map, | 1768 | |
| 1768 | ¤t_mapping, | 1769 | rc = selinux_set_mapping(&policydb, secclass_map, |
| 1769 | ¤t_mapping_size)) { | 1770 | ¤t_mapping, |
| 1771 | ¤t_mapping_size); | ||
| 1772 | if (rc) { | ||
| 1770 | policydb_destroy(&policydb); | 1773 | policydb_destroy(&policydb); |
| 1771 | avtab_cache_destroy(); | 1774 | avtab_cache_destroy(); |
| 1772 | return -EINVAL; | 1775 | return rc; |
| 1773 | } | 1776 | } |
| 1774 | if (policydb_load_isids(&policydb, &sidtab)) { | 1777 | |
| 1778 | rc = policydb_load_isids(&policydb, &sidtab); | ||
| 1779 | if (rc) { | ||
| 1775 | policydb_destroy(&policydb); | 1780 | policydb_destroy(&policydb); |
| 1776 | avtab_cache_destroy(); | 1781 | avtab_cache_destroy(); |
| 1777 | return -EINVAL; | 1782 | return rc; |
| 1778 | } | 1783 | } |
| 1784 | |||
| 1779 | security_load_policycaps(); | 1785 | security_load_policycaps(); |
| 1780 | ss_initialized = 1; | 1786 | ss_initialized = 1; |
| 1781 | seqno = ++latest_granting; | 1787 | seqno = ++latest_granting; |
| @@ -1791,8 +1797,9 @@ int security_load_policy(void *data, size_t len) | |||
| 1791 | sidtab_hash_eval(&sidtab, "sids"); | 1797 | sidtab_hash_eval(&sidtab, "sids"); |
| 1792 | #endif | 1798 | #endif |
| 1793 | 1799 | ||
| 1794 | if (policydb_read(&newpolicydb, fp)) | 1800 | rc = policydb_read(&newpolicydb, fp); |
| 1795 | return -EINVAL; | 1801 | if (rc) |
| 1802 | return rc; | ||
| 1796 | 1803 | ||
| 1797 | /* If switching between different policy types, log MLS status */ | 1804 | /* If switching between different policy types, log MLS status */ |
| 1798 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) | 1805 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) |
| @@ -1807,8 +1814,8 @@ int security_load_policy(void *data, size_t len) | |||
| 1807 | return rc; | 1814 | return rc; |
| 1808 | } | 1815 | } |
| 1809 | 1816 | ||
| 1810 | if (selinux_set_mapping(&newpolicydb, secclass_map, | 1817 | rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size); |
| 1811 | &map, &map_size)) | 1818 | if (rc) |
| 1812 | goto err; | 1819 | goto err; |
| 1813 | 1820 | ||
| 1814 | rc = security_preserve_bools(&newpolicydb); | 1821 | rc = security_preserve_bools(&newpolicydb); |
| @@ -1819,10 +1826,10 @@ int security_load_policy(void *data, size_t len) | |||
| 1819 | 1826 | ||
| 1820 | /* Clone the SID table. */ | 1827 | /* Clone the SID table. */ |
| 1821 | sidtab_shutdown(&sidtab); | 1828 | sidtab_shutdown(&sidtab); |
| 1822 | if (sidtab_map(&sidtab, clone_sid, &newsidtab)) { | 1829 | |
| 1823 | rc = -ENOMEM; | 1830 | rc = sidtab_map(&sidtab, clone_sid, &newsidtab); |
| 1831 | if (rc) | ||
| 1824 | goto err; | 1832 | goto err; |
| 1825 | } | ||
| 1826 | 1833 | ||
| 1827 | /* | 1834 | /* |
| 1828 | * Convert the internal representations of contexts | 1835 | * Convert the internal representations of contexts |
| @@ -2101,9 +2108,9 @@ int security_get_user_sids(u32 fromsid, | |||
| 2101 | 2108 | ||
| 2102 | ebitmap_for_each_positive_bit(&user->roles, rnode, i) { | 2109 | ebitmap_for_each_positive_bit(&user->roles, rnode, i) { |
| 2103 | role = policydb.role_val_to_struct[i]; | 2110 | role = policydb.role_val_to_struct[i]; |
| 2104 | usercon.role = i+1; | 2111 | usercon.role = i + 1; |
| 2105 | ebitmap_for_each_positive_bit(&role->types, tnode, j) { | 2112 | ebitmap_for_each_positive_bit(&role->types, tnode, j) { |
| 2106 | usercon.type = j+1; | 2113 | usercon.type = j + 1; |
| 2107 | 2114 | ||
| 2108 | if (mls_setup_user_range(fromcon, user, &usercon)) | 2115 | if (mls_setup_user_range(fromcon, user, &usercon)) |
| 2109 | continue; | 2116 | continue; |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index fdfeaa2f28ec..0f2fc480fc61 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -19,7 +19,6 @@ | |||
| 19 | #include <linux/pagemap.h> | 19 | #include <linux/pagemap.h> |
| 20 | #include <linux/mount.h> | 20 | #include <linux/mount.h> |
| 21 | #include <linux/stat.h> | 21 | #include <linux/stat.h> |
| 22 | #include <linux/ext2_fs.h> | ||
| 23 | #include <linux/kd.h> | 22 | #include <linux/kd.h> |
| 24 | #include <asm/ioctls.h> | 23 | #include <asm/ioctls.h> |
| 25 | #include <linux/ip.h> | 24 | #include <linux/ip.h> |
| @@ -1119,15 +1118,6 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, | |||
| 1119 | } | 1118 | } |
| 1120 | 1119 | ||
| 1121 | /** | 1120 | /** |
| 1122 | * smack_cred_commit - commit new credentials | ||
| 1123 | * @new: the new credentials | ||
| 1124 | * @old: the original credentials | ||
| 1125 | */ | ||
| 1126 | static void smack_cred_commit(struct cred *new, const struct cred *old) | ||
| 1127 | { | ||
| 1128 | } | ||
| 1129 | |||
| 1130 | /** | ||
| 1131 | * smack_cred_transfer - Transfer the old credentials to the new credentials | 1121 | * smack_cred_transfer - Transfer the old credentials to the new credentials |
| 1132 | * @new: the new credentials | 1122 | * @new: the new credentials |
| 1133 | * @old: the original credentials | 1123 | * @old: the original credentials |
| @@ -3121,7 +3111,6 @@ struct security_operations smack_ops = { | |||
| 3121 | .cred_alloc_blank = smack_cred_alloc_blank, | 3111 | .cred_alloc_blank = smack_cred_alloc_blank, |
| 3122 | .cred_free = smack_cred_free, | 3112 | .cred_free = smack_cred_free, |
| 3123 | .cred_prepare = smack_cred_prepare, | 3113 | .cred_prepare = smack_cred_prepare, |
| 3124 | .cred_commit = smack_cred_commit, | ||
| 3125 | .cred_transfer = smack_cred_transfer, | 3114 | .cred_transfer = smack_cred_transfer, |
| 3126 | .kernel_act_as = smack_kernel_act_as, | 3115 | .kernel_act_as = smack_kernel_act_as, |
| 3127 | .kernel_create_files_as = smack_kernel_create_files_as, | 3116 | .kernel_create_files_as = smack_kernel_create_files_as, |
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 60a9e2002da1..4fb39030f6bd 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
| @@ -1 +1 @@ | |||
| obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o | obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 975c45d88baa..b5dbdc9ff73c 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
| @@ -76,6 +76,49 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, | |||
| 76 | const int buffer_len); | 76 | const int buffer_len); |
| 77 | 77 | ||
| 78 | /** | 78 | /** |
| 79 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. | ||
| 80 | * | ||
| 81 | * @filename: Name or name group. | ||
| 82 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
| 83 | * | ||
| 84 | * Returns true on success, false otherwise. | ||
| 85 | */ | ||
| 86 | bool tomoyo_parse_name_union(const char *filename, | ||
| 87 | struct tomoyo_name_union *ptr) | ||
| 88 | { | ||
| 89 | if (!tomoyo_is_correct_path(filename, 0, 0, 0)) | ||
| 90 | return false; | ||
| 91 | if (filename[0] == '@') { | ||
| 92 | ptr->group = tomoyo_get_path_group(filename + 1); | ||
| 93 | ptr->is_group = true; | ||
| 94 | return ptr->group != NULL; | ||
| 95 | } | ||
| 96 | ptr->filename = tomoyo_get_name(filename); | ||
| 97 | ptr->is_group = false; | ||
| 98 | return ptr->filename != NULL; | ||
| 99 | } | ||
| 100 | |||
| 101 | /** | ||
| 102 | * tomoyo_print_name_union - Print a tomoyo_name_union. | ||
| 103 | * | ||
| 104 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
| 105 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
| 106 | * | ||
| 107 | * Returns true on success, false otherwise. | ||
| 108 | */ | ||
| 109 | static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head, | ||
| 110 | const struct tomoyo_name_union *ptr) | ||
| 111 | { | ||
| 112 | int pos = head->read_avail; | ||
| 113 | if (pos && head->read_buf[pos - 1] == ' ') | ||
| 114 | head->read_avail--; | ||
| 115 | if (ptr->is_group) | ||
| 116 | return tomoyo_io_printf(head, " @%s", | ||
| 117 | ptr->group->group_name->name); | ||
| 118 | return tomoyo_io_printf(head, " %s", ptr->filename->name); | ||
| 119 | } | ||
| 120 | |||
| 121 | /** | ||
| 79 | * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. | 122 | * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. |
| 80 | * | 123 | * |
| 81 | * @str: Pointer to the string. | 124 | * @str: Pointer to the string. |
| @@ -172,6 +215,33 @@ static void tomoyo_normalize_line(unsigned char *buffer) | |||
| 172 | } | 215 | } |
| 173 | 216 | ||
| 174 | /** | 217 | /** |
| 218 | * tomoyo_tokenize - Tokenize string. | ||
| 219 | * | ||
| 220 | * @buffer: The line to tokenize. | ||
| 221 | * @w: Pointer to "char *". | ||
| 222 | * @size: Sizeof @w . | ||
| 223 | * | ||
| 224 | * Returns true on success, false otherwise. | ||
| 225 | */ | ||
| 226 | bool tomoyo_tokenize(char *buffer, char *w[], size_t size) | ||
| 227 | { | ||
| 228 | int count = size / sizeof(char *); | ||
| 229 | int i; | ||
| 230 | for (i = 0; i < count; i++) | ||
| 231 | w[i] = ""; | ||
| 232 | for (i = 0; i < count; i++) { | ||
| 233 | char *cp = strchr(buffer, ' '); | ||
| 234 | if (cp) | ||
| 235 | *cp = '\0'; | ||
| 236 | w[i] = buffer; | ||
| 237 | if (!cp) | ||
| 238 | break; | ||
| 239 | buffer = cp + 1; | ||
| 240 | } | ||
| 241 | return i < count || !*buffer; | ||
| 242 | } | ||
| 243 | |||
| 244 | /** | ||
| 175 | * tomoyo_is_correct_path - Validate a pathname. | 245 | * tomoyo_is_correct_path - Validate a pathname. |
| 176 | * @filename: The pathname to check. | 246 | * @filename: The pathname to check. |
| 177 | * @start_type: Should the pathname start with '/'? | 247 | * @start_type: Should the pathname start with '/'? |
| @@ -874,17 +944,17 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) | |||
| 874 | static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | 944 | static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned |
| 875 | int profile) | 945 | int profile) |
| 876 | { | 946 | { |
| 877 | static DEFINE_MUTEX(lock); | ||
| 878 | struct tomoyo_profile *ptr = NULL; | 947 | struct tomoyo_profile *ptr = NULL; |
| 879 | int i; | 948 | int i; |
| 880 | 949 | ||
| 881 | if (profile >= TOMOYO_MAX_PROFILES) | 950 | if (profile >= TOMOYO_MAX_PROFILES) |
| 882 | return NULL; | 951 | return NULL; |
| 883 | mutex_lock(&lock); | 952 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 953 | return NULL; | ||
| 884 | ptr = tomoyo_profile_ptr[profile]; | 954 | ptr = tomoyo_profile_ptr[profile]; |
| 885 | if (ptr) | 955 | if (ptr) |
| 886 | goto ok; | 956 | goto ok; |
| 887 | ptr = kmalloc(sizeof(*ptr), GFP_KERNEL); | 957 | ptr = kmalloc(sizeof(*ptr), GFP_NOFS); |
| 888 | if (!tomoyo_memory_ok(ptr)) { | 958 | if (!tomoyo_memory_ok(ptr)) { |
| 889 | kfree(ptr); | 959 | kfree(ptr); |
| 890 | ptr = NULL; | 960 | ptr = NULL; |
| @@ -895,7 +965,7 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | |||
| 895 | mb(); /* Avoid out-of-order execution. */ | 965 | mb(); /* Avoid out-of-order execution. */ |
| 896 | tomoyo_profile_ptr[profile] = ptr; | 966 | tomoyo_profile_ptr[profile] = ptr; |
| 897 | ok: | 967 | ok: |
| 898 | mutex_unlock(&lock); | 968 | mutex_unlock(&tomoyo_policy_lock); |
| 899 | return ptr; | 969 | return ptr; |
| 900 | } | 970 | } |
| 901 | 971 | ||
| @@ -1071,44 +1141,42 @@ LIST_HEAD(tomoyo_policy_manager_list); | |||
| 1071 | static int tomoyo_update_manager_entry(const char *manager, | 1141 | static int tomoyo_update_manager_entry(const char *manager, |
| 1072 | const bool is_delete) | 1142 | const bool is_delete) |
| 1073 | { | 1143 | { |
| 1074 | struct tomoyo_policy_manager_entry *entry = NULL; | ||
| 1075 | struct tomoyo_policy_manager_entry *ptr; | 1144 | struct tomoyo_policy_manager_entry *ptr; |
| 1076 | const struct tomoyo_path_info *saved_manager; | 1145 | struct tomoyo_policy_manager_entry e = { }; |
| 1077 | int error = is_delete ? -ENOENT : -ENOMEM; | 1146 | int error = is_delete ? -ENOENT : -ENOMEM; |
| 1078 | bool is_domain = false; | ||
| 1079 | 1147 | ||
| 1080 | if (tomoyo_is_domain_def(manager)) { | 1148 | if (tomoyo_is_domain_def(manager)) { |
| 1081 | if (!tomoyo_is_correct_domain(manager)) | 1149 | if (!tomoyo_is_correct_domain(manager)) |
| 1082 | return -EINVAL; | 1150 | return -EINVAL; |
| 1083 | is_domain = true; | 1151 | e.is_domain = true; |
| 1084 | } else { | 1152 | } else { |
| 1085 | if (!tomoyo_is_correct_path(manager, 1, -1, -1)) | 1153 | if (!tomoyo_is_correct_path(manager, 1, -1, -1)) |
| 1086 | return -EINVAL; | 1154 | return -EINVAL; |
| 1087 | } | 1155 | } |
| 1088 | saved_manager = tomoyo_get_name(manager); | 1156 | e.manager = tomoyo_get_name(manager); |
| 1089 | if (!saved_manager) | 1157 | if (!e.manager) |
| 1090 | return -ENOMEM; | 1158 | return -ENOMEM; |
| 1091 | if (!is_delete) | 1159 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 1092 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 1160 | goto out; |
| 1093 | mutex_lock(&tomoyo_policy_lock); | ||
| 1094 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { | 1161 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { |
| 1095 | if (ptr->manager != saved_manager) | 1162 | if (ptr->manager != e.manager) |
| 1096 | continue; | 1163 | continue; |
| 1097 | ptr->is_deleted = is_delete; | 1164 | ptr->is_deleted = is_delete; |
| 1098 | error = 0; | 1165 | error = 0; |
| 1099 | break; | 1166 | break; |
| 1100 | } | 1167 | } |
| 1101 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 1168 | if (!is_delete && error) { |
| 1102 | entry->manager = saved_manager; | 1169 | struct tomoyo_policy_manager_entry *entry = |
| 1103 | saved_manager = NULL; | 1170 | tomoyo_commit_ok(&e, sizeof(e)); |
| 1104 | entry->is_domain = is_domain; | 1171 | if (entry) { |
| 1105 | list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list); | 1172 | list_add_tail_rcu(&entry->list, |
| 1106 | entry = NULL; | 1173 | &tomoyo_policy_manager_list); |
| 1107 | error = 0; | 1174 | error = 0; |
| 1175 | } | ||
| 1108 | } | 1176 | } |
| 1109 | mutex_unlock(&tomoyo_policy_lock); | 1177 | mutex_unlock(&tomoyo_policy_lock); |
| 1110 | tomoyo_put_name(saved_manager); | 1178 | out: |
| 1111 | kfree(entry); | 1179 | tomoyo_put_name(e.manager); |
| 1112 | return error; | 1180 | return error; |
| 1113 | } | 1181 | } |
| 1114 | 1182 | ||
| @@ -1287,7 +1355,8 @@ static int tomoyo_delete_domain(char *domainname) | |||
| 1287 | 1355 | ||
| 1288 | name.name = domainname; | 1356 | name.name = domainname; |
| 1289 | tomoyo_fill_path_info(&name); | 1357 | tomoyo_fill_path_info(&name); |
| 1290 | mutex_lock(&tomoyo_policy_lock); | 1358 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 1359 | return 0; | ||
| 1291 | /* Is there an active domain? */ | 1360 | /* Is there an active domain? */ |
| 1292 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 1361 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
| 1293 | /* Never delete tomoyo_kernel_domain */ | 1362 | /* Never delete tomoyo_kernel_domain */ |
| @@ -1369,23 +1438,20 @@ static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head, | |||
| 1369 | { | 1438 | { |
| 1370 | int pos; | 1439 | int pos; |
| 1371 | u8 bit; | 1440 | u8 bit; |
| 1372 | const char *atmark = ""; | ||
| 1373 | const char *filename; | ||
| 1374 | const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); | 1441 | const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); |
| 1375 | 1442 | ||
| 1376 | filename = ptr->filename->name; | ||
| 1377 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { | 1443 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
| 1378 | const char *msg; | ||
| 1379 | if (!(perm & (1 << bit))) | 1444 | if (!(perm & (1 << bit))) |
| 1380 | continue; | 1445 | continue; |
| 1381 | /* Print "read/write" instead of "read" and "write". */ | 1446 | /* Print "read/write" instead of "read" and "write". */ |
| 1382 | if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) | 1447 | if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) |
| 1383 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) | 1448 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) |
| 1384 | continue; | 1449 | continue; |
| 1385 | msg = tomoyo_path2keyword(bit); | ||
| 1386 | pos = head->read_avail; | 1450 | pos = head->read_avail; |
| 1387 | if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, | 1451 | if (!tomoyo_io_printf(head, "allow_%s ", |
| 1388 | atmark, filename)) | 1452 | tomoyo_path2keyword(bit)) || |
| 1453 | !tomoyo_print_name_union(head, &ptr->name) || | ||
| 1454 | !tomoyo_io_printf(head, "\n")) | ||
| 1389 | goto out; | 1455 | goto out; |
| 1390 | } | 1456 | } |
| 1391 | head->read_bit = 0; | 1457 | head->read_bit = 0; |
| @@ -1408,23 +1474,18 @@ static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head, | |||
| 1408 | struct tomoyo_path2_acl *ptr) | 1474 | struct tomoyo_path2_acl *ptr) |
| 1409 | { | 1475 | { |
| 1410 | int pos; | 1476 | int pos; |
| 1411 | const char *atmark1 = ""; | ||
| 1412 | const char *atmark2 = ""; | ||
| 1413 | const char *filename1; | ||
| 1414 | const char *filename2; | ||
| 1415 | const u8 perm = ptr->perm; | 1477 | const u8 perm = ptr->perm; |
| 1416 | u8 bit; | 1478 | u8 bit; |
| 1417 | 1479 | ||
| 1418 | filename1 = ptr->filename1->name; | ||
| 1419 | filename2 = ptr->filename2->name; | ||
| 1420 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { | 1480 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { |
| 1421 | const char *msg; | ||
| 1422 | if (!(perm & (1 << bit))) | 1481 | if (!(perm & (1 << bit))) |
| 1423 | continue; | 1482 | continue; |
| 1424 | msg = tomoyo_path22keyword(bit); | ||
| 1425 | pos = head->read_avail; | 1483 | pos = head->read_avail; |
| 1426 | if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, | 1484 | if (!tomoyo_io_printf(head, "allow_%s ", |
| 1427 | atmark1, filename1, atmark2, filename2)) | 1485 | tomoyo_path22keyword(bit)) || |
| 1486 | !tomoyo_print_name_union(head, &ptr->name1) || | ||
| 1487 | !tomoyo_print_name_union(head, &ptr->name2) || | ||
| 1488 | !tomoyo_io_printf(head, "\n")) | ||
| 1428 | goto out; | 1489 | goto out; |
| 1429 | } | 1490 | } |
| 1430 | head->read_bit = 0; | 1491 | head->read_bit = 0; |
| @@ -1687,6 +1748,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | |||
| 1687 | return tomoyo_write_pattern_policy(data, is_delete); | 1748 | return tomoyo_write_pattern_policy(data, is_delete); |
| 1688 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) | 1749 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) |
| 1689 | return tomoyo_write_no_rewrite_policy(data, is_delete); | 1750 | return tomoyo_write_no_rewrite_policy(data, is_delete); |
| 1751 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP)) | ||
| 1752 | return tomoyo_write_path_group_policy(data, is_delete); | ||
| 1690 | return -EINVAL; | 1753 | return -EINVAL; |
| 1691 | } | 1754 | } |
| 1692 | 1755 | ||
| @@ -1743,6 +1806,12 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) | |||
| 1743 | head->read_var2 = NULL; | 1806 | head->read_var2 = NULL; |
| 1744 | head->read_step = 9; | 1807 | head->read_step = 9; |
| 1745 | case 9: | 1808 | case 9: |
| 1809 | if (!tomoyo_read_path_group_policy(head)) | ||
| 1810 | break; | ||
| 1811 | head->read_var1 = NULL; | ||
| 1812 | head->read_var2 = NULL; | ||
| 1813 | head->read_step = 10; | ||
| 1814 | case 10: | ||
| 1746 | head->read_eof = true; | 1815 | head->read_eof = true; |
| 1747 | break; | 1816 | break; |
| 1748 | default: | 1817 | default: |
| @@ -1886,7 +1955,7 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | |||
| 1886 | */ | 1955 | */ |
| 1887 | static int tomoyo_open_control(const u8 type, struct file *file) | 1956 | static int tomoyo_open_control(const u8 type, struct file *file) |
| 1888 | { | 1957 | { |
| 1889 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL); | 1958 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); |
| 1890 | 1959 | ||
| 1891 | if (!head) | 1960 | if (!head) |
| 1892 | return -ENOMEM; | 1961 | return -ENOMEM; |
| @@ -1947,7 +2016,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
| 1947 | } else { | 2016 | } else { |
| 1948 | if (!head->readbuf_size) | 2017 | if (!head->readbuf_size) |
| 1949 | head->readbuf_size = 4096 * 2; | 2018 | head->readbuf_size = 4096 * 2; |
| 1950 | head->read_buf = kzalloc(head->readbuf_size, GFP_KERNEL); | 2019 | head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); |
| 1951 | if (!head->read_buf) { | 2020 | if (!head->read_buf) { |
| 1952 | kfree(head); | 2021 | kfree(head); |
| 1953 | return -ENOMEM; | 2022 | return -ENOMEM; |
| @@ -1961,7 +2030,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
| 1961 | head->write = NULL; | 2030 | head->write = NULL; |
| 1962 | } else if (head->write) { | 2031 | } else if (head->write) { |
| 1963 | head->writebuf_size = 4096 * 2; | 2032 | head->writebuf_size = 4096 * 2; |
| 1964 | head->write_buf = kzalloc(head->writebuf_size, GFP_KERNEL); | 2033 | head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS); |
| 1965 | if (!head->write_buf) { | 2034 | if (!head->write_buf) { |
| 1966 | kfree(head->read_buf); | 2035 | kfree(head->read_buf); |
| 1967 | kfree(head); | 2036 | kfree(head); |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 67bd22dd3e68..9f1ae5e3ba51 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
| @@ -54,6 +54,7 @@ struct linux_binprm; | |||
| 54 | #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " | 54 | #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " |
| 55 | #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " | 55 | #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " |
| 56 | #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " | 56 | #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " |
| 57 | #define TOMOYO_KEYWORD_PATH_GROUP "path_group " | ||
| 57 | #define TOMOYO_KEYWORD_SELECT "select " | 58 | #define TOMOYO_KEYWORD_SELECT "select " |
| 58 | #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " | 59 | #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " |
| 59 | #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" | 60 | #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" |
| @@ -204,6 +205,27 @@ struct tomoyo_path_info_with_data { | |||
| 204 | char barrier2[16]; /* Safeguard for overrun. */ | 205 | char barrier2[16]; /* Safeguard for overrun. */ |
| 205 | }; | 206 | }; |
| 206 | 207 | ||
| 208 | struct tomoyo_name_union { | ||
| 209 | const struct tomoyo_path_info *filename; | ||
| 210 | struct tomoyo_path_group *group; | ||
| 211 | u8 is_group; | ||
| 212 | }; | ||
| 213 | |||
| 214 | /* Structure for "path_group" directive. */ | ||
| 215 | struct tomoyo_path_group { | ||
| 216 | struct list_head list; | ||
| 217 | const struct tomoyo_path_info *group_name; | ||
| 218 | struct list_head member_list; | ||
| 219 | atomic_t users; | ||
| 220 | }; | ||
| 221 | |||
| 222 | /* Structure for "path_group" directive. */ | ||
| 223 | struct tomoyo_path_group_member { | ||
| 224 | struct list_head list; | ||
| 225 | bool is_deleted; | ||
| 226 | const struct tomoyo_path_info *member_name; | ||
| 227 | }; | ||
| 228 | |||
| 207 | /* | 229 | /* |
| 208 | * tomoyo_acl_info is a structure which is used for holding | 230 | * tomoyo_acl_info is a structure which is used for holding |
| 209 | * | 231 | * |
| @@ -274,7 +296,7 @@ struct tomoyo_domain_info { | |||
| 274 | * | 296 | * |
| 275 | * (1) "head" which is a "struct tomoyo_acl_info". | 297 | * (1) "head" which is a "struct tomoyo_acl_info". |
| 276 | * (2) "perm" which is a bitmask of permitted operations. | 298 | * (2) "perm" which is a bitmask of permitted operations. |
| 277 | * (3) "filename" is the pathname. | 299 | * (3) "name" is the pathname. |
| 278 | * | 300 | * |
| 279 | * Directives held by this structure are "allow_read/write", "allow_execute", | 301 | * Directives held by this structure are "allow_read/write", "allow_execute", |
| 280 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", | 302 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", |
| @@ -287,8 +309,7 @@ struct tomoyo_path_acl { | |||
| 287 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ | 309 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ |
| 288 | u8 perm_high; | 310 | u8 perm_high; |
| 289 | u16 perm; | 311 | u16 perm; |
| 290 | /* Pointer to single pathname. */ | 312 | struct tomoyo_name_union name; |
| 291 | const struct tomoyo_path_info *filename; | ||
| 292 | }; | 313 | }; |
| 293 | 314 | ||
| 294 | /* | 315 | /* |
| @@ -298,8 +319,8 @@ struct tomoyo_path_acl { | |||
| 298 | * | 319 | * |
| 299 | * (1) "head" which is a "struct tomoyo_acl_info". | 320 | * (1) "head" which is a "struct tomoyo_acl_info". |
| 300 | * (2) "perm" which is a bitmask of permitted operations. | 321 | * (2) "perm" which is a bitmask of permitted operations. |
| 301 | * (3) "filename1" is the source/old pathname. | 322 | * (3) "name1" is the source/old pathname. |
| 302 | * (4) "filename2" is the destination/new pathname. | 323 | * (4) "name2" is the destination/new pathname. |
| 303 | * | 324 | * |
| 304 | * Directives held by this structure are "allow_rename", "allow_link" and | 325 | * Directives held by this structure are "allow_rename", "allow_link" and |
| 305 | * "allow_pivot_root". | 326 | * "allow_pivot_root". |
| @@ -307,10 +328,8 @@ struct tomoyo_path_acl { | |||
| 307 | struct tomoyo_path2_acl { | 328 | struct tomoyo_path2_acl { |
| 308 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */ | 329 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */ |
| 309 | u8 perm; | 330 | u8 perm; |
| 310 | /* Pointer to single pathname. */ | 331 | struct tomoyo_name_union name1; |
| 311 | const struct tomoyo_path_info *filename1; | 332 | struct tomoyo_name_union name2; |
| 312 | /* Pointer to single pathname. */ | ||
| 313 | const struct tomoyo_path_info *filename2; | ||
| 314 | }; | 333 | }; |
| 315 | 334 | ||
| 316 | /* | 335 | /* |
| @@ -514,6 +533,9 @@ struct tomoyo_policy_manager_entry { | |||
| 514 | 533 | ||
| 515 | /********** Function prototypes. **********/ | 534 | /********** Function prototypes. **********/ |
| 516 | 535 | ||
| 536 | /* Check whether the given name matches the given name_union. */ | ||
| 537 | bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, | ||
| 538 | const struct tomoyo_name_union *ptr); | ||
| 517 | /* Check whether the domain has too many ACL entries to hold. */ | 539 | /* Check whether the domain has too many ACL entries to hold. */ |
| 518 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); | 540 | bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); |
| 519 | /* Transactional sprintf() for policy dump. */ | 541 | /* Transactional sprintf() for policy dump. */ |
| @@ -526,6 +548,12 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, | |||
| 526 | const s8 pattern_type, const s8 end_type); | 548 | const s8 pattern_type, const s8 end_type); |
| 527 | /* Check whether the token can be a domainname. */ | 549 | /* Check whether the token can be a domainname. */ |
| 528 | bool tomoyo_is_domain_def(const unsigned char *buffer); | 550 | bool tomoyo_is_domain_def(const unsigned char *buffer); |
| 551 | bool tomoyo_parse_name_union(const char *filename, | ||
| 552 | struct tomoyo_name_union *ptr); | ||
| 553 | /* Check whether the given filename matches the given path_group. */ | ||
| 554 | bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, | ||
| 555 | const struct tomoyo_path_group *group, | ||
| 556 | const bool may_use_pattern); | ||
| 529 | /* Check whether the given filename matches the given pattern. */ | 557 | /* Check whether the given filename matches the given pattern. */ |
| 530 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, | 558 | bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, |
| 531 | const struct tomoyo_path_info *pattern); | 559 | const struct tomoyo_path_info *pattern); |
| @@ -540,10 +568,14 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head); | |||
| 540 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head); | 568 | bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head); |
| 541 | /* Read "file_pattern" entry in exception policy. */ | 569 | /* Read "file_pattern" entry in exception policy. */ |
| 542 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head); | 570 | bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head); |
| 571 | /* Read "path_group" entry in exception policy. */ | ||
| 572 | bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head); | ||
| 543 | /* Read "allow_read" entry in exception policy. */ | 573 | /* Read "allow_read" entry in exception policy. */ |
| 544 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head); | 574 | bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head); |
| 545 | /* Read "deny_rewrite" entry in exception policy. */ | 575 | /* Read "deny_rewrite" entry in exception policy. */ |
| 546 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head); | 576 | bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head); |
| 577 | /* Tokenize a line. */ | ||
| 578 | bool tomoyo_tokenize(char *buffer, char *w[], size_t size); | ||
| 547 | /* Write domain policy violation warning message to console? */ | 579 | /* Write domain policy violation warning message to console? */ |
| 548 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); | 580 | bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); |
| 549 | /* Convert double path operation to operation name. */ | 581 | /* Convert double path operation to operation name. */ |
| @@ -580,12 +612,18 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete); | |||
| 580 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete); | 612 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete); |
| 581 | /* Create "file_pattern" entry in exception policy. */ | 613 | /* Create "file_pattern" entry in exception policy. */ |
| 582 | int tomoyo_write_pattern_policy(char *data, const bool is_delete); | 614 | int tomoyo_write_pattern_policy(char *data, const bool is_delete); |
| 615 | /* Create "path_group" entry in exception policy. */ | ||
| 616 | int tomoyo_write_path_group_policy(char *data, const bool is_delete); | ||
| 583 | /* Find a domain by the given name. */ | 617 | /* Find a domain by the given name. */ |
| 584 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); | 618 | struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); |
| 585 | /* Find or create a domain by the given name. */ | 619 | /* Find or create a domain by the given name. */ |
| 586 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | 620 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * |
| 587 | domainname, | 621 | domainname, |
| 588 | const u8 profile); | 622 | const u8 profile); |
| 623 | |||
| 624 | /* Allocate memory for "struct tomoyo_path_group". */ | ||
| 625 | struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name); | ||
| 626 | |||
| 589 | /* Check mode for specified functionality. */ | 627 | /* Check mode for specified functionality. */ |
| 590 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, | 628 | unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, |
| 591 | const u8 index); | 629 | const u8 index); |
| @@ -616,6 +654,7 @@ char *tomoyo_realpath_from_path(struct path *path); | |||
| 616 | 654 | ||
| 617 | /* Check memory quota. */ | 655 | /* Check memory quota. */ |
| 618 | bool tomoyo_memory_ok(void *ptr); | 656 | bool tomoyo_memory_ok(void *ptr); |
| 657 | void *tomoyo_commit_ok(void *data, const unsigned int size); | ||
| 619 | 658 | ||
| 620 | /* | 659 | /* |
| 621 | * Keep the given name on the RAM. | 660 | * Keep the given name on the RAM. |
| @@ -641,6 +680,9 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, | |||
| 641 | int tomoyo_check_rewrite_permission(struct file *filp); | 680 | int tomoyo_check_rewrite_permission(struct file *filp); |
| 642 | int tomoyo_find_next_domain(struct linux_binprm *bprm); | 681 | int tomoyo_find_next_domain(struct linux_binprm *bprm); |
| 643 | 682 | ||
| 683 | /* Drop refcount on tomoyo_name_union. */ | ||
| 684 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr); | ||
| 685 | |||
| 644 | /* Run garbage collector. */ | 686 | /* Run garbage collector. */ |
| 645 | void tomoyo_run_gc(void); | 687 | void tomoyo_run_gc(void); |
| 646 | 688 | ||
| @@ -654,6 +696,7 @@ extern struct srcu_struct tomoyo_ss; | |||
| 654 | /* The list for "struct tomoyo_domain_info". */ | 696 | /* The list for "struct tomoyo_domain_info". */ |
| 655 | extern struct list_head tomoyo_domain_list; | 697 | extern struct list_head tomoyo_domain_list; |
| 656 | 698 | ||
| 699 | extern struct list_head tomoyo_path_group_list; | ||
| 657 | extern struct list_head tomoyo_domain_initializer_list; | 700 | extern struct list_head tomoyo_domain_initializer_list; |
| 658 | extern struct list_head tomoyo_domain_keeper_list; | 701 | extern struct list_head tomoyo_domain_keeper_list; |
| 659 | extern struct list_head tomoyo_alias_list; | 702 | extern struct list_head tomoyo_alias_list; |
| @@ -662,7 +705,6 @@ extern struct list_head tomoyo_pattern_list; | |||
| 662 | extern struct list_head tomoyo_no_rewrite_list; | 705 | extern struct list_head tomoyo_no_rewrite_list; |
| 663 | extern struct list_head tomoyo_policy_manager_list; | 706 | extern struct list_head tomoyo_policy_manager_list; |
| 664 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 707 | extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
| 665 | extern struct mutex tomoyo_name_list_lock; | ||
| 666 | 708 | ||
| 667 | /* Lock for protecting policy. */ | 709 | /* Lock for protecting policy. */ |
| 668 | extern struct mutex tomoyo_policy_lock; | 710 | extern struct mutex tomoyo_policy_lock; |
| @@ -725,6 +767,12 @@ static inline void tomoyo_put_name(const struct tomoyo_path_info *name) | |||
| 725 | } | 767 | } |
| 726 | } | 768 | } |
| 727 | 769 | ||
| 770 | static inline void tomoyo_put_path_group(struct tomoyo_path_group *group) | ||
| 771 | { | ||
| 772 | if (group) | ||
| 773 | atomic_dec(&group->users); | ||
| 774 | } | ||
| 775 | |||
| 728 | static inline struct tomoyo_domain_info *tomoyo_domain(void) | 776 | static inline struct tomoyo_domain_info *tomoyo_domain(void) |
| 729 | { | 777 | { |
| 730 | return current_cred()->security; | 778 | return current_cred()->security; |
| @@ -736,6 +784,59 @@ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct | |||
| 736 | return task_cred_xxx(task, security); | 784 | return task_cred_xxx(task, security); |
| 737 | } | 785 | } |
| 738 | 786 | ||
| 787 | static inline bool tomoyo_is_same_acl_head(const struct tomoyo_acl_info *p1, | ||
| 788 | const struct tomoyo_acl_info *p2) | ||
| 789 | { | ||
| 790 | return p1->type == p2->type; | ||
| 791 | } | ||
| 792 | |||
| 793 | static inline bool tomoyo_is_same_name_union | ||
| 794 | (const struct tomoyo_name_union *p1, const struct tomoyo_name_union *p2) | ||
| 795 | { | ||
| 796 | return p1->filename == p2->filename && p1->group == p2->group && | ||
| 797 | p1->is_group == p2->is_group; | ||
| 798 | } | ||
| 799 | |||
| 800 | static inline bool tomoyo_is_same_path_acl(const struct tomoyo_path_acl *p1, | ||
| 801 | const struct tomoyo_path_acl *p2) | ||
| 802 | { | ||
| 803 | return tomoyo_is_same_acl_head(&p1->head, &p2->head) && | ||
| 804 | tomoyo_is_same_name_union(&p1->name, &p2->name); | ||
| 805 | } | ||
| 806 | |||
| 807 | static inline bool tomoyo_is_same_path2_acl(const struct tomoyo_path2_acl *p1, | ||
| 808 | const struct tomoyo_path2_acl *p2) | ||
| 809 | { | ||
| 810 | return tomoyo_is_same_acl_head(&p1->head, &p2->head) && | ||
| 811 | tomoyo_is_same_name_union(&p1->name1, &p2->name1) && | ||
| 812 | tomoyo_is_same_name_union(&p1->name2, &p2->name2); | ||
| 813 | } | ||
| 814 | |||
| 815 | static inline bool tomoyo_is_same_domain_initializer_entry | ||
| 816 | (const struct tomoyo_domain_initializer_entry *p1, | ||
| 817 | const struct tomoyo_domain_initializer_entry *p2) | ||
| 818 | { | ||
| 819 | return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name | ||
| 820 | && p1->domainname == p2->domainname | ||
| 821 | && p1->program == p2->program; | ||
| 822 | } | ||
| 823 | |||
| 824 | static inline bool tomoyo_is_same_domain_keeper_entry | ||
| 825 | (const struct tomoyo_domain_keeper_entry *p1, | ||
| 826 | const struct tomoyo_domain_keeper_entry *p2) | ||
| 827 | { | ||
| 828 | return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name | ||
| 829 | && p1->domainname == p2->domainname | ||
| 830 | && p1->program == p2->program; | ||
| 831 | } | ||
| 832 | |||
| 833 | static inline bool tomoyo_is_same_alias_entry | ||
| 834 | (const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2) | ||
| 835 | { | ||
| 836 | return p1->original_name == p2->original_name && | ||
| 837 | p1->aliased_name == p2->aliased_name; | ||
| 838 | } | ||
| 839 | |||
| 739 | /** | 840 | /** |
| 740 | * list_for_each_cookie - iterate over a list with cookie. | 841 | * list_for_each_cookie - iterate over a list with cookie. |
| 741 | * @pos: the &struct list_head to use as a loop cursor. | 842 | * @pos: the &struct list_head to use as a loop cursor. |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index acb8c397d5cf..cd8ba4446763 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
| @@ -130,57 +130,47 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
| 130 | const bool is_not, | 130 | const bool is_not, |
| 131 | const bool is_delete) | 131 | const bool is_delete) |
| 132 | { | 132 | { |
| 133 | struct tomoyo_domain_initializer_entry *entry = NULL; | ||
| 134 | struct tomoyo_domain_initializer_entry *ptr; | 133 | struct tomoyo_domain_initializer_entry *ptr; |
| 135 | const struct tomoyo_path_info *saved_program = NULL; | 134 | struct tomoyo_domain_initializer_entry e = { .is_not = is_not }; |
| 136 | const struct tomoyo_path_info *saved_domainname = NULL; | ||
| 137 | int error = is_delete ? -ENOENT : -ENOMEM; | 135 | int error = is_delete ? -ENOENT : -ENOMEM; |
| 138 | bool is_last_name = false; | ||
| 139 | 136 | ||
| 140 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) | 137 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) |
| 141 | return -EINVAL; /* No patterns allowed. */ | 138 | return -EINVAL; /* No patterns allowed. */ |
| 142 | if (domainname) { | 139 | if (domainname) { |
| 143 | if (!tomoyo_is_domain_def(domainname) && | 140 | if (!tomoyo_is_domain_def(domainname) && |
| 144 | tomoyo_is_correct_path(domainname, 1, -1, -1)) | 141 | tomoyo_is_correct_path(domainname, 1, -1, -1)) |
| 145 | is_last_name = true; | 142 | e.is_last_name = true; |
| 146 | else if (!tomoyo_is_correct_domain(domainname)) | 143 | else if (!tomoyo_is_correct_domain(domainname)) |
| 147 | return -EINVAL; | 144 | return -EINVAL; |
| 148 | saved_domainname = tomoyo_get_name(domainname); | 145 | e.domainname = tomoyo_get_name(domainname); |
| 149 | if (!saved_domainname) | 146 | if (!e.domainname) |
| 150 | goto out; | 147 | goto out; |
| 151 | } | 148 | } |
| 152 | saved_program = tomoyo_get_name(program); | 149 | e.program = tomoyo_get_name(program); |
| 153 | if (!saved_program) | 150 | if (!e.program) |
| 151 | goto out; | ||
| 152 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
| 154 | goto out; | 153 | goto out; |
| 155 | if (!is_delete) | ||
| 156 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
| 157 | mutex_lock(&tomoyo_policy_lock); | ||
| 158 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { | 154 | list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { |
| 159 | if (ptr->is_not != is_not || | 155 | if (!tomoyo_is_same_domain_initializer_entry(ptr, &e)) |
| 160 | ptr->domainname != saved_domainname || | ||
| 161 | ptr->program != saved_program) | ||
| 162 | continue; | 156 | continue; |
| 163 | ptr->is_deleted = is_delete; | 157 | ptr->is_deleted = is_delete; |
| 164 | error = 0; | 158 | error = 0; |
| 165 | break; | 159 | break; |
| 166 | } | 160 | } |
| 167 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 161 | if (!is_delete && error) { |
| 168 | entry->domainname = saved_domainname; | 162 | struct tomoyo_domain_initializer_entry *entry = |
| 169 | saved_domainname = NULL; | 163 | tomoyo_commit_ok(&e, sizeof(e)); |
| 170 | entry->program = saved_program; | 164 | if (entry) { |
| 171 | saved_program = NULL; | 165 | list_add_tail_rcu(&entry->list, |
| 172 | entry->is_not = is_not; | 166 | &tomoyo_domain_initializer_list); |
| 173 | entry->is_last_name = is_last_name; | 167 | error = 0; |
| 174 | list_add_tail_rcu(&entry->list, | 168 | } |
| 175 | &tomoyo_domain_initializer_list); | ||
| 176 | entry = NULL; | ||
| 177 | error = 0; | ||
| 178 | } | 169 | } |
| 179 | mutex_unlock(&tomoyo_policy_lock); | 170 | mutex_unlock(&tomoyo_policy_lock); |
| 180 | out: | 171 | out: |
| 181 | tomoyo_put_name(saved_domainname); | 172 | tomoyo_put_name(e.domainname); |
| 182 | tomoyo_put_name(saved_program); | 173 | tomoyo_put_name(e.program); |
| 183 | kfree(entry); | ||
| 184 | return error; | 174 | return error; |
| 185 | } | 175 | } |
| 186 | 176 | ||
| @@ -350,56 +340,47 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
| 350 | const bool is_not, | 340 | const bool is_not, |
| 351 | const bool is_delete) | 341 | const bool is_delete) |
| 352 | { | 342 | { |
| 353 | struct tomoyo_domain_keeper_entry *entry = NULL; | ||
| 354 | struct tomoyo_domain_keeper_entry *ptr; | 343 | struct tomoyo_domain_keeper_entry *ptr; |
| 355 | const struct tomoyo_path_info *saved_domainname = NULL; | 344 | struct tomoyo_domain_keeper_entry e = { .is_not = is_not }; |
| 356 | const struct tomoyo_path_info *saved_program = NULL; | ||
| 357 | int error = is_delete ? -ENOENT : -ENOMEM; | 345 | int error = is_delete ? -ENOENT : -ENOMEM; |
| 358 | bool is_last_name = false; | ||
| 359 | 346 | ||
| 360 | if (!tomoyo_is_domain_def(domainname) && | 347 | if (!tomoyo_is_domain_def(domainname) && |
| 361 | tomoyo_is_correct_path(domainname, 1, -1, -1)) | 348 | tomoyo_is_correct_path(domainname, 1, -1, -1)) |
| 362 | is_last_name = true; | 349 | e.is_last_name = true; |
| 363 | else if (!tomoyo_is_correct_domain(domainname)) | 350 | else if (!tomoyo_is_correct_domain(domainname)) |
| 364 | return -EINVAL; | 351 | return -EINVAL; |
| 365 | if (program) { | 352 | if (program) { |
| 366 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) | 353 | if (!tomoyo_is_correct_path(program, 1, -1, -1)) |
| 367 | return -EINVAL; | 354 | return -EINVAL; |
| 368 | saved_program = tomoyo_get_name(program); | 355 | e.program = tomoyo_get_name(program); |
| 369 | if (!saved_program) | 356 | if (!e.program) |
| 370 | goto out; | 357 | goto out; |
| 371 | } | 358 | } |
| 372 | saved_domainname = tomoyo_get_name(domainname); | 359 | e.domainname = tomoyo_get_name(domainname); |
| 373 | if (!saved_domainname) | 360 | if (!e.domainname) |
| 361 | goto out; | ||
| 362 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
| 374 | goto out; | 363 | goto out; |
| 375 | if (!is_delete) | ||
| 376 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
| 377 | mutex_lock(&tomoyo_policy_lock); | ||
| 378 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { | 364 | list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { |
| 379 | if (ptr->is_not != is_not || | 365 | if (!tomoyo_is_same_domain_keeper_entry(ptr, &e)) |
| 380 | ptr->domainname != saved_domainname || | ||
| 381 | ptr->program != saved_program) | ||
| 382 | continue; | 366 | continue; |
| 383 | ptr->is_deleted = is_delete; | 367 | ptr->is_deleted = is_delete; |
| 384 | error = 0; | 368 | error = 0; |
| 385 | break; | 369 | break; |
| 386 | } | 370 | } |
| 387 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 371 | if (!is_delete && error) { |
| 388 | entry->domainname = saved_domainname; | 372 | struct tomoyo_domain_keeper_entry *entry = |
| 389 | saved_domainname = NULL; | 373 | tomoyo_commit_ok(&e, sizeof(e)); |
| 390 | entry->program = saved_program; | 374 | if (entry) { |
| 391 | saved_program = NULL; | 375 | list_add_tail_rcu(&entry->list, |
| 392 | entry->is_not = is_not; | 376 | &tomoyo_domain_keeper_list); |
| 393 | entry->is_last_name = is_last_name; | 377 | error = 0; |
| 394 | list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list); | 378 | } |
| 395 | entry = NULL; | ||
| 396 | error = 0; | ||
| 397 | } | 379 | } |
| 398 | mutex_unlock(&tomoyo_policy_lock); | 380 | mutex_unlock(&tomoyo_policy_lock); |
| 399 | out: | 381 | out: |
| 400 | tomoyo_put_name(saved_domainname); | 382 | tomoyo_put_name(e.domainname); |
| 401 | tomoyo_put_name(saved_program); | 383 | tomoyo_put_name(e.program); |
| 402 | kfree(entry); | ||
| 403 | return error; | 384 | return error; |
| 404 | } | 385 | } |
| 405 | 386 | ||
| @@ -551,44 +532,38 @@ static int tomoyo_update_alias_entry(const char *original_name, | |||
| 551 | const char *aliased_name, | 532 | const char *aliased_name, |
| 552 | const bool is_delete) | 533 | const bool is_delete) |
| 553 | { | 534 | { |
| 554 | struct tomoyo_alias_entry *entry = NULL; | ||
| 555 | struct tomoyo_alias_entry *ptr; | 535 | struct tomoyo_alias_entry *ptr; |
| 556 | const struct tomoyo_path_info *saved_original_name; | 536 | struct tomoyo_alias_entry e = { }; |
| 557 | const struct tomoyo_path_info *saved_aliased_name; | ||
| 558 | int error = is_delete ? -ENOENT : -ENOMEM; | 537 | int error = is_delete ? -ENOENT : -ENOMEM; |
| 559 | 538 | ||
| 560 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || | 539 | if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || |
| 561 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1)) | 540 | !tomoyo_is_correct_path(aliased_name, 1, -1, -1)) |
| 562 | return -EINVAL; /* No patterns allowed. */ | 541 | return -EINVAL; /* No patterns allowed. */ |
| 563 | saved_original_name = tomoyo_get_name(original_name); | 542 | e.original_name = tomoyo_get_name(original_name); |
| 564 | saved_aliased_name = tomoyo_get_name(aliased_name); | 543 | e.aliased_name = tomoyo_get_name(aliased_name); |
| 565 | if (!saved_original_name || !saved_aliased_name) | 544 | if (!e.original_name || !e.aliased_name) |
| 545 | goto out; | ||
| 546 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
| 566 | goto out; | 547 | goto out; |
| 567 | if (!is_delete) | ||
| 568 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
| 569 | mutex_lock(&tomoyo_policy_lock); | ||
| 570 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { | 548 | list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { |
| 571 | if (ptr->original_name != saved_original_name || | 549 | if (!tomoyo_is_same_alias_entry(ptr, &e)) |
| 572 | ptr->aliased_name != saved_aliased_name) | ||
| 573 | continue; | 550 | continue; |
| 574 | ptr->is_deleted = is_delete; | 551 | ptr->is_deleted = is_delete; |
| 575 | error = 0; | 552 | error = 0; |
| 576 | break; | 553 | break; |
| 577 | } | 554 | } |
| 578 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 555 | if (!is_delete && error) { |
| 579 | entry->original_name = saved_original_name; | 556 | struct tomoyo_alias_entry *entry = |
| 580 | saved_original_name = NULL; | 557 | tomoyo_commit_ok(&e, sizeof(e)); |
| 581 | entry->aliased_name = saved_aliased_name; | 558 | if (entry) { |
| 582 | saved_aliased_name = NULL; | 559 | list_add_tail_rcu(&entry->list, &tomoyo_alias_list); |
| 583 | list_add_tail_rcu(&entry->list, &tomoyo_alias_list); | 560 | error = 0; |
| 584 | entry = NULL; | 561 | } |
| 585 | error = 0; | ||
| 586 | } | 562 | } |
| 587 | mutex_unlock(&tomoyo_policy_lock); | 563 | mutex_unlock(&tomoyo_policy_lock); |
| 588 | out: | 564 | out: |
| 589 | tomoyo_put_name(saved_original_name); | 565 | tomoyo_put_name(e.original_name); |
| 590 | tomoyo_put_name(saved_aliased_name); | 566 | tomoyo_put_name(e.aliased_name); |
| 591 | kfree(entry); | ||
| 592 | return error; | 567 | return error; |
| 593 | } | 568 | } |
| 594 | 569 | ||
| @@ -656,7 +631,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
| 656 | const u8 profile) | 631 | const u8 profile) |
| 657 | { | 632 | { |
| 658 | struct tomoyo_domain_info *entry; | 633 | struct tomoyo_domain_info *entry; |
| 659 | struct tomoyo_domain_info *domain; | 634 | struct tomoyo_domain_info *domain = NULL; |
| 660 | const struct tomoyo_path_info *saved_domainname; | 635 | const struct tomoyo_path_info *saved_domainname; |
| 661 | bool found = false; | 636 | bool found = false; |
| 662 | 637 | ||
| @@ -665,8 +640,9 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
| 665 | saved_domainname = tomoyo_get_name(domainname); | 640 | saved_domainname = tomoyo_get_name(domainname); |
| 666 | if (!saved_domainname) | 641 | if (!saved_domainname) |
| 667 | return NULL; | 642 | return NULL; |
| 668 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | 643 | entry = kzalloc(sizeof(*entry), GFP_NOFS); |
| 669 | mutex_lock(&tomoyo_policy_lock); | 644 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 645 | goto out; | ||
| 670 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 646 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
| 671 | if (domain->is_deleted || | 647 | if (domain->is_deleted || |
| 672 | tomoyo_pathcmp(saved_domainname, domain->domainname)) | 648 | tomoyo_pathcmp(saved_domainname, domain->domainname)) |
| @@ -685,6 +661,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
| 685 | found = true; | 661 | found = true; |
| 686 | } | 662 | } |
| 687 | mutex_unlock(&tomoyo_policy_lock); | 663 | mutex_unlock(&tomoyo_policy_lock); |
| 664 | out: | ||
| 688 | tomoyo_put_name(saved_domainname); | 665 | tomoyo_put_name(saved_domainname); |
| 689 | kfree(entry); | 666 | kfree(entry); |
| 690 | return found ? domain : NULL; | 667 | return found ? domain : NULL; |
| @@ -705,7 +682,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
| 705 | * This function assumes that the size of buffer returned by | 682 | * This function assumes that the size of buffer returned by |
| 706 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. | 683 | * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. |
| 707 | */ | 684 | */ |
| 708 | struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); | 685 | struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS); |
| 709 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 686 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
| 710 | struct tomoyo_domain_info *domain = NULL; | 687 | struct tomoyo_domain_info *domain = NULL; |
| 711 | const char *old_domain_name = old_domain->domainname->name; | 688 | const char *old_domain_name = old_domain->domainname->name; |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 6f3fe76a1fde..1c6f8238ec47 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
| @@ -45,6 +45,37 @@ static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { | |||
| 45 | [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", | 45 | [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", |
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | void tomoyo_put_name_union(struct tomoyo_name_union *ptr) | ||
| 49 | { | ||
| 50 | if (!ptr) | ||
| 51 | return; | ||
| 52 | if (ptr->is_group) | ||
| 53 | tomoyo_put_path_group(ptr->group); | ||
| 54 | else | ||
| 55 | tomoyo_put_name(ptr->filename); | ||
| 56 | } | ||
| 57 | |||
| 58 | bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, | ||
| 59 | const struct tomoyo_name_union *ptr) | ||
| 60 | { | ||
| 61 | if (ptr->is_group) | ||
| 62 | return tomoyo_path_matches_group(name, ptr->group, 1); | ||
| 63 | return tomoyo_path_matches_pattern(name, ptr->filename); | ||
| 64 | } | ||
| 65 | |||
| 66 | static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info | ||
| 67 | *name, | ||
| 68 | const struct tomoyo_name_union | ||
| 69 | *ptr, const bool may_use_pattern) | ||
| 70 | { | ||
| 71 | if (ptr->is_group) | ||
| 72 | return tomoyo_path_matches_group(name, ptr->group, | ||
| 73 | may_use_pattern); | ||
| 74 | if (may_use_pattern || !ptr->filename->is_patterned) | ||
| 75 | return tomoyo_path_matches_pattern(name, ptr->filename); | ||
| 76 | return false; | ||
| 77 | } | ||
| 78 | |||
| 48 | /** | 79 | /** |
| 49 | * tomoyo_path2keyword - Get the name of single path operation. | 80 | * tomoyo_path2keyword - Get the name of single path operation. |
| 50 | * | 81 | * |
| @@ -100,7 +131,7 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path) | |||
| 100 | { | 131 | { |
| 101 | int error; | 132 | int error; |
| 102 | struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), | 133 | struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), |
| 103 | GFP_KERNEL); | 134 | GFP_NOFS); |
| 104 | 135 | ||
| 105 | if (!buf) | 136 | if (!buf) |
| 106 | return NULL; | 137 | return NULL; |
| @@ -164,36 +195,36 @@ LIST_HEAD(tomoyo_globally_readable_list); | |||
| 164 | static int tomoyo_update_globally_readable_entry(const char *filename, | 195 | static int tomoyo_update_globally_readable_entry(const char *filename, |
| 165 | const bool is_delete) | 196 | const bool is_delete) |
| 166 | { | 197 | { |
| 167 | struct tomoyo_globally_readable_file_entry *entry = NULL; | ||
| 168 | struct tomoyo_globally_readable_file_entry *ptr; | 198 | struct tomoyo_globally_readable_file_entry *ptr; |
| 169 | const struct tomoyo_path_info *saved_filename; | 199 | struct tomoyo_globally_readable_file_entry e = { }; |
| 170 | int error = is_delete ? -ENOENT : -ENOMEM; | 200 | int error = is_delete ? -ENOENT : -ENOMEM; |
| 171 | 201 | ||
| 172 | if (!tomoyo_is_correct_path(filename, 1, 0, -1)) | 202 | if (!tomoyo_is_correct_path(filename, 1, 0, -1)) |
| 173 | return -EINVAL; | 203 | return -EINVAL; |
| 174 | saved_filename = tomoyo_get_name(filename); | 204 | e.filename = tomoyo_get_name(filename); |
| 175 | if (!saved_filename) | 205 | if (!e.filename) |
| 176 | return -ENOMEM; | 206 | return -ENOMEM; |
| 177 | if (!is_delete) | 207 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 178 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 208 | goto out; |
| 179 | mutex_lock(&tomoyo_policy_lock); | ||
| 180 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { | 209 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { |
| 181 | if (ptr->filename != saved_filename) | 210 | if (ptr->filename != e.filename) |
| 182 | continue; | 211 | continue; |
| 183 | ptr->is_deleted = is_delete; | 212 | ptr->is_deleted = is_delete; |
| 184 | error = 0; | 213 | error = 0; |
| 185 | break; | 214 | break; |
| 186 | } | 215 | } |
| 187 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 216 | if (!is_delete && error) { |
| 188 | entry->filename = saved_filename; | 217 | struct tomoyo_globally_readable_file_entry *entry = |
| 189 | saved_filename = NULL; | 218 | tomoyo_commit_ok(&e, sizeof(e)); |
| 190 | list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); | 219 | if (entry) { |
| 191 | entry = NULL; | 220 | list_add_tail_rcu(&entry->list, |
| 192 | error = 0; | 221 | &tomoyo_globally_readable_list); |
| 222 | error = 0; | ||
| 223 | } | ||
| 193 | } | 224 | } |
| 194 | mutex_unlock(&tomoyo_policy_lock); | 225 | mutex_unlock(&tomoyo_policy_lock); |
| 195 | tomoyo_put_name(saved_filename); | 226 | out: |
| 196 | kfree(entry); | 227 | tomoyo_put_name(e.filename); |
| 197 | return error; | 228 | return error; |
| 198 | } | 229 | } |
| 199 | 230 | ||
| @@ -311,37 +342,34 @@ LIST_HEAD(tomoyo_pattern_list); | |||
| 311 | static int tomoyo_update_file_pattern_entry(const char *pattern, | 342 | static int tomoyo_update_file_pattern_entry(const char *pattern, |
| 312 | const bool is_delete) | 343 | const bool is_delete) |
| 313 | { | 344 | { |
| 314 | struct tomoyo_pattern_entry *entry = NULL; | ||
| 315 | struct tomoyo_pattern_entry *ptr; | 345 | struct tomoyo_pattern_entry *ptr; |
| 316 | const struct tomoyo_path_info *saved_pattern; | 346 | struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) }; |
| 317 | int error = is_delete ? -ENOENT : -ENOMEM; | 347 | int error = is_delete ? -ENOENT : -ENOMEM; |
| 318 | 348 | ||
| 319 | saved_pattern = tomoyo_get_name(pattern); | 349 | if (!e.pattern) |
| 320 | if (!saved_pattern) | ||
| 321 | return error; | 350 | return error; |
| 322 | if (!saved_pattern->is_patterned) | 351 | if (!e.pattern->is_patterned) |
| 352 | goto out; | ||
| 353 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
| 323 | goto out; | 354 | goto out; |
| 324 | if (!is_delete) | ||
| 325 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
| 326 | mutex_lock(&tomoyo_policy_lock); | ||
| 327 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { | 355 | list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { |
| 328 | if (saved_pattern != ptr->pattern) | 356 | if (e.pattern != ptr->pattern) |
| 329 | continue; | 357 | continue; |
| 330 | ptr->is_deleted = is_delete; | 358 | ptr->is_deleted = is_delete; |
| 331 | error = 0; | 359 | error = 0; |
| 332 | break; | 360 | break; |
| 333 | } | 361 | } |
| 334 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 362 | if (!is_delete && error) { |
| 335 | entry->pattern = saved_pattern; | 363 | struct tomoyo_pattern_entry *entry = |
| 336 | saved_pattern = NULL; | 364 | tomoyo_commit_ok(&e, sizeof(e)); |
| 337 | list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); | 365 | if (entry) { |
| 338 | entry = NULL; | 366 | list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); |
| 339 | error = 0; | 367 | error = 0; |
| 368 | } | ||
| 340 | } | 369 | } |
| 341 | mutex_unlock(&tomoyo_policy_lock); | 370 | mutex_unlock(&tomoyo_policy_lock); |
| 342 | out: | 371 | out: |
| 343 | kfree(entry); | 372 | tomoyo_put_name(e.pattern); |
| 344 | tomoyo_put_name(saved_pattern); | ||
| 345 | return error; | 373 | return error; |
| 346 | } | 374 | } |
| 347 | 375 | ||
| @@ -464,36 +492,36 @@ LIST_HEAD(tomoyo_no_rewrite_list); | |||
| 464 | static int tomoyo_update_no_rewrite_entry(const char *pattern, | 492 | static int tomoyo_update_no_rewrite_entry(const char *pattern, |
| 465 | const bool is_delete) | 493 | const bool is_delete) |
| 466 | { | 494 | { |
| 467 | struct tomoyo_no_rewrite_entry *entry = NULL; | ||
| 468 | struct tomoyo_no_rewrite_entry *ptr; | 495 | struct tomoyo_no_rewrite_entry *ptr; |
| 469 | const struct tomoyo_path_info *saved_pattern; | 496 | struct tomoyo_no_rewrite_entry e = { }; |
| 470 | int error = is_delete ? -ENOENT : -ENOMEM; | 497 | int error = is_delete ? -ENOENT : -ENOMEM; |
| 471 | 498 | ||
| 472 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) | 499 | if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) |
| 473 | return -EINVAL; | 500 | return -EINVAL; |
| 474 | saved_pattern = tomoyo_get_name(pattern); | 501 | e.pattern = tomoyo_get_name(pattern); |
| 475 | if (!saved_pattern) | 502 | if (!e.pattern) |
| 476 | return error; | 503 | return error; |
| 477 | if (!is_delete) | 504 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 478 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 505 | goto out; |
| 479 | mutex_lock(&tomoyo_policy_lock); | ||
| 480 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { | 506 | list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { |
| 481 | if (ptr->pattern != saved_pattern) | 507 | if (ptr->pattern != e.pattern) |
| 482 | continue; | 508 | continue; |
| 483 | ptr->is_deleted = is_delete; | 509 | ptr->is_deleted = is_delete; |
| 484 | error = 0; | 510 | error = 0; |
| 485 | break; | 511 | break; |
| 486 | } | 512 | } |
| 487 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 513 | if (!is_delete && error) { |
| 488 | entry->pattern = saved_pattern; | 514 | struct tomoyo_no_rewrite_entry *entry = |
| 489 | saved_pattern = NULL; | 515 | tomoyo_commit_ok(&e, sizeof(e)); |
| 490 | list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); | 516 | if (entry) { |
| 491 | entry = NULL; | 517 | list_add_tail_rcu(&entry->list, |
| 492 | error = 0; | 518 | &tomoyo_no_rewrite_list); |
| 519 | error = 0; | ||
| 520 | } | ||
| 493 | } | 521 | } |
| 494 | mutex_unlock(&tomoyo_policy_lock); | 522 | mutex_unlock(&tomoyo_policy_lock); |
| 495 | tomoyo_put_name(saved_pattern); | 523 | out: |
| 496 | kfree(entry); | 524 | tomoyo_put_name(e.pattern); |
| 497 | return error; | 525 | return error; |
| 498 | } | 526 | } |
| 499 | 527 | ||
| @@ -640,13 +668,9 @@ static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain, | |||
| 640 | if (!(acl->perm_high & (perm >> 16))) | 668 | if (!(acl->perm_high & (perm >> 16))) |
| 641 | continue; | 669 | continue; |
| 642 | } | 670 | } |
| 643 | if (may_use_pattern || !acl->filename->is_patterned) { | 671 | if (!tomoyo_compare_name_union_pattern(filename, &acl->name, |
| 644 | if (!tomoyo_path_matches_pattern(filename, | 672 | may_use_pattern)) |
| 645 | acl->filename)) | ||
| 646 | continue; | ||
| 647 | } else { | ||
| 648 | continue; | 673 | continue; |
| 649 | } | ||
| 650 | error = 0; | 674 | error = 0; |
| 651 | break; | 675 | break; |
| 652 | } | 676 | } |
| @@ -805,70 +829,64 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename, | |||
| 805 | struct tomoyo_domain_info *const domain, | 829 | struct tomoyo_domain_info *const domain, |
| 806 | const bool is_delete) | 830 | const bool is_delete) |
| 807 | { | 831 | { |
| 808 | static const u32 rw_mask = | 832 | static const u32 tomoyo_rw_mask = |
| 809 | (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); | 833 | (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); |
| 810 | const struct tomoyo_path_info *saved_filename; | 834 | const u32 perm = 1 << type; |
| 811 | struct tomoyo_acl_info *ptr; | 835 | struct tomoyo_acl_info *ptr; |
| 812 | struct tomoyo_path_acl *entry = NULL; | 836 | struct tomoyo_path_acl e = { |
| 837 | .head.type = TOMOYO_TYPE_PATH_ACL, | ||
| 838 | .perm_high = perm >> 16, | ||
| 839 | .perm = perm | ||
| 840 | }; | ||
| 813 | int error = is_delete ? -ENOENT : -ENOMEM; | 841 | int error = is_delete ? -ENOENT : -ENOMEM; |
| 814 | const u32 perm = 1 << type; | ||
| 815 | 842 | ||
| 843 | if (type == TOMOYO_TYPE_READ_WRITE) | ||
| 844 | e.perm |= tomoyo_rw_mask; | ||
| 816 | if (!domain) | 845 | if (!domain) |
| 817 | return -EINVAL; | 846 | return -EINVAL; |
| 818 | if (!tomoyo_is_correct_path(filename, 0, 0, 0)) | 847 | if (!tomoyo_parse_name_union(filename, &e.name)) |
| 819 | return -EINVAL; | 848 | return -EINVAL; |
| 820 | saved_filename = tomoyo_get_name(filename); | 849 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 821 | if (!saved_filename) | 850 | goto out; |
| 822 | return -ENOMEM; | ||
| 823 | if (!is_delete) | ||
| 824 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
| 825 | mutex_lock(&tomoyo_policy_lock); | ||
| 826 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | 851 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
| 827 | struct tomoyo_path_acl *acl = | 852 | struct tomoyo_path_acl *acl = |
| 828 | container_of(ptr, struct tomoyo_path_acl, head); | 853 | container_of(ptr, struct tomoyo_path_acl, head); |
| 829 | if (ptr->type != TOMOYO_TYPE_PATH_ACL) | 854 | if (!tomoyo_is_same_path_acl(acl, &e)) |
| 830 | continue; | ||
| 831 | if (acl->filename != saved_filename) | ||
| 832 | continue; | 855 | continue; |
| 833 | if (is_delete) { | 856 | if (is_delete) { |
| 834 | if (perm <= 0xFFFF) | 857 | if (perm <= 0xFFFF) |
| 835 | acl->perm &= ~perm; | 858 | acl->perm &= ~perm; |
| 836 | else | 859 | else |
| 837 | acl->perm_high &= ~(perm >> 16); | 860 | acl->perm_high &= ~(perm >> 16); |
| 838 | if ((acl->perm & rw_mask) != rw_mask) | 861 | if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask) |
| 839 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); | 862 | acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); |
| 840 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) | 863 | else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) |
| 841 | acl->perm &= ~rw_mask; | 864 | acl->perm &= ~tomoyo_rw_mask; |
| 842 | } else { | 865 | } else { |
| 843 | if (perm <= 0xFFFF) | 866 | if (perm <= 0xFFFF) |
| 844 | acl->perm |= perm; | 867 | acl->perm |= perm; |
| 845 | else | 868 | else |
| 846 | acl->perm_high |= (perm >> 16); | 869 | acl->perm_high |= (perm >> 16); |
| 847 | if ((acl->perm & rw_mask) == rw_mask) | 870 | if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask) |
| 848 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; | 871 | acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; |
| 849 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) | 872 | else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) |
| 850 | acl->perm |= rw_mask; | 873 | acl->perm |= tomoyo_rw_mask; |
| 851 | } | 874 | } |
| 852 | error = 0; | 875 | error = 0; |
| 853 | break; | 876 | break; |
| 854 | } | 877 | } |
| 855 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 878 | if (!is_delete && error) { |
| 856 | entry->head.type = TOMOYO_TYPE_PATH_ACL; | 879 | struct tomoyo_path_acl *entry = |
| 857 | if (perm <= 0xFFFF) | 880 | tomoyo_commit_ok(&e, sizeof(e)); |
| 858 | entry->perm = perm; | 881 | if (entry) { |
| 859 | else | 882 | list_add_tail_rcu(&entry->head.list, |
| 860 | entry->perm_high = (perm >> 16); | 883 | &domain->acl_info_list); |
| 861 | if (perm == (1 << TOMOYO_TYPE_READ_WRITE)) | 884 | error = 0; |
| 862 | entry->perm |= rw_mask; | 885 | } |
| 863 | entry->filename = saved_filename; | ||
| 864 | saved_filename = NULL; | ||
| 865 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); | ||
| 866 | entry = NULL; | ||
| 867 | error = 0; | ||
| 868 | } | 886 | } |
| 869 | mutex_unlock(&tomoyo_policy_lock); | 887 | mutex_unlock(&tomoyo_policy_lock); |
| 870 | kfree(entry); | 888 | out: |
| 871 | tomoyo_put_name(saved_filename); | 889 | tomoyo_put_name_union(&e.name); |
| 872 | return error; | 890 | return error; |
| 873 | } | 891 | } |
| 874 | 892 | ||
| @@ -890,32 +908,25 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1, | |||
| 890 | struct tomoyo_domain_info *const domain, | 908 | struct tomoyo_domain_info *const domain, |
| 891 | const bool is_delete) | 909 | const bool is_delete) |
| 892 | { | 910 | { |
| 893 | const struct tomoyo_path_info *saved_filename1; | 911 | const u8 perm = 1 << type; |
| 894 | const struct tomoyo_path_info *saved_filename2; | 912 | struct tomoyo_path2_acl e = { |
| 913 | .head.type = TOMOYO_TYPE_PATH2_ACL, | ||
| 914 | .perm = perm | ||
| 915 | }; | ||
| 895 | struct tomoyo_acl_info *ptr; | 916 | struct tomoyo_acl_info *ptr; |
| 896 | struct tomoyo_path2_acl *entry = NULL; | ||
| 897 | int error = is_delete ? -ENOENT : -ENOMEM; | 917 | int error = is_delete ? -ENOENT : -ENOMEM; |
| 898 | const u8 perm = 1 << type; | ||
| 899 | 918 | ||
| 900 | if (!domain) | 919 | if (!domain) |
| 901 | return -EINVAL; | 920 | return -EINVAL; |
| 902 | if (!tomoyo_is_correct_path(filename1, 0, 0, 0) || | 921 | if (!tomoyo_parse_name_union(filename1, &e.name1) || |
| 903 | !tomoyo_is_correct_path(filename2, 0, 0, 0)) | 922 | !tomoyo_parse_name_union(filename2, &e.name2)) |
| 904 | return -EINVAL; | 923 | goto out; |
| 905 | saved_filename1 = tomoyo_get_name(filename1); | 924 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 906 | saved_filename2 = tomoyo_get_name(filename2); | ||
| 907 | if (!saved_filename1 || !saved_filename2) | ||
| 908 | goto out; | 925 | goto out; |
| 909 | if (!is_delete) | ||
| 910 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | ||
| 911 | mutex_lock(&tomoyo_policy_lock); | ||
| 912 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | 926 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { |
| 913 | struct tomoyo_path2_acl *acl = | 927 | struct tomoyo_path2_acl *acl = |
| 914 | container_of(ptr, struct tomoyo_path2_acl, head); | 928 | container_of(ptr, struct tomoyo_path2_acl, head); |
| 915 | if (ptr->type != TOMOYO_TYPE_PATH2_ACL) | 929 | if (!tomoyo_is_same_path2_acl(acl, &e)) |
| 916 | continue; | ||
| 917 | if (acl->filename1 != saved_filename1 || | ||
| 918 | acl->filename2 != saved_filename2) | ||
| 919 | continue; | 930 | continue; |
| 920 | if (is_delete) | 931 | if (is_delete) |
| 921 | acl->perm &= ~perm; | 932 | acl->perm &= ~perm; |
| @@ -924,22 +935,19 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1, | |||
| 924 | error = 0; | 935 | error = 0; |
| 925 | break; | 936 | break; |
| 926 | } | 937 | } |
| 927 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 938 | if (!is_delete && error) { |
| 928 | entry->head.type = TOMOYO_TYPE_PATH2_ACL; | 939 | struct tomoyo_path2_acl *entry = |
| 929 | entry->perm = perm; | 940 | tomoyo_commit_ok(&e, sizeof(e)); |
| 930 | entry->filename1 = saved_filename1; | 941 | if (entry) { |
| 931 | saved_filename1 = NULL; | 942 | list_add_tail_rcu(&entry->head.list, |
| 932 | entry->filename2 = saved_filename2; | 943 | &domain->acl_info_list); |
| 933 | saved_filename2 = NULL; | 944 | error = 0; |
| 934 | list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); | 945 | } |
| 935 | entry = NULL; | ||
| 936 | error = 0; | ||
| 937 | } | 946 | } |
| 938 | mutex_unlock(&tomoyo_policy_lock); | 947 | mutex_unlock(&tomoyo_policy_lock); |
| 939 | out: | 948 | out: |
| 940 | tomoyo_put_name(saved_filename1); | 949 | tomoyo_put_name_union(&e.name1); |
| 941 | tomoyo_put_name(saved_filename2); | 950 | tomoyo_put_name_union(&e.name2); |
| 942 | kfree(entry); | ||
| 943 | return error; | 951 | return error; |
| 944 | } | 952 | } |
| 945 | 953 | ||
| @@ -992,9 +1000,9 @@ static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain, | |||
| 992 | acl = container_of(ptr, struct tomoyo_path2_acl, head); | 1000 | acl = container_of(ptr, struct tomoyo_path2_acl, head); |
| 993 | if (!(acl->perm & perm)) | 1001 | if (!(acl->perm & perm)) |
| 994 | continue; | 1002 | continue; |
| 995 | if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) | 1003 | if (!tomoyo_compare_name_union(filename1, &acl->name1)) |
| 996 | continue; | 1004 | continue; |
| 997 | if (!tomoyo_path_matches_pattern(filename2, acl->filename2)) | 1005 | if (!tomoyo_compare_name_union(filename2, &acl->name2)) |
| 998 | continue; | 1006 | continue; |
| 999 | error = 0; | 1007 | error = 0; |
| 1000 | break; | 1008 | break; |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index d9ad35bc7fa8..b9cc71b04314 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
| 13 | 13 | ||
| 14 | enum tomoyo_gc_id { | 14 | enum tomoyo_gc_id { |
| 15 | TOMOYO_ID_PATH_GROUP, | ||
| 16 | TOMOYO_ID_PATH_GROUP_MEMBER, | ||
| 15 | TOMOYO_ID_DOMAIN_INITIALIZER, | 17 | TOMOYO_ID_DOMAIN_INITIALIZER, |
| 16 | TOMOYO_ID_DOMAIN_KEEPER, | 18 | TOMOYO_ID_DOMAIN_KEEPER, |
| 17 | TOMOYO_ID_ALIAS, | 19 | TOMOYO_ID_ALIAS, |
| @@ -91,15 +93,15 @@ static void tomoyo_del_acl(struct tomoyo_acl_info *acl) | |||
| 91 | { | 93 | { |
| 92 | struct tomoyo_path_acl *entry | 94 | struct tomoyo_path_acl *entry |
| 93 | = container_of(acl, typeof(*entry), head); | 95 | = container_of(acl, typeof(*entry), head); |
| 94 | tomoyo_put_name(entry->filename); | 96 | tomoyo_put_name_union(&entry->name); |
| 95 | } | 97 | } |
| 96 | break; | 98 | break; |
| 97 | case TOMOYO_TYPE_PATH2_ACL: | 99 | case TOMOYO_TYPE_PATH2_ACL: |
| 98 | { | 100 | { |
| 99 | struct tomoyo_path2_acl *entry | 101 | struct tomoyo_path2_acl *entry |
| 100 | = container_of(acl, typeof(*entry), head); | 102 | = container_of(acl, typeof(*entry), head); |
| 101 | tomoyo_put_name(entry->filename1); | 103 | tomoyo_put_name_union(&entry->name1); |
| 102 | tomoyo_put_name(entry->filename2); | 104 | tomoyo_put_name_union(&entry->name2); |
| 103 | } | 105 | } |
| 104 | break; | 106 | break; |
| 105 | default: | 107 | default: |
| @@ -149,9 +151,21 @@ static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) | |||
| 149 | { | 151 | { |
| 150 | } | 152 | } |
| 151 | 153 | ||
| 154 | static void tomoyo_del_path_group_member(struct tomoyo_path_group_member | ||
| 155 | *member) | ||
| 156 | { | ||
| 157 | tomoyo_put_name(member->member_name); | ||
| 158 | } | ||
| 159 | |||
| 160 | static void tomoyo_del_path_group(struct tomoyo_path_group *group) | ||
| 161 | { | ||
| 162 | tomoyo_put_name(group->group_name); | ||
| 163 | } | ||
| 164 | |||
| 152 | static void tomoyo_collect_entry(void) | 165 | static void tomoyo_collect_entry(void) |
| 153 | { | 166 | { |
| 154 | mutex_lock(&tomoyo_policy_lock); | 167 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 168 | return; | ||
| 155 | { | 169 | { |
| 156 | struct tomoyo_globally_readable_file_entry *ptr; | 170 | struct tomoyo_globally_readable_file_entry *ptr; |
| 157 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, | 171 | list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, |
| @@ -275,8 +289,6 @@ static void tomoyo_collect_entry(void) | |||
| 275 | break; | 289 | break; |
| 276 | } | 290 | } |
| 277 | } | 291 | } |
| 278 | mutex_unlock(&tomoyo_policy_lock); | ||
| 279 | mutex_lock(&tomoyo_name_list_lock); | ||
| 280 | { | 292 | { |
| 281 | int i; | 293 | int i; |
| 282 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { | 294 | for (i = 0; i < TOMOYO_MAX_HASH; i++) { |
| @@ -294,7 +306,30 @@ static void tomoyo_collect_entry(void) | |||
| 294 | } | 306 | } |
| 295 | } | 307 | } |
| 296 | } | 308 | } |
| 297 | mutex_unlock(&tomoyo_name_list_lock); | 309 | { |
| 310 | struct tomoyo_path_group *group; | ||
| 311 | list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) { | ||
| 312 | struct tomoyo_path_group_member *member; | ||
| 313 | list_for_each_entry_rcu(member, &group->member_list, | ||
| 314 | list) { | ||
| 315 | if (!member->is_deleted) | ||
| 316 | continue; | ||
| 317 | if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP_MEMBER, | ||
| 318 | member)) | ||
| 319 | list_del_rcu(&member->list); | ||
| 320 | else | ||
| 321 | break; | ||
| 322 | } | ||
| 323 | if (!list_empty(&group->member_list) || | ||
| 324 | atomic_read(&group->users)) | ||
| 325 | continue; | ||
| 326 | if (tomoyo_add_to_gc(TOMOYO_ID_PATH_GROUP, group)) | ||
| 327 | list_del_rcu(&group->list); | ||
| 328 | else | ||
| 329 | break; | ||
| 330 | } | ||
| 331 | } | ||
| 332 | mutex_unlock(&tomoyo_policy_lock); | ||
| 298 | } | 333 | } |
| 299 | 334 | ||
| 300 | static void tomoyo_kfree_entry(void) | 335 | static void tomoyo_kfree_entry(void) |
| @@ -335,6 +370,12 @@ static void tomoyo_kfree_entry(void) | |||
| 335 | if (!tomoyo_del_domain(p->element)) | 370 | if (!tomoyo_del_domain(p->element)) |
| 336 | continue; | 371 | continue; |
| 337 | break; | 372 | break; |
| 373 | case TOMOYO_ID_PATH_GROUP_MEMBER: | ||
| 374 | tomoyo_del_path_group_member(p->element); | ||
| 375 | break; | ||
| 376 | case TOMOYO_ID_PATH_GROUP: | ||
| 377 | tomoyo_del_path_group(p->element); | ||
| 378 | break; | ||
| 338 | default: | 379 | default: |
| 339 | printk(KERN_WARNING "Unknown type\n"); | 380 | printk(KERN_WARNING "Unknown type\n"); |
| 340 | break; | 381 | break; |
diff --git a/security/tomoyo/path_group.c b/security/tomoyo/path_group.c new file mode 100644 index 000000000000..c988041c8e1c --- /dev/null +++ b/security/tomoyo/path_group.c | |||
| @@ -0,0 +1,172 @@ | |||
| 1 | /* | ||
| 2 | * security/tomoyo/path_group.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005-2009 NTT DATA CORPORATION | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/slab.h> | ||
| 8 | #include "common.h" | ||
| 9 | /* The list for "struct ccs_path_group". */ | ||
| 10 | LIST_HEAD(tomoyo_path_group_list); | ||
| 11 | |||
| 12 | /** | ||
| 13 | * tomoyo_get_path_group - Allocate memory for "struct tomoyo_path_group". | ||
| 14 | * | ||
| 15 | * @group_name: The name of pathname group. | ||
| 16 | * | ||
| 17 | * Returns pointer to "struct tomoyo_path_group" on success, NULL otherwise. | ||
| 18 | */ | ||
| 19 | struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name) | ||
| 20 | { | ||
| 21 | struct tomoyo_path_group *entry = NULL; | ||
| 22 | struct tomoyo_path_group *group = NULL; | ||
| 23 | const struct tomoyo_path_info *saved_group_name; | ||
| 24 | int error = -ENOMEM; | ||
| 25 | if (!tomoyo_is_correct_path(group_name, 0, 0, 0) || | ||
| 26 | !group_name[0]) | ||
| 27 | return NULL; | ||
| 28 | saved_group_name = tomoyo_get_name(group_name); | ||
| 29 | if (!saved_group_name) | ||
| 30 | return NULL; | ||
| 31 | entry = kzalloc(sizeof(*entry), GFP_NOFS); | ||
| 32 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
| 33 | goto out; | ||
| 34 | list_for_each_entry_rcu(group, &tomoyo_path_group_list, list) { | ||
| 35 | if (saved_group_name != group->group_name) | ||
| 36 | continue; | ||
| 37 | atomic_inc(&group->users); | ||
| 38 | error = 0; | ||
| 39 | break; | ||
| 40 | } | ||
| 41 | if (error && tomoyo_memory_ok(entry)) { | ||
| 42 | INIT_LIST_HEAD(&entry->member_list); | ||
| 43 | entry->group_name = saved_group_name; | ||
| 44 | saved_group_name = NULL; | ||
| 45 | atomic_set(&entry->users, 1); | ||
| 46 | list_add_tail_rcu(&entry->list, &tomoyo_path_group_list); | ||
| 47 | group = entry; | ||
| 48 | entry = NULL; | ||
| 49 | error = 0; | ||
| 50 | } | ||
| 51 | mutex_unlock(&tomoyo_policy_lock); | ||
| 52 | out: | ||
| 53 | tomoyo_put_name(saved_group_name); | ||
| 54 | kfree(entry); | ||
| 55 | return !error ? group : NULL; | ||
| 56 | } | ||
| 57 | |||
| 58 | /** | ||
| 59 | * tomoyo_write_path_group_policy - Write "struct tomoyo_path_group" list. | ||
| 60 | * | ||
| 61 | * @data: String to parse. | ||
| 62 | * @is_delete: True if it is a delete request. | ||
| 63 | * | ||
| 64 | * Returns 0 on success, nagative value otherwise. | ||
| 65 | */ | ||
| 66 | int tomoyo_write_path_group_policy(char *data, const bool is_delete) | ||
| 67 | { | ||
| 68 | struct tomoyo_path_group *group; | ||
| 69 | struct tomoyo_path_group_member *member; | ||
| 70 | struct tomoyo_path_group_member e = { }; | ||
| 71 | int error = is_delete ? -ENOENT : -ENOMEM; | ||
| 72 | char *w[2]; | ||
| 73 | if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) | ||
| 74 | return -EINVAL; | ||
| 75 | group = tomoyo_get_path_group(w[0]); | ||
| 76 | if (!group) | ||
| 77 | return -ENOMEM; | ||
| 78 | e.member_name = tomoyo_get_name(w[1]); | ||
| 79 | if (!e.member_name) | ||
| 80 | goto out; | ||
| 81 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
| 82 | goto out; | ||
| 83 | list_for_each_entry_rcu(member, &group->member_list, list) { | ||
| 84 | if (member->member_name != e.member_name) | ||
| 85 | continue; | ||
| 86 | member->is_deleted = is_delete; | ||
| 87 | error = 0; | ||
| 88 | break; | ||
| 89 | } | ||
| 90 | if (!is_delete && error) { | ||
| 91 | struct tomoyo_path_group_member *entry = | ||
| 92 | tomoyo_commit_ok(&e, sizeof(e)); | ||
| 93 | if (entry) { | ||
| 94 | list_add_tail_rcu(&entry->list, &group->member_list); | ||
| 95 | error = 0; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | mutex_unlock(&tomoyo_policy_lock); | ||
| 99 | out: | ||
| 100 | tomoyo_put_name(e.member_name); | ||
| 101 | tomoyo_put_path_group(group); | ||
| 102 | return error; | ||
| 103 | } | ||
| 104 | |||
| 105 | /** | ||
| 106 | * tomoyo_read_path_group_policy - Read "struct tomoyo_path_group" list. | ||
| 107 | * | ||
| 108 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
| 109 | * | ||
| 110 | * Returns true on success, false otherwise. | ||
| 111 | * | ||
| 112 | * Caller holds tomoyo_read_lock(). | ||
| 113 | */ | ||
| 114 | bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head) | ||
| 115 | { | ||
| 116 | struct list_head *gpos; | ||
| 117 | struct list_head *mpos; | ||
| 118 | list_for_each_cookie(gpos, head->read_var1, &tomoyo_path_group_list) { | ||
| 119 | struct tomoyo_path_group *group; | ||
| 120 | group = list_entry(gpos, struct tomoyo_path_group, list); | ||
| 121 | list_for_each_cookie(mpos, head->read_var2, | ||
| 122 | &group->member_list) { | ||
| 123 | struct tomoyo_path_group_member *member; | ||
| 124 | member = list_entry(mpos, | ||
| 125 | struct tomoyo_path_group_member, | ||
| 126 | list); | ||
| 127 | if (member->is_deleted) | ||
| 128 | continue; | ||
| 129 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_PATH_GROUP | ||
| 130 | "%s %s\n", | ||
| 131 | group->group_name->name, | ||
| 132 | member->member_name->name)) | ||
| 133 | return false; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | return true; | ||
| 137 | } | ||
| 138 | |||
| 139 | /** | ||
| 140 | * tomoyo_path_matches_group - Check whether the given pathname matches members of the given pathname group. | ||
| 141 | * | ||
| 142 | * @pathname: The name of pathname. | ||
| 143 | * @group: Pointer to "struct tomoyo_path_group". | ||
| 144 | * @may_use_pattern: True if wild card is permitted. | ||
| 145 | * | ||
| 146 | * Returns true if @pathname matches pathnames in @group, false otherwise. | ||
| 147 | * | ||
| 148 | * Caller holds tomoyo_read_lock(). | ||
| 149 | */ | ||
| 150 | bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, | ||
| 151 | const struct tomoyo_path_group *group, | ||
| 152 | const bool may_use_pattern) | ||
| 153 | { | ||
| 154 | struct tomoyo_path_group_member *member; | ||
| 155 | bool matched = false; | ||
| 156 | list_for_each_entry_rcu(member, &group->member_list, list) { | ||
| 157 | if (member->is_deleted) | ||
| 158 | continue; | ||
| 159 | if (!member->member_name->is_patterned) { | ||
| 160 | if (tomoyo_pathcmp(pathname, member->member_name)) | ||
| 161 | continue; | ||
| 162 | } else if (may_use_pattern) { | ||
| 163 | if (!tomoyo_path_matches_pattern(pathname, | ||
| 164 | member->member_name)) | ||
| 165 | continue; | ||
| 166 | } else | ||
| 167 | continue; | ||
| 168 | matched = true; | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | return matched; | ||
| 172 | } | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index c225c65ce426..d1b96f019621 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
| @@ -139,7 +139,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, | |||
| 139 | */ | 139 | */ |
| 140 | char *tomoyo_realpath_from_path(struct path *path) | 140 | char *tomoyo_realpath_from_path(struct path *path) |
| 141 | { | 141 | { |
| 142 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_KERNEL); | 142 | char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS); |
| 143 | 143 | ||
| 144 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) | 144 | BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) |
| 145 | <= TOMOYO_MAX_PATHNAME_LEN - 1); | 145 | <= TOMOYO_MAX_PATHNAME_LEN - 1); |
| @@ -223,6 +223,25 @@ bool tomoyo_memory_ok(void *ptr) | |||
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | /** | 225 | /** |
| 226 | * tomoyo_commit_ok - Check memory quota. | ||
| 227 | * | ||
| 228 | * @data: Data to copy from. | ||
| 229 | * @size: Size in byte. | ||
| 230 | * | ||
| 231 | * Returns pointer to allocated memory on success, NULL otherwise. | ||
| 232 | */ | ||
| 233 | void *tomoyo_commit_ok(void *data, const unsigned int size) | ||
| 234 | { | ||
| 235 | void *ptr = kzalloc(size, GFP_NOFS); | ||
| 236 | if (tomoyo_memory_ok(ptr)) { | ||
| 237 | memmove(ptr, data, size); | ||
| 238 | memset(data, 0, size); | ||
| 239 | return ptr; | ||
| 240 | } | ||
| 241 | return NULL; | ||
| 242 | } | ||
| 243 | |||
| 244 | /** | ||
| 226 | * tomoyo_memory_free - Free memory for elements. | 245 | * tomoyo_memory_free - Free memory for elements. |
| 227 | * | 246 | * |
| 228 | * @ptr: Pointer to allocated memory. | 247 | * @ptr: Pointer to allocated memory. |
| @@ -240,8 +259,6 @@ void tomoyo_memory_free(void *ptr) | |||
| 240 | * "const struct tomoyo_path_info *". | 259 | * "const struct tomoyo_path_info *". |
| 241 | */ | 260 | */ |
| 242 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 261 | struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
| 243 | /* Lock for protecting tomoyo_name_list . */ | ||
| 244 | DEFINE_MUTEX(tomoyo_name_list_lock); | ||
| 245 | 262 | ||
| 246 | /** | 263 | /** |
| 247 | * tomoyo_get_name - Allocate permanent memory for string data. | 264 | * tomoyo_get_name - Allocate permanent memory for string data. |
| @@ -263,14 +280,15 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
| 263 | len = strlen(name) + 1; | 280 | len = strlen(name) + 1; |
| 264 | hash = full_name_hash((const unsigned char *) name, len - 1); | 281 | hash = full_name_hash((const unsigned char *) name, len - 1); |
| 265 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; | 282 | head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; |
| 266 | mutex_lock(&tomoyo_name_list_lock); | 283 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
| 284 | return NULL; | ||
| 267 | list_for_each_entry(ptr, head, list) { | 285 | list_for_each_entry(ptr, head, list) { |
| 268 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) | 286 | if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) |
| 269 | continue; | 287 | continue; |
| 270 | atomic_inc(&ptr->users); | 288 | atomic_inc(&ptr->users); |
| 271 | goto out; | 289 | goto out; |
| 272 | } | 290 | } |
| 273 | ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); | 291 | ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS); |
| 274 | allocated_len = ptr ? ksize(ptr) : 0; | 292 | allocated_len = ptr ? ksize(ptr) : 0; |
| 275 | if (!ptr || (tomoyo_quota_for_policy && | 293 | if (!ptr || (tomoyo_quota_for_policy && |
| 276 | atomic_read(&tomoyo_policy_memory_size) + allocated_len | 294 | atomic_read(&tomoyo_policy_memory_size) + allocated_len |
| @@ -290,7 +308,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) | |||
| 290 | tomoyo_fill_path_info(&ptr->entry); | 308 | tomoyo_fill_path_info(&ptr->entry); |
| 291 | list_add_tail(&ptr->list, head); | 309 | list_add_tail(&ptr->list, head); |
| 292 | out: | 310 | out: |
| 293 | mutex_unlock(&tomoyo_name_list_lock); | 311 | mutex_unlock(&tomoyo_policy_lock); |
| 294 | return ptr ? &ptr->entry : NULL; | 312 | return ptr ? &ptr->entry : NULL; |
| 295 | } | 313 | } |
| 296 | 314 | ||
