diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 11:06:39 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 11:06:39 -0400 |
| commit | bb2cbf5e9367d8598fecd0c48dead69560750223 (patch) | |
| tree | fb2c620451b90f41a31726bdd82077813f941e39 /security | |
| parent | e7fda6c4c3c1a7d6996dd75fd84670fa0b5d448f (diff) | |
| parent | 478d085524c57cf4283699f529d5a4c22188ea69 (diff) | |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"In this release:
- PKCS#7 parser for the key management subsystem from David Howells
- appoint Kees Cook as seccomp maintainer
- bugfixes and general maintenance across the subsystem"
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (94 commits)
X.509: Need to export x509_request_asymmetric_key()
netlabel: shorter names for the NetLabel catmap funcs/structs
netlabel: fix the catmap walking functions
netlabel: fix the horribly broken catmap functions
netlabel: fix a problem when setting bits below the previously lowest bit
PKCS#7: X.509 certificate issuer and subject are mandatory fields in the ASN.1
tpm: simplify code by using %*phN specifier
tpm: Provide a generic means to override the chip returned timeouts
tpm: missing tpm_chip_put in tpm_get_random()
tpm: Properly clean sysfs entries in error path
tpm: Add missing tpm_do_selftest to ST33 I2C driver
PKCS#7: Use x509_request_asymmetric_key()
Revert "selinux: fix the default socket labeling in sock_graft()"
X.509: x509_request_asymmetric_keys() doesn't need string length arguments
PKCS#7: fix sparse non static symbol warning
KEYS: revert encrypted key change
ima: add support for measuring and appraising firmware
firmware_class: perform new LSM checks
security: introduce kernel_fw_from_file hook
PKCS#7: Missing inclusion of linux/err.h
...
Diffstat (limited to 'security')
34 files changed, 781 insertions, 377 deletions
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 452567d3a08e..d97cba3e3849 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
| @@ -621,7 +621,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) | |||
| 621 | * There is no exception for unconfined as change_hat is not | 621 | * There is no exception for unconfined as change_hat is not |
| 622 | * available. | 622 | * available. |
| 623 | */ | 623 | */ |
| 624 | if (current->no_new_privs) | 624 | if (task_no_new_privs(current)) |
| 625 | return -EPERM; | 625 | return -EPERM; |
| 626 | 626 | ||
| 627 | /* released below */ | 627 | /* released below */ |
| @@ -776,7 +776,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, | |||
| 776 | * no_new_privs is set because this aways results in a reduction | 776 | * no_new_privs is set because this aways results in a reduction |
| 777 | * of permissions. | 777 | * of permissions. |
| 778 | */ | 778 | */ |
| 779 | if (current->no_new_privs && !unconfined(profile)) { | 779 | if (task_no_new_privs(current) && !unconfined(profile)) { |
| 780 | put_cred(cred); | 780 | put_cred(cred); |
| 781 | return -EPERM; | 781 | return -EPERM; |
| 782 | } | 782 | } |
diff --git a/security/capability.c b/security/capability.c index e76373de3129..a74fde6a7468 100644 --- a/security/capability.c +++ b/security/capability.c | |||
| @@ -401,6 +401,11 @@ static int cap_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
| 401 | return 0; | 401 | return 0; |
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | static int cap_kernel_fw_from_file(struct file *file, char *buf, size_t size) | ||
| 405 | { | ||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 404 | static int cap_kernel_module_request(char *kmod_name) | 409 | static int cap_kernel_module_request(char *kmod_name) |
| 405 | { | 410 | { |
| 406 | return 0; | 411 | return 0; |
| @@ -1015,6 +1020,7 @@ void __init security_fixup_ops(struct security_operations *ops) | |||
| 1015 | set_to_cap_if_null(ops, cred_transfer); | 1020 | set_to_cap_if_null(ops, cred_transfer); |
| 1016 | set_to_cap_if_null(ops, kernel_act_as); | 1021 | set_to_cap_if_null(ops, kernel_act_as); |
| 1017 | set_to_cap_if_null(ops, kernel_create_files_as); | 1022 | set_to_cap_if_null(ops, kernel_create_files_as); |
| 1023 | set_to_cap_if_null(ops, kernel_fw_from_file); | ||
| 1018 | set_to_cap_if_null(ops, kernel_module_request); | 1024 | set_to_cap_if_null(ops, kernel_module_request); |
| 1019 | set_to_cap_if_null(ops, kernel_module_from_file); | 1025 | set_to_cap_if_null(ops, kernel_module_from_file); |
| 1020 | set_to_cap_if_null(ops, task_fix_setuid); | 1026 | set_to_cap_if_null(ops, task_fix_setuid); |
diff --git a/security/commoncap.c b/security/commoncap.c index b9d613e0ef14..bab0611afc1e 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
| @@ -421,6 +421,9 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data | |||
| 421 | cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); | 421 | cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); |
| 422 | } | 422 | } |
| 423 | 423 | ||
| 424 | cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; | ||
| 425 | cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; | ||
| 426 | |||
| 424 | return 0; | 427 | return 0; |
| 425 | } | 428 | } |
| 426 | 429 | ||
| @@ -822,15 +825,20 @@ int cap_task_setnice(struct task_struct *p, int nice) | |||
| 822 | * Implement PR_CAPBSET_DROP. Attempt to remove the specified capability from | 825 | * Implement PR_CAPBSET_DROP. Attempt to remove the specified capability from |
| 823 | * the current task's bounding set. Returns 0 on success, -ve on error. | 826 | * the current task's bounding set. Returns 0 on success, -ve on error. |
| 824 | */ | 827 | */ |
| 825 | static long cap_prctl_drop(struct cred *new, unsigned long cap) | 828 | static int cap_prctl_drop(unsigned long cap) |
| 826 | { | 829 | { |
| 830 | struct cred *new; | ||
| 831 | |||
| 827 | if (!ns_capable(current_user_ns(), CAP_SETPCAP)) | 832 | if (!ns_capable(current_user_ns(), CAP_SETPCAP)) |
| 828 | return -EPERM; | 833 | return -EPERM; |
| 829 | if (!cap_valid(cap)) | 834 | if (!cap_valid(cap)) |
| 830 | return -EINVAL; | 835 | return -EINVAL; |
| 831 | 836 | ||
| 837 | new = prepare_creds(); | ||
| 838 | if (!new) | ||
| 839 | return -ENOMEM; | ||
| 832 | cap_lower(new->cap_bset, cap); | 840 | cap_lower(new->cap_bset, cap); |
| 833 | return 0; | 841 | return commit_creds(new); |
| 834 | } | 842 | } |
| 835 | 843 | ||
| 836 | /** | 844 | /** |
| @@ -848,26 +856,17 @@ static long cap_prctl_drop(struct cred *new, unsigned long cap) | |||
| 848 | int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | 856 | int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, |
| 849 | unsigned long arg4, unsigned long arg5) | 857 | unsigned long arg4, unsigned long arg5) |
| 850 | { | 858 | { |
| 859 | const struct cred *old = current_cred(); | ||
| 851 | struct cred *new; | 860 | struct cred *new; |
| 852 | long error = 0; | ||
| 853 | |||
| 854 | new = prepare_creds(); | ||
| 855 | if (!new) | ||
| 856 | return -ENOMEM; | ||
| 857 | 861 | ||
| 858 | switch (option) { | 862 | switch (option) { |
| 859 | case PR_CAPBSET_READ: | 863 | case PR_CAPBSET_READ: |
| 860 | error = -EINVAL; | ||
| 861 | if (!cap_valid(arg2)) | 864 | if (!cap_valid(arg2)) |
| 862 | goto error; | 865 | return -EINVAL; |
| 863 | error = !!cap_raised(new->cap_bset, arg2); | 866 | return !!cap_raised(old->cap_bset, arg2); |
| 864 | goto no_change; | ||
| 865 | 867 | ||
| 866 | case PR_CAPBSET_DROP: | 868 | case PR_CAPBSET_DROP: |
| 867 | error = cap_prctl_drop(new, arg2); | 869 | return cap_prctl_drop(arg2); |
| 868 | if (error < 0) | ||
| 869 | goto error; | ||
| 870 | goto changed; | ||
| 871 | 870 | ||
| 872 | /* | 871 | /* |
| 873 | * The next four prctl's remain to assist with transitioning a | 872 | * The next four prctl's remain to assist with transitioning a |
| @@ -889,10 +888,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 889 | * capability-based-privilege environment. | 888 | * capability-based-privilege environment. |
| 890 | */ | 889 | */ |
| 891 | case PR_SET_SECUREBITS: | 890 | case PR_SET_SECUREBITS: |
| 892 | error = -EPERM; | 891 | if ((((old->securebits & SECURE_ALL_LOCKS) >> 1) |
| 893 | if ((((new->securebits & SECURE_ALL_LOCKS) >> 1) | 892 | & (old->securebits ^ arg2)) /*[1]*/ |
| 894 | & (new->securebits ^ arg2)) /*[1]*/ | 893 | || ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ |
| 895 | || ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ | ||
| 896 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ | 894 | || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ |
| 897 | || (cap_capable(current_cred(), | 895 | || (cap_capable(current_cred(), |
| 898 | current_cred()->user_ns, CAP_SETPCAP, | 896 | current_cred()->user_ns, CAP_SETPCAP, |
| @@ -906,46 +904,39 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
| 906 | */ | 904 | */ |
| 907 | ) | 905 | ) |
| 908 | /* cannot change a locked bit */ | 906 | /* cannot change a locked bit */ |
| 909 | goto error; | 907 | return -EPERM; |
| 908 | |||
| 909 | new = prepare_creds(); | ||
| 910 | if (!new) | ||
| 911 | return -ENOMEM; | ||
| 910 | new->securebits = arg2; | 912 | new->securebits = arg2; |
| 911 | goto changed; | 913 | return commit_creds(new); |
| 912 | 914 | ||
| 913 | case PR_GET_SECUREBITS: | 915 | case PR_GET_SECUREBITS: |
| 914 | error = new->securebits; | 916 | return old->securebits; |
| 915 | goto no_change; | ||
| 916 | 917 | ||
| 917 | case PR_GET_KEEPCAPS: | 918 | case PR_GET_KEEPCAPS: |
| 918 | if (issecure(SECURE_KEEP_CAPS)) | 919 | return !!issecure(SECURE_KEEP_CAPS); |
| 919 | error = 1; | ||
| 920 | goto no_change; | ||
| 921 | 920 | ||
| 922 | case PR_SET_KEEPCAPS: | 921 | case PR_SET_KEEPCAPS: |
| 923 | error = -EINVAL; | ||
| 924 | if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ | 922 | if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ |
| 925 | goto error; | 923 | return -EINVAL; |
| 926 | error = -EPERM; | ||
| 927 | if (issecure(SECURE_KEEP_CAPS_LOCKED)) | 924 | if (issecure(SECURE_KEEP_CAPS_LOCKED)) |
| 928 | goto error; | 925 | return -EPERM; |
| 926 | |||
| 927 | new = prepare_creds(); | ||
| 928 | if (!new) | ||
| 929 | return -ENOMEM; | ||
| 929 | if (arg2) | 930 | if (arg2) |
| 930 | new->securebits |= issecure_mask(SECURE_KEEP_CAPS); | 931 | new->securebits |= issecure_mask(SECURE_KEEP_CAPS); |
| 931 | else | 932 | else |
| 932 | new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); | 933 | new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); |
| 933 | goto changed; | 934 | return commit_creds(new); |
| 934 | 935 | ||
| 935 | default: | 936 | default: |
| 936 | /* No functionality available - continue with default */ | 937 | /* No functionality available - continue with default */ |
| 937 | error = -ENOSYS; | 938 | return -ENOSYS; |
| 938 | goto error; | ||
| 939 | } | 939 | } |
| 940 | |||
| 941 | /* Functionality provided */ | ||
| 942 | changed: | ||
| 943 | return commit_creds(new); | ||
| 944 | |||
| 945 | no_change: | ||
| 946 | error: | ||
| 947 | abort_creds(new); | ||
| 948 | return error; | ||
| 949 | } | 940 | } |
| 950 | 941 | ||
| 951 | /** | 942 | /** |
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index b4af4ebc5be2..8d4fbff8b87c 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
| @@ -13,7 +13,9 @@ | |||
| 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 14 | 14 | ||
| 15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
| 16 | #include <linux/sched.h> | ||
| 16 | #include <linux/rbtree.h> | 17 | #include <linux/rbtree.h> |
| 18 | #include <linux/cred.h> | ||
| 17 | #include <linux/key-type.h> | 19 | #include <linux/key-type.h> |
| 18 | #include <linux/digsig.h> | 20 | #include <linux/digsig.h> |
| 19 | 21 | ||
| @@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX]; | |||
| 24 | static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { | 26 | static const char *keyring_name[INTEGRITY_KEYRING_MAX] = { |
| 25 | "_evm", | 27 | "_evm", |
| 26 | "_module", | 28 | "_module", |
| 29 | #ifndef CONFIG_IMA_TRUSTED_KEYRING | ||
| 27 | "_ima", | 30 | "_ima", |
| 31 | #else | ||
| 32 | ".ima", | ||
| 33 | #endif | ||
| 28 | }; | 34 | }; |
| 29 | 35 | ||
| 30 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 36 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
| @@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | |||
| 56 | 62 | ||
| 57 | return -EOPNOTSUPP; | 63 | return -EOPNOTSUPP; |
| 58 | } | 64 | } |
| 65 | |||
| 66 | int integrity_init_keyring(const unsigned int id) | ||
| 67 | { | ||
| 68 | const struct cred *cred = current_cred(); | ||
| 69 | int err = 0; | ||
| 70 | |||
| 71 | keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0), | ||
| 72 | KGIDT_INIT(0), cred, | ||
| 73 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | ||
| 74 | KEY_USR_VIEW | KEY_USR_READ | | ||
| 75 | KEY_USR_WRITE | KEY_USR_SEARCH), | ||
| 76 | KEY_ALLOC_NOT_IN_QUOTA, NULL); | ||
| 77 | if (!IS_ERR(keyring[id])) | ||
| 78 | set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags); | ||
| 79 | else { | ||
| 80 | err = PTR_ERR(keyring[id]); | ||
| 81 | pr_info("Can't allocate %s keyring (%d)\n", | ||
| 82 | keyring_name[id], err); | ||
| 83 | keyring[id] = NULL; | ||
| 84 | } | ||
| 85 | return err; | ||
| 86 | } | ||
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 81a27971d884..08758fbd496f 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig | |||
| @@ -123,3 +123,13 @@ config IMA_APPRAISE | |||
| 123 | For more information on integrity appraisal refer to: | 123 | For more information on integrity appraisal refer to: |
| 124 | <http://linux-ima.sourceforge.net> | 124 | <http://linux-ima.sourceforge.net> |
| 125 | If unsure, say N. | 125 | If unsure, say N. |
| 126 | |||
| 127 | config IMA_TRUSTED_KEYRING | ||
| 128 | bool "Require all keys on the .ima keyring be signed" | ||
| 129 | depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING | ||
| 130 | depends on INTEGRITY_ASYMMETRIC_KEYS | ||
| 131 | select KEYS_DEBUG_PROC_KEYS | ||
| 132 | default y | ||
| 133 | help | ||
| 134 | This option requires that all keys added to the .ima | ||
| 135 | keyring be signed by a key on the system trusted keyring. | ||
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index f79fa8be203c..57da4bd7ba0c 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h | |||
| @@ -158,7 +158,7 @@ struct integrity_iint_cache *integrity_iint_insert(struct inode *inode); | |||
| 158 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | 158 | struct integrity_iint_cache *integrity_iint_find(struct inode *inode); |
| 159 | 159 | ||
| 160 | /* IMA policy related functions */ | 160 | /* IMA policy related functions */ |
| 161 | enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, POST_SETATTR }; | 161 | enum ima_hooks { FILE_CHECK = 1, MMAP_CHECK, BPRM_CHECK, MODULE_CHECK, FIRMWARE_CHECK, POST_SETATTR }; |
| 162 | 162 | ||
| 163 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, | 163 | int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask, |
| 164 | int flags); | 164 | int flags); |
| @@ -171,6 +171,7 @@ void ima_delete_rules(void); | |||
| 171 | #define IMA_APPRAISE_ENFORCE 0x01 | 171 | #define IMA_APPRAISE_ENFORCE 0x01 |
| 172 | #define IMA_APPRAISE_FIX 0x02 | 172 | #define IMA_APPRAISE_FIX 0x02 |
| 173 | #define IMA_APPRAISE_MODULES 0x04 | 173 | #define IMA_APPRAISE_MODULES 0x04 |
| 174 | #define IMA_APPRAISE_FIRMWARE 0x08 | ||
| 174 | 175 | ||
| 175 | #ifdef CONFIG_IMA_APPRAISE | 176 | #ifdef CONFIG_IMA_APPRAISE |
| 176 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | 177 | int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, |
| @@ -249,4 +250,16 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op, | |||
| 249 | return -EINVAL; | 250 | return -EINVAL; |
| 250 | } | 251 | } |
| 251 | #endif /* CONFIG_IMA_LSM_RULES */ | 252 | #endif /* CONFIG_IMA_LSM_RULES */ |
| 253 | |||
| 254 | #ifdef CONFIG_IMA_TRUSTED_KEYRING | ||
| 255 | static inline int ima_init_keyring(const unsigned int id) | ||
| 256 | { | ||
| 257 | return integrity_init_keyring(id); | ||
| 258 | } | ||
| 259 | #else | ||
| 260 | static inline int ima_init_keyring(const unsigned int id) | ||
| 261 | { | ||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | #endif /* CONFIG_IMA_TRUSTED_KEYRING */ | ||
| 252 | #endif | 265 | #endif |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index d3113d4aaa3c..86bfd5c5df85 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
| @@ -75,6 +75,8 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, | |||
| 75 | return iint->ima_bprm_status; | 75 | return iint->ima_bprm_status; |
| 76 | case MODULE_CHECK: | 76 | case MODULE_CHECK: |
| 77 | return iint->ima_module_status; | 77 | return iint->ima_module_status; |
| 78 | case FIRMWARE_CHECK: | ||
| 79 | return iint->ima_firmware_status; | ||
| 78 | case FILE_CHECK: | 80 | case FILE_CHECK: |
| 79 | default: | 81 | default: |
| 80 | return iint->ima_file_status; | 82 | return iint->ima_file_status; |
| @@ -94,6 +96,9 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, | |||
| 94 | case MODULE_CHECK: | 96 | case MODULE_CHECK: |
| 95 | iint->ima_module_status = status; | 97 | iint->ima_module_status = status; |
| 96 | break; | 98 | break; |
| 99 | case FIRMWARE_CHECK: | ||
| 100 | iint->ima_firmware_status = status; | ||
| 101 | break; | ||
| 97 | case FILE_CHECK: | 102 | case FILE_CHECK: |
| 98 | default: | 103 | default: |
| 99 | iint->ima_file_status = status; | 104 | iint->ima_file_status = status; |
| @@ -113,6 +118,9 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) | |||
| 113 | case MODULE_CHECK: | 118 | case MODULE_CHECK: |
| 114 | iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED); | 119 | iint->flags |= (IMA_MODULE_APPRAISED | IMA_APPRAISED); |
| 115 | break; | 120 | break; |
| 121 | case FIRMWARE_CHECK: | ||
| 122 | iint->flags |= (IMA_FIRMWARE_APPRAISED | IMA_APPRAISED); | ||
| 123 | break; | ||
| 116 | case FILE_CHECK: | 124 | case FILE_CHECK: |
| 117 | default: | 125 | default: |
| 118 | iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); | 126 | iint->flags |= (IMA_FILE_APPRAISED | IMA_APPRAISED); |
| @@ -214,7 +222,7 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, | |||
| 214 | hash_start = 1; | 222 | hash_start = 1; |
| 215 | case IMA_XATTR_DIGEST: | 223 | case IMA_XATTR_DIGEST: |
| 216 | if (iint->flags & IMA_DIGSIG_REQUIRED) { | 224 | if (iint->flags & IMA_DIGSIG_REQUIRED) { |
| 217 | cause = "IMA signature required"; | 225 | cause = "IMA-signature-required"; |
| 218 | status = INTEGRITY_FAIL; | 226 | status = INTEGRITY_FAIL; |
| 219 | break; | 227 | break; |
| 220 | } | 228 | } |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index ccd0ac8fa9a0..0bd732843fe7 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 17 | 17 | ||
| 18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 19 | #include <linux/moduleparam.h> | ||
| 20 | #include <linux/ratelimit.h> | ||
| 19 | #include <linux/file.h> | 21 | #include <linux/file.h> |
| 20 | #include <linux/crypto.h> | 22 | #include <linux/crypto.h> |
| 21 | #include <linux/scatterlist.h> | 23 | #include <linux/scatterlist.h> |
| @@ -25,7 +27,45 @@ | |||
| 25 | #include <crypto/hash_info.h> | 27 | #include <crypto/hash_info.h> |
| 26 | #include "ima.h" | 28 | #include "ima.h" |
| 27 | 29 | ||
| 30 | struct ahash_completion { | ||
| 31 | struct completion completion; | ||
| 32 | int err; | ||
| 33 | }; | ||
| 34 | |||
| 35 | /* minimum file size for ahash use */ | ||
| 36 | static unsigned long ima_ahash_minsize; | ||
| 37 | module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644); | ||
| 38 | MODULE_PARM_DESC(ahash_minsize, "Minimum file size for ahash use"); | ||
| 39 | |||
| 40 | /* default is 0 - 1 page. */ | ||
| 41 | static int ima_maxorder; | ||
| 42 | static unsigned int ima_bufsize = PAGE_SIZE; | ||
| 43 | |||
| 44 | static int param_set_bufsize(const char *val, const struct kernel_param *kp) | ||
| 45 | { | ||
| 46 | unsigned long long size; | ||
| 47 | int order; | ||
| 48 | |||
| 49 | size = memparse(val, NULL); | ||
| 50 | order = get_order(size); | ||
| 51 | if (order >= MAX_ORDER) | ||
| 52 | return -EINVAL; | ||
| 53 | ima_maxorder = order; | ||
| 54 | ima_bufsize = PAGE_SIZE << order; | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | static struct kernel_param_ops param_ops_bufsize = { | ||
| 59 | .set = param_set_bufsize, | ||
| 60 | .get = param_get_uint, | ||
| 61 | }; | ||
| 62 | #define param_check_bufsize(name, p) __param_check(name, p, unsigned int) | ||
| 63 | |||
| 64 | module_param_named(ahash_bufsize, ima_bufsize, bufsize, 0644); | ||
| 65 | MODULE_PARM_DESC(ahash_bufsize, "Maximum ahash buffer size"); | ||
| 66 | |||
| 28 | static struct crypto_shash *ima_shash_tfm; | 67 | static struct crypto_shash *ima_shash_tfm; |
| 68 | static struct crypto_ahash *ima_ahash_tfm; | ||
| 29 | 69 | ||
| 30 | /** | 70 | /** |
| 31 | * ima_kernel_read - read file content | 71 | * ima_kernel_read - read file content |
| @@ -93,9 +133,246 @@ static void ima_free_tfm(struct crypto_shash *tfm) | |||
| 93 | crypto_free_shash(tfm); | 133 | crypto_free_shash(tfm); |
| 94 | } | 134 | } |
| 95 | 135 | ||
| 96 | /* | 136 | /** |
| 97 | * Calculate the MD5/SHA1 file digest | 137 | * ima_alloc_pages() - Allocate contiguous pages. |
| 138 | * @max_size: Maximum amount of memory to allocate. | ||
| 139 | * @allocated_size: Returned size of actual allocation. | ||
| 140 | * @last_warn: Should the min_size allocation warn or not. | ||
| 141 | * | ||
| 142 | * Tries to do opportunistic allocation for memory first trying to allocate | ||
| 143 | * max_size amount of memory and then splitting that until zero order is | ||
| 144 | * reached. Allocation is tried without generating allocation warnings unless | ||
| 145 | * last_warn is set. Last_warn set affects only last allocation of zero order. | ||
| 146 | * | ||
| 147 | * By default, ima_maxorder is 0 and it is equivalent to kmalloc(GFP_KERNEL) | ||
| 148 | * | ||
| 149 | * Return pointer to allocated memory, or NULL on failure. | ||
| 150 | */ | ||
| 151 | static void *ima_alloc_pages(loff_t max_size, size_t *allocated_size, | ||
| 152 | int last_warn) | ||
| 153 | { | ||
| 154 | void *ptr; | ||
| 155 | int order = ima_maxorder; | ||
| 156 | gfp_t gfp_mask = __GFP_WAIT | __GFP_NOWARN | __GFP_NORETRY; | ||
| 157 | |||
| 158 | if (order) | ||
| 159 | order = min(get_order(max_size), order); | ||
| 160 | |||
| 161 | for (; order; order--) { | ||
| 162 | ptr = (void *)__get_free_pages(gfp_mask, order); | ||
| 163 | if (ptr) { | ||
| 164 | *allocated_size = PAGE_SIZE << order; | ||
| 165 | return ptr; | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 169 | /* order is zero - one page */ | ||
| 170 | |||
| 171 | gfp_mask = GFP_KERNEL; | ||
| 172 | |||
| 173 | if (!last_warn) | ||
| 174 | gfp_mask |= __GFP_NOWARN; | ||
| 175 | |||
| 176 | ptr = (void *)__get_free_pages(gfp_mask, 0); | ||
| 177 | if (ptr) { | ||
| 178 | *allocated_size = PAGE_SIZE; | ||
| 179 | return ptr; | ||
| 180 | } | ||
| 181 | |||
| 182 | *allocated_size = 0; | ||
| 183 | return NULL; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * ima_free_pages() - Free pages allocated by ima_alloc_pages(). | ||
| 188 | * @ptr: Pointer to allocated pages. | ||
| 189 | * @size: Size of allocated buffer. | ||
| 98 | */ | 190 | */ |
| 191 | static void ima_free_pages(void *ptr, size_t size) | ||
| 192 | { | ||
| 193 | if (!ptr) | ||
| 194 | return; | ||
| 195 | free_pages((unsigned long)ptr, get_order(size)); | ||
| 196 | } | ||
| 197 | |||
| 198 | static struct crypto_ahash *ima_alloc_atfm(enum hash_algo algo) | ||
| 199 | { | ||
| 200 | struct crypto_ahash *tfm = ima_ahash_tfm; | ||
| 201 | int rc; | ||
| 202 | |||
| 203 | if ((algo != ima_hash_algo && algo < HASH_ALGO__LAST) || !tfm) { | ||
| 204 | tfm = crypto_alloc_ahash(hash_algo_name[algo], 0, 0); | ||
| 205 | if (!IS_ERR(tfm)) { | ||
| 206 | if (algo == ima_hash_algo) | ||
| 207 | ima_ahash_tfm = tfm; | ||
| 208 | } else { | ||
| 209 | rc = PTR_ERR(tfm); | ||
| 210 | pr_err("Can not allocate %s (reason: %d)\n", | ||
| 211 | hash_algo_name[algo], rc); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | return tfm; | ||
| 215 | } | ||
| 216 | |||
| 217 | static void ima_free_atfm(struct crypto_ahash *tfm) | ||
| 218 | { | ||
| 219 | if (tfm != ima_ahash_tfm) | ||
| 220 | crypto_free_ahash(tfm); | ||
| 221 | } | ||
| 222 | |||
| 223 | static void ahash_complete(struct crypto_async_request *req, int err) | ||
| 224 | { | ||
| 225 | struct ahash_completion *res = req->data; | ||
| 226 | |||
| 227 | if (err == -EINPROGRESS) | ||
| 228 | return; | ||
| 229 | res->err = err; | ||
| 230 | complete(&res->completion); | ||
| 231 | } | ||
| 232 | |||
| 233 | static int ahash_wait(int err, struct ahash_completion *res) | ||
| 234 | { | ||
| 235 | switch (err) { | ||
| 236 | case 0: | ||
| 237 | break; | ||
| 238 | case -EINPROGRESS: | ||
| 239 | case -EBUSY: | ||
| 240 | wait_for_completion(&res->completion); | ||
| 241 | reinit_completion(&res->completion); | ||
| 242 | err = res->err; | ||
| 243 | /* fall through */ | ||
| 244 | default: | ||
| 245 | pr_crit_ratelimited("ahash calculation failed: err: %d\n", err); | ||
| 246 | } | ||
| 247 | |||
| 248 | return err; | ||
| 249 | } | ||
| 250 | |||
| 251 | static int ima_calc_file_hash_atfm(struct file *file, | ||
| 252 | struct ima_digest_data *hash, | ||
| 253 | struct crypto_ahash *tfm) | ||
| 254 | { | ||
| 255 | loff_t i_size, offset; | ||
| 256 | char *rbuf[2] = { NULL, }; | ||
| 257 | int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0; | ||
| 258 | struct ahash_request *req; | ||
| 259 | struct scatterlist sg[1]; | ||
| 260 | struct ahash_completion res; | ||
| 261 | size_t rbuf_size[2]; | ||
| 262 | |||
| 263 | hash->length = crypto_ahash_digestsize(tfm); | ||
| 264 | |||
| 265 | req = ahash_request_alloc(tfm, GFP_KERNEL); | ||
| 266 | if (!req) | ||
| 267 | return -ENOMEM; | ||
| 268 | |||
| 269 | init_completion(&res.completion); | ||
| 270 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | | ||
| 271 | CRYPTO_TFM_REQ_MAY_SLEEP, | ||
| 272 | ahash_complete, &res); | ||
| 273 | |||
| 274 | rc = ahash_wait(crypto_ahash_init(req), &res); | ||
| 275 | if (rc) | ||
| 276 | goto out1; | ||
| 277 | |||
| 278 | i_size = i_size_read(file_inode(file)); | ||
| 279 | |||
| 280 | if (i_size == 0) | ||
| 281 | goto out2; | ||
| 282 | |||
| 283 | /* | ||
| 284 | * Try to allocate maximum size of memory. | ||
| 285 | * Fail if even a single page cannot be allocated. | ||
| 286 | */ | ||
| 287 | rbuf[0] = ima_alloc_pages(i_size, &rbuf_size[0], 1); | ||
| 288 | if (!rbuf[0]) { | ||
| 289 | rc = -ENOMEM; | ||
| 290 | goto out1; | ||
| 291 | } | ||
| 292 | |||
| 293 | /* Only allocate one buffer if that is enough. */ | ||
| 294 | if (i_size > rbuf_size[0]) { | ||
| 295 | /* | ||
| 296 | * Try to allocate secondary buffer. If that fails fallback to | ||
| 297 | * using single buffering. Use previous memory allocation size | ||
| 298 | * as baseline for possible allocation size. | ||
| 299 | */ | ||
| 300 | rbuf[1] = ima_alloc_pages(i_size - rbuf_size[0], | ||
| 301 | &rbuf_size[1], 0); | ||
| 302 | } | ||
| 303 | |||
| 304 | if (!(file->f_mode & FMODE_READ)) { | ||
| 305 | file->f_mode |= FMODE_READ; | ||
| 306 | read = 1; | ||
| 307 | } | ||
| 308 | |||
| 309 | for (offset = 0; offset < i_size; offset += rbuf_len) { | ||
| 310 | if (!rbuf[1] && offset) { | ||
| 311 | /* Not using two buffers, and it is not the first | ||
| 312 | * read/request, wait for the completion of the | ||
| 313 | * previous ahash_update() request. | ||
| 314 | */ | ||
| 315 | rc = ahash_wait(ahash_rc, &res); | ||
| 316 | if (rc) | ||
| 317 | goto out3; | ||
| 318 | } | ||
| 319 | /* read buffer */ | ||
| 320 | rbuf_len = min_t(loff_t, i_size - offset, rbuf_size[active]); | ||
| 321 | rc = ima_kernel_read(file, offset, rbuf[active], rbuf_len); | ||
| 322 | if (rc != rbuf_len) | ||
| 323 | goto out3; | ||
| 324 | |||
| 325 | if (rbuf[1] && offset) { | ||
| 326 | /* Using two buffers, and it is not the first | ||
| 327 | * read/request, wait for the completion of the | ||
| 328 | * previous ahash_update() request. | ||
| 329 | */ | ||
| 330 | rc = ahash_wait(ahash_rc, &res); | ||
| 331 | if (rc) | ||
| 332 | goto out3; | ||
| 333 | } | ||
| 334 | |||
| 335 | sg_init_one(&sg[0], rbuf[active], rbuf_len); | ||
| 336 | ahash_request_set_crypt(req, sg, NULL, rbuf_len); | ||
| 337 | |||
| 338 | ahash_rc = crypto_ahash_update(req); | ||
| 339 | |||
| 340 | if (rbuf[1]) | ||
| 341 | active = !active; /* swap buffers, if we use two */ | ||
| 342 | } | ||
| 343 | /* wait for the last update request to complete */ | ||
| 344 | rc = ahash_wait(ahash_rc, &res); | ||
| 345 | out3: | ||
| 346 | if (read) | ||
| 347 | file->f_mode &= ~FMODE_READ; | ||
| 348 | ima_free_pages(rbuf[0], rbuf_size[0]); | ||
| 349 | ima_free_pages(rbuf[1], rbuf_size[1]); | ||
| 350 | out2: | ||
| 351 | if (!rc) { | ||
| 352 | ahash_request_set_crypt(req, NULL, hash->digest, 0); | ||
| 353 | rc = ahash_wait(crypto_ahash_final(req), &res); | ||
| 354 | } | ||
| 355 | out1: | ||
| 356 | ahash_request_free(req); | ||
| 357 | return rc; | ||
| 358 | } | ||
| 359 | |||
| 360 | static int ima_calc_file_ahash(struct file *file, struct ima_digest_data *hash) | ||
| 361 | { | ||
| 362 | struct crypto_ahash *tfm; | ||
| 363 | int rc; | ||
| 364 | |||
| 365 | tfm = ima_alloc_atfm(hash->algo); | ||
| 366 | if (IS_ERR(tfm)) | ||
| 367 | return PTR_ERR(tfm); | ||
| 368 | |||
| 369 | rc = ima_calc_file_hash_atfm(file, hash, tfm); | ||
| 370 | |||
| 371 | ima_free_atfm(tfm); | ||
| 372 | |||
| 373 | return rc; | ||
| 374 | } | ||
| 375 | |||
| 99 | static int ima_calc_file_hash_tfm(struct file *file, | 376 | static int ima_calc_file_hash_tfm(struct file *file, |
| 100 | struct ima_digest_data *hash, | 377 | struct ima_digest_data *hash, |
| 101 | struct crypto_shash *tfm) | 378 | struct crypto_shash *tfm) |
| @@ -156,7 +433,7 @@ out: | |||
| 156 | return rc; | 433 | return rc; |
| 157 | } | 434 | } |
| 158 | 435 | ||
| 159 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | 436 | static int ima_calc_file_shash(struct file *file, struct ima_digest_data *hash) |
| 160 | { | 437 | { |
| 161 | struct crypto_shash *tfm; | 438 | struct crypto_shash *tfm; |
| 162 | int rc; | 439 | int rc; |
| @@ -173,6 +450,35 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | |||
| 173 | } | 450 | } |
| 174 | 451 | ||
| 175 | /* | 452 | /* |
| 453 | * ima_calc_file_hash - calculate file hash | ||
| 454 | * | ||
| 455 | * Asynchronous hash (ahash) allows using HW acceleration for calculating | ||
| 456 | * a hash. ahash performance varies for different data sizes on different | ||
| 457 | * crypto accelerators. shash performance might be better for smaller files. | ||
| 458 | * The 'ima.ahash_minsize' module parameter allows specifying the best | ||
| 459 | * minimum file size for using ahash on the system. | ||
| 460 | * | ||
| 461 | * If the ima.ahash_minsize parameter is not specified, this function uses | ||
| 462 | * shash for the hash calculation. If ahash fails, it falls back to using | ||
| 463 | * shash. | ||
| 464 | */ | ||
| 465 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | ||
| 466 | { | ||
| 467 | loff_t i_size; | ||
| 468 | int rc; | ||
| 469 | |||
| 470 | i_size = i_size_read(file_inode(file)); | ||
| 471 | |||
| 472 | if (ima_ahash_minsize && i_size >= ima_ahash_minsize) { | ||
| 473 | rc = ima_calc_file_ahash(file, hash); | ||
| 474 | if (!rc) | ||
| 475 | return 0; | ||
| 476 | } | ||
| 477 | |||
| 478 | return ima_calc_file_shash(file, hash); | ||
| 479 | } | ||
| 480 | |||
| 481 | /* | ||
| 176 | * Calculate the hash of template data | 482 | * Calculate the hash of template data |
| 177 | */ | 483 | */ |
| 178 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, | 484 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 09baa335ebc7..2917f980bf30 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -88,8 +88,6 @@ static void ima_rdwr_violation_check(struct file *file) | |||
| 88 | if (!S_ISREG(inode->i_mode) || !ima_initialized) | 88 | if (!S_ISREG(inode->i_mode) || !ima_initialized) |
| 89 | return; | 89 | return; |
| 90 | 90 | ||
| 91 | mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */ | ||
| 92 | |||
| 93 | if (mode & FMODE_WRITE) { | 91 | if (mode & FMODE_WRITE) { |
| 94 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { | 92 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { |
| 95 | struct integrity_iint_cache *iint; | 93 | struct integrity_iint_cache *iint; |
| @@ -104,8 +102,6 @@ static void ima_rdwr_violation_check(struct file *file) | |||
| 104 | send_writers = true; | 102 | send_writers = true; |
| 105 | } | 103 | } |
| 106 | 104 | ||
| 107 | mutex_unlock(&inode->i_mutex); | ||
| 108 | |||
| 109 | if (!send_tomtou && !send_writers) | 105 | if (!send_tomtou && !send_writers) |
| 110 | return; | 106 | return; |
| 111 | 107 | ||
| @@ -163,7 +159,7 @@ static int process_measurement(struct file *file, const char *filename, | |||
| 163 | { | 159 | { |
| 164 | struct inode *inode = file_inode(file); | 160 | struct inode *inode = file_inode(file); |
| 165 | struct integrity_iint_cache *iint; | 161 | struct integrity_iint_cache *iint; |
| 166 | struct ima_template_desc *template_desc = ima_template_desc_current(); | 162 | struct ima_template_desc *template_desc; |
| 167 | char *pathbuf = NULL; | 163 | char *pathbuf = NULL; |
| 168 | const char *pathname = NULL; | 164 | const char *pathname = NULL; |
| 169 | int rc = -ENOMEM, action, must_appraise, _func; | 165 | int rc = -ENOMEM, action, must_appraise, _func; |
| @@ -207,6 +203,7 @@ static int process_measurement(struct file *file, const char *filename, | |||
| 207 | goto out_digsig; | 203 | goto out_digsig; |
| 208 | } | 204 | } |
| 209 | 205 | ||
| 206 | template_desc = ima_template_desc_current(); | ||
| 210 | if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) { | 207 | if (strcmp(template_desc->name, IMA_TEMPLATE_IMA_NAME) == 0) { |
| 211 | if (action & IMA_APPRAISE_SUBMASK) | 208 | if (action & IMA_APPRAISE_SUBMASK) |
| 212 | xattr_ptr = &xattr_value; | 209 | xattr_ptr = &xattr_value; |
| @@ -322,14 +319,31 @@ int ima_module_check(struct file *file) | |||
| 322 | return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK); | 319 | return process_measurement(file, NULL, MAY_EXEC, MODULE_CHECK); |
| 323 | } | 320 | } |
| 324 | 321 | ||
| 322 | int ima_fw_from_file(struct file *file, char *buf, size_t size) | ||
| 323 | { | ||
| 324 | if (!file) { | ||
| 325 | if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && | ||
| 326 | (ima_appraise & IMA_APPRAISE_ENFORCE)) | ||
| 327 | return -EACCES; /* INTEGRITY_UNKNOWN */ | ||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | return process_measurement(file, NULL, MAY_EXEC, FIRMWARE_CHECK); | ||
| 331 | } | ||
| 332 | |||
| 325 | static int __init init_ima(void) | 333 | static int __init init_ima(void) |
| 326 | { | 334 | { |
| 327 | int error; | 335 | int error; |
| 328 | 336 | ||
| 329 | hash_setup(CONFIG_IMA_DEFAULT_HASH); | 337 | hash_setup(CONFIG_IMA_DEFAULT_HASH); |
| 330 | error = ima_init(); | 338 | error = ima_init(); |
| 331 | if (!error) | 339 | if (error) |
| 332 | ima_initialized = 1; | 340 | goto out; |
| 341 | |||
| 342 | error = ima_init_keyring(INTEGRITY_KEYRING_IMA); | ||
| 343 | if (error) | ||
| 344 | goto out; | ||
| 345 | ima_initialized = 1; | ||
| 346 | out: | ||
| 333 | return error; | 347 | return error; |
| 334 | } | 348 | } |
| 335 | 349 | ||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 40a7488f6721..07099a8bc283 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
| @@ -84,6 +84,7 @@ static struct ima_rule_entry default_rules[] = { | |||
| 84 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID, | 84 | {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID, |
| 85 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, | 85 | .flags = IMA_FUNC | IMA_MASK | IMA_UID}, |
| 86 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, | 86 | {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, |
| 87 | {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, | ||
| 87 | }; | 88 | }; |
| 88 | 89 | ||
| 89 | static struct ima_rule_entry default_appraise_rules[] = { | 90 | static struct ima_rule_entry default_appraise_rules[] = { |
| @@ -241,6 +242,8 @@ static int get_subaction(struct ima_rule_entry *rule, int func) | |||
| 241 | return IMA_BPRM_APPRAISE; | 242 | return IMA_BPRM_APPRAISE; |
| 242 | case MODULE_CHECK: | 243 | case MODULE_CHECK: |
| 243 | return IMA_MODULE_APPRAISE; | 244 | return IMA_MODULE_APPRAISE; |
| 245 | case FIRMWARE_CHECK: | ||
| 246 | return IMA_FIRMWARE_APPRAISE; | ||
| 244 | case FILE_CHECK: | 247 | case FILE_CHECK: |
| 245 | default: | 248 | default: |
| 246 | return IMA_FILE_APPRAISE; | 249 | return IMA_FILE_APPRAISE; |
| @@ -332,7 +335,7 @@ void __init ima_init_policy(void) | |||
| 332 | void ima_update_policy(void) | 335 | void ima_update_policy(void) |
| 333 | { | 336 | { |
| 334 | static const char op[] = "policy_update"; | 337 | static const char op[] = "policy_update"; |
| 335 | const char *cause = "already exists"; | 338 | const char *cause = "already-exists"; |
| 336 | int result = 1; | 339 | int result = 1; |
| 337 | int audit_info = 0; | 340 | int audit_info = 0; |
| 338 | 341 | ||
| @@ -486,6 +489,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
| 486 | entry->func = FILE_CHECK; | 489 | entry->func = FILE_CHECK; |
| 487 | else if (strcmp(args[0].from, "MODULE_CHECK") == 0) | 490 | else if (strcmp(args[0].from, "MODULE_CHECK") == 0) |
| 488 | entry->func = MODULE_CHECK; | 491 | entry->func = MODULE_CHECK; |
| 492 | else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0) | ||
| 493 | entry->func = FIRMWARE_CHECK; | ||
| 489 | else if ((strcmp(args[0].from, "FILE_MMAP") == 0) | 494 | else if ((strcmp(args[0].from, "FILE_MMAP") == 0) |
| 490 | || (strcmp(args[0].from, "MMAP_CHECK") == 0)) | 495 | || (strcmp(args[0].from, "MMAP_CHECK") == 0)) |
| 491 | entry->func = MMAP_CHECK; | 496 | entry->func = MMAP_CHECK; |
| @@ -636,6 +641,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
| 636 | result = -EINVAL; | 641 | result = -EINVAL; |
| 637 | else if (entry->func == MODULE_CHECK) | 642 | else if (entry->func == MODULE_CHECK) |
| 638 | ima_appraise |= IMA_APPRAISE_MODULES; | 643 | ima_appraise |= IMA_APPRAISE_MODULES; |
| 644 | else if (entry->func == FIRMWARE_CHECK) | ||
| 645 | ima_appraise |= IMA_APPRAISE_FIRMWARE; | ||
| 639 | audit_log_format(ab, "res=%d", !result); | 646 | audit_log_format(ab, "res=%d", !result); |
| 640 | audit_log_end(ab); | 647 | audit_log_end(ab); |
| 641 | return result; | 648 | return result; |
| @@ -659,7 +666,7 @@ ssize_t ima_parse_add_rule(char *rule) | |||
| 659 | /* Prevent installed policy from changing */ | 666 | /* Prevent installed policy from changing */ |
| 660 | if (ima_rules != &ima_default_rules) { | 667 | if (ima_rules != &ima_default_rules) { |
| 661 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | 668 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
| 662 | NULL, op, "already exists", | 669 | NULL, op, "already-exists", |
| 663 | -EACCES, audit_info); | 670 | -EACCES, audit_info); |
| 664 | return -EACCES; | 671 | return -EACCES; |
| 665 | } | 672 | } |
| @@ -685,7 +692,7 @@ ssize_t ima_parse_add_rule(char *rule) | |||
| 685 | if (result) { | 692 | if (result) { |
| 686 | kfree(entry); | 693 | kfree(entry); |
| 687 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, | 694 | integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, |
| 688 | NULL, op, "invalid policy", result, | 695 | NULL, op, "invalid-policy", result, |
| 689 | audit_info); | 696 | audit_info); |
| 690 | return result; | 697 | return result; |
| 691 | } | 698 | } |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 33c0a70f6b15..19b8e314ca96 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
| @@ -46,10 +46,14 @@ | |||
| 46 | #define IMA_BPRM_APPRAISED 0x00002000 | 46 | #define IMA_BPRM_APPRAISED 0x00002000 |
| 47 | #define IMA_MODULE_APPRAISE 0x00004000 | 47 | #define IMA_MODULE_APPRAISE 0x00004000 |
| 48 | #define IMA_MODULE_APPRAISED 0x00008000 | 48 | #define IMA_MODULE_APPRAISED 0x00008000 |
| 49 | #define IMA_FIRMWARE_APPRAISE 0x00010000 | ||
| 50 | #define IMA_FIRMWARE_APPRAISED 0x00020000 | ||
| 49 | #define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ | 51 | #define IMA_APPRAISE_SUBMASK (IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \ |
| 50 | IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE) | 52 | IMA_BPRM_APPRAISE | IMA_MODULE_APPRAISE | \ |
| 53 | IMA_FIRMWARE_APPRAISE) | ||
| 51 | #define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ | 54 | #define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \ |
| 52 | IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED) | 55 | IMA_BPRM_APPRAISED | IMA_MODULE_APPRAISED | \ |
| 56 | IMA_FIRMWARE_APPRAISED) | ||
| 53 | 57 | ||
| 54 | enum evm_ima_xattr_type { | 58 | enum evm_ima_xattr_type { |
| 55 | IMA_XATTR_DIGEST = 0x01, | 59 | IMA_XATTR_DIGEST = 0x01, |
| @@ -104,6 +108,7 @@ struct integrity_iint_cache { | |||
| 104 | enum integrity_status ima_mmap_status:4; | 108 | enum integrity_status ima_mmap_status:4; |
| 105 | enum integrity_status ima_bprm_status:4; | 109 | enum integrity_status ima_bprm_status:4; |
| 106 | enum integrity_status ima_module_status:4; | 110 | enum integrity_status ima_module_status:4; |
| 111 | enum integrity_status ima_firmware_status:4; | ||
| 107 | enum integrity_status evm_status:4; | 112 | enum integrity_status evm_status:4; |
| 108 | struct ima_digest_data *ima_hash; | 113 | struct ima_digest_data *ima_hash; |
| 109 | }; | 114 | }; |
| @@ -124,6 +129,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | |||
| 124 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, | 129 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
| 125 | const char *digest, int digestlen); | 130 | const char *digest, int digestlen); |
| 126 | 131 | ||
| 132 | int integrity_init_keyring(const unsigned int id); | ||
| 127 | #else | 133 | #else |
| 128 | 134 | ||
| 129 | static inline int integrity_digsig_verify(const unsigned int id, | 135 | static inline int integrity_digsig_verify(const unsigned int id, |
| @@ -133,6 +139,10 @@ static inline int integrity_digsig_verify(const unsigned int id, | |||
| 133 | return -EOPNOTSUPP; | 139 | return -EOPNOTSUPP; |
| 134 | } | 140 | } |
| 135 | 141 | ||
| 142 | static inline int integrity_init_keyring(const unsigned int id) | ||
| 143 | { | ||
| 144 | return 0; | ||
| 145 | } | ||
| 136 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ | 146 | #endif /* CONFIG_INTEGRITY_SIGNATURE */ |
| 137 | 147 | ||
| 138 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS | 148 | #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS |
diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 8137b27d641d..c2f91a0cf889 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c | |||
| @@ -34,7 +34,9 @@ MODULE_LICENSE("GPL"); | |||
| 34 | struct key_type key_type_big_key = { | 34 | struct key_type key_type_big_key = { |
| 35 | .name = "big_key", | 35 | .name = "big_key", |
| 36 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 36 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
| 37 | .instantiate = big_key_instantiate, | 37 | .preparse = big_key_preparse, |
| 38 | .free_preparse = big_key_free_preparse, | ||
| 39 | .instantiate = generic_key_instantiate, | ||
| 38 | .match = user_match, | 40 | .match = user_match, |
| 39 | .revoke = big_key_revoke, | 41 | .revoke = big_key_revoke, |
| 40 | .destroy = big_key_destroy, | 42 | .destroy = big_key_destroy, |
| @@ -43,11 +45,11 @@ struct key_type key_type_big_key = { | |||
| 43 | }; | 45 | }; |
| 44 | 46 | ||
| 45 | /* | 47 | /* |
| 46 | * Instantiate a big key | 48 | * Preparse a big key |
| 47 | */ | 49 | */ |
| 48 | int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | 50 | int big_key_preparse(struct key_preparsed_payload *prep) |
| 49 | { | 51 | { |
| 50 | struct path *path = (struct path *)&key->payload.data2; | 52 | struct path *path = (struct path *)&prep->payload; |
| 51 | struct file *file; | 53 | struct file *file; |
| 52 | ssize_t written; | 54 | ssize_t written; |
| 53 | size_t datalen = prep->datalen; | 55 | size_t datalen = prep->datalen; |
| @@ -58,11 +60,9 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 58 | goto error; | 60 | goto error; |
| 59 | 61 | ||
| 60 | /* Set an arbitrary quota */ | 62 | /* Set an arbitrary quota */ |
| 61 | ret = key_payload_reserve(key, 16); | 63 | prep->quotalen = 16; |
| 62 | if (ret < 0) | ||
| 63 | goto error; | ||
| 64 | 64 | ||
| 65 | key->type_data.x[1] = datalen; | 65 | prep->type_data[1] = (void *)(unsigned long)datalen; |
| 66 | 66 | ||
| 67 | if (datalen > BIG_KEY_FILE_THRESHOLD) { | 67 | if (datalen > BIG_KEY_FILE_THRESHOLD) { |
| 68 | /* Create a shmem file to store the data in. This will permit the data | 68 | /* Create a shmem file to store the data in. This will permit the data |
| @@ -73,7 +73,7 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 73 | file = shmem_kernel_file_setup("", datalen, 0); | 73 | file = shmem_kernel_file_setup("", datalen, 0); |
| 74 | if (IS_ERR(file)) { | 74 | if (IS_ERR(file)) { |
| 75 | ret = PTR_ERR(file); | 75 | ret = PTR_ERR(file); |
| 76 | goto err_quota; | 76 | goto error; |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | written = kernel_write(file, prep->data, prep->datalen, 0); | 79 | written = kernel_write(file, prep->data, prep->datalen, 0); |
| @@ -93,24 +93,33 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | |||
| 93 | } else { | 93 | } else { |
| 94 | /* Just store the data in a buffer */ | 94 | /* Just store the data in a buffer */ |
| 95 | void *data = kmalloc(datalen, GFP_KERNEL); | 95 | void *data = kmalloc(datalen, GFP_KERNEL); |
| 96 | if (!data) { | 96 | if (!data) |
| 97 | ret = -ENOMEM; | 97 | return -ENOMEM; |
| 98 | goto err_quota; | ||
| 99 | } | ||
| 100 | 98 | ||
| 101 | key->payload.data = memcpy(data, prep->data, prep->datalen); | 99 | prep->payload[0] = memcpy(data, prep->data, prep->datalen); |
| 102 | } | 100 | } |
| 103 | return 0; | 101 | return 0; |
| 104 | 102 | ||
| 105 | err_fput: | 103 | err_fput: |
| 106 | fput(file); | 104 | fput(file); |
| 107 | err_quota: | ||
| 108 | key_payload_reserve(key, 0); | ||
| 109 | error: | 105 | error: |
| 110 | return ret; | 106 | return ret; |
| 111 | } | 107 | } |
| 112 | 108 | ||
| 113 | /* | 109 | /* |
| 110 | * Clear preparsement. | ||
| 111 | */ | ||
| 112 | void big_key_free_preparse(struct key_preparsed_payload *prep) | ||
| 113 | { | ||
| 114 | if (prep->datalen > BIG_KEY_FILE_THRESHOLD) { | ||
| 115 | struct path *path = (struct path *)&prep->payload; | ||
| 116 | path_put(path); | ||
| 117 | } else { | ||
| 118 | kfree(prep->payload[0]); | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | /* | ||
| 114 | * dispose of the links from a revoked keyring | 123 | * dispose of the links from a revoked keyring |
| 115 | * - called with the key sem write-locked | 124 | * - called with the key sem write-locked |
| 116 | */ | 125 | */ |
diff --git a/security/keys/key.c b/security/keys/key.c index 2048a110e7f1..b90a68c4e2c4 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -437,6 +437,11 @@ static int __key_instantiate_and_link(struct key *key, | |||
| 437 | /* disable the authorisation key */ | 437 | /* disable the authorisation key */ |
| 438 | if (authkey) | 438 | if (authkey) |
| 439 | key_revoke(authkey); | 439 | key_revoke(authkey); |
| 440 | |||
| 441 | if (prep->expiry != TIME_T_MAX) { | ||
| 442 | key->expiry = prep->expiry; | ||
| 443 | key_schedule_gc(prep->expiry + key_gc_delay); | ||
| 444 | } | ||
| 440 | } | 445 | } |
| 441 | } | 446 | } |
| 442 | 447 | ||
| @@ -479,6 +484,7 @@ int key_instantiate_and_link(struct key *key, | |||
| 479 | prep.data = data; | 484 | prep.data = data; |
| 480 | prep.datalen = datalen; | 485 | prep.datalen = datalen; |
| 481 | prep.quotalen = key->type->def_datalen; | 486 | prep.quotalen = key->type->def_datalen; |
| 487 | prep.expiry = TIME_T_MAX; | ||
| 482 | if (key->type->preparse) { | 488 | if (key->type->preparse) { |
| 483 | ret = key->type->preparse(&prep); | 489 | ret = key->type->preparse(&prep); |
| 484 | if (ret < 0) | 490 | if (ret < 0) |
| @@ -488,7 +494,7 @@ int key_instantiate_and_link(struct key *key, | |||
| 488 | if (keyring) { | 494 | if (keyring) { |
| 489 | ret = __key_link_begin(keyring, &key->index_key, &edit); | 495 | ret = __key_link_begin(keyring, &key->index_key, &edit); |
| 490 | if (ret < 0) | 496 | if (ret < 0) |
| 491 | goto error_free_preparse; | 497 | goto error; |
| 492 | } | 498 | } |
| 493 | 499 | ||
| 494 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); | 500 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit); |
| @@ -496,10 +502,9 @@ int key_instantiate_and_link(struct key *key, | |||
| 496 | if (keyring) | 502 | if (keyring) |
| 497 | __key_link_end(keyring, &key->index_key, edit); | 503 | __key_link_end(keyring, &key->index_key, edit); |
| 498 | 504 | ||
| 499 | error_free_preparse: | 505 | error: |
| 500 | if (key->type->preparse) | 506 | if (key->type->preparse) |
| 501 | key->type->free_preparse(&prep); | 507 | key->type->free_preparse(&prep); |
| 502 | error: | ||
| 503 | return ret; | 508 | return ret; |
| 504 | } | 509 | } |
| 505 | 510 | ||
| @@ -811,11 +816,12 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 811 | prep.datalen = plen; | 816 | prep.datalen = plen; |
| 812 | prep.quotalen = index_key.type->def_datalen; | 817 | prep.quotalen = index_key.type->def_datalen; |
| 813 | prep.trusted = flags & KEY_ALLOC_TRUSTED; | 818 | prep.trusted = flags & KEY_ALLOC_TRUSTED; |
| 819 | prep.expiry = TIME_T_MAX; | ||
| 814 | if (index_key.type->preparse) { | 820 | if (index_key.type->preparse) { |
| 815 | ret = index_key.type->preparse(&prep); | 821 | ret = index_key.type->preparse(&prep); |
| 816 | if (ret < 0) { | 822 | if (ret < 0) { |
| 817 | key_ref = ERR_PTR(ret); | 823 | key_ref = ERR_PTR(ret); |
| 818 | goto error_put_type; | 824 | goto error_free_prep; |
| 819 | } | 825 | } |
| 820 | if (!index_key.description) | 826 | if (!index_key.description) |
| 821 | index_key.description = prep.description; | 827 | index_key.description = prep.description; |
| @@ -941,6 +947,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
| 941 | prep.data = payload; | 947 | prep.data = payload; |
| 942 | prep.datalen = plen; | 948 | prep.datalen = plen; |
| 943 | prep.quotalen = key->type->def_datalen; | 949 | prep.quotalen = key->type->def_datalen; |
| 950 | prep.expiry = TIME_T_MAX; | ||
| 944 | if (key->type->preparse) { | 951 | if (key->type->preparse) { |
| 945 | ret = key->type->preparse(&prep); | 952 | ret = key->type->preparse(&prep); |
| 946 | if (ret < 0) | 953 | if (ret < 0) |
| @@ -956,9 +963,9 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
| 956 | 963 | ||
| 957 | up_write(&key->sem); | 964 | up_write(&key->sem); |
| 958 | 965 | ||
| 966 | error: | ||
| 959 | if (key->type->preparse) | 967 | if (key->type->preparse) |
| 960 | key->type->free_preparse(&prep); | 968 | key->type->free_preparse(&prep); |
| 961 | error: | ||
| 962 | return ret; | 969 | return ret; |
| 963 | } | 970 | } |
| 964 | EXPORT_SYMBOL(key_update); | 971 | EXPORT_SYMBOL(key_update); |
| @@ -1024,6 +1031,38 @@ void key_invalidate(struct key *key) | |||
| 1024 | EXPORT_SYMBOL(key_invalidate); | 1031 | EXPORT_SYMBOL(key_invalidate); |
| 1025 | 1032 | ||
| 1026 | /** | 1033 | /** |
| 1034 | * generic_key_instantiate - Simple instantiation of a key from preparsed data | ||
| 1035 | * @key: The key to be instantiated | ||
| 1036 | * @prep: The preparsed data to load. | ||
| 1037 | * | ||
| 1038 | * Instantiate a key from preparsed data. We assume we can just copy the data | ||
| 1039 | * in directly and clear the old pointers. | ||
| 1040 | * | ||
| 1041 | * This can be pointed to directly by the key type instantiate op pointer. | ||
| 1042 | */ | ||
| 1043 | int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep) | ||
| 1044 | { | ||
| 1045 | int ret; | ||
| 1046 | |||
| 1047 | pr_devel("==>%s()\n", __func__); | ||
| 1048 | |||
| 1049 | ret = key_payload_reserve(key, prep->quotalen); | ||
| 1050 | if (ret == 0) { | ||
| 1051 | key->type_data.p[0] = prep->type_data[0]; | ||
| 1052 | key->type_data.p[1] = prep->type_data[1]; | ||
| 1053 | rcu_assign_keypointer(key, prep->payload[0]); | ||
| 1054 | key->payload.data2[1] = prep->payload[1]; | ||
| 1055 | prep->type_data[0] = NULL; | ||
| 1056 | prep->type_data[1] = NULL; | ||
| 1057 | prep->payload[0] = NULL; | ||
| 1058 | prep->payload[1] = NULL; | ||
| 1059 | } | ||
| 1060 | pr_devel("<==%s() = %d\n", __func__, ret); | ||
| 1061 | return ret; | ||
| 1062 | } | ||
| 1063 | EXPORT_SYMBOL(generic_key_instantiate); | ||
| 1064 | |||
| 1065 | /** | ||
| 1027 | * register_key_type - Register a type of key. | 1066 | * register_key_type - Register a type of key. |
| 1028 | * @ktype: The new key type. | 1067 | * @ktype: The new key type. |
| 1029 | * | 1068 | * |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index cd5bd0cef25d..e26f860e5f2e 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type, | |||
| 37 | return ret; | 37 | return ret; |
| 38 | if (ret == 0 || ret >= len) | 38 | if (ret == 0 || ret >= len) |
| 39 | return -EINVAL; | 39 | return -EINVAL; |
| 40 | if (type[0] == '.') | ||
| 41 | return -EPERM; | ||
| 42 | type[len - 1] = '\0'; | 40 | type[len - 1] = '\0'; |
| 43 | return 0; | 41 | return 0; |
| 44 | } | 42 | } |
| @@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
| 86 | if (!*description) { | 84 | if (!*description) { |
| 87 | kfree(description); | 85 | kfree(description); |
| 88 | description = NULL; | 86 | description = NULL; |
| 87 | } else if ((description[0] == '.') && | ||
| 88 | (strncmp(type, "keyring", 7) == 0)) { | ||
| 89 | ret = -EPERM; | ||
| 90 | goto error2; | ||
| 89 | } | 91 | } |
| 90 | } | 92 | } |
| 91 | 93 | ||
| @@ -404,12 +406,25 @@ long keyctl_invalidate_key(key_serial_t id) | |||
| 404 | key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); | 406 | key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); |
| 405 | if (IS_ERR(key_ref)) { | 407 | if (IS_ERR(key_ref)) { |
| 406 | ret = PTR_ERR(key_ref); | 408 | ret = PTR_ERR(key_ref); |
| 409 | |||
| 410 | /* Root is permitted to invalidate certain special keys */ | ||
| 411 | if (capable(CAP_SYS_ADMIN)) { | ||
| 412 | key_ref = lookup_user_key(id, 0, 0); | ||
| 413 | if (IS_ERR(key_ref)) | ||
| 414 | goto error; | ||
| 415 | if (test_bit(KEY_FLAG_ROOT_CAN_INVAL, | ||
| 416 | &key_ref_to_ptr(key_ref)->flags)) | ||
| 417 | goto invalidate; | ||
| 418 | goto error_put; | ||
| 419 | } | ||
| 420 | |||
| 407 | goto error; | 421 | goto error; |
| 408 | } | 422 | } |
| 409 | 423 | ||
| 424 | invalidate: | ||
| 410 | key_invalidate(key_ref_to_ptr(key_ref)); | 425 | key_invalidate(key_ref_to_ptr(key_ref)); |
| 411 | ret = 0; | 426 | ret = 0; |
| 412 | 427 | error_put: | |
| 413 | key_ref_put(key_ref); | 428 | key_ref_put(key_ref); |
| 414 | error: | 429 | error: |
| 415 | kleave(" = %ld", ret); | 430 | kleave(" = %ld", ret); |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 9cf2575f0d97..8314a7d2104d 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -73,6 +73,8 @@ static inline unsigned keyring_hash(const char *desc) | |||
| 73 | * can be treated as ordinary keys in addition to having their own special | 73 | * can be treated as ordinary keys in addition to having their own special |
| 74 | * operations. | 74 | * operations. |
| 75 | */ | 75 | */ |
| 76 | static int keyring_preparse(struct key_preparsed_payload *prep); | ||
| 77 | static void keyring_free_preparse(struct key_preparsed_payload *prep); | ||
| 76 | static int keyring_instantiate(struct key *keyring, | 78 | static int keyring_instantiate(struct key *keyring, |
| 77 | struct key_preparsed_payload *prep); | 79 | struct key_preparsed_payload *prep); |
| 78 | static void keyring_revoke(struct key *keyring); | 80 | static void keyring_revoke(struct key *keyring); |
| @@ -84,6 +86,8 @@ static long keyring_read(const struct key *keyring, | |||
| 84 | struct key_type key_type_keyring = { | 86 | struct key_type key_type_keyring = { |
| 85 | .name = "keyring", | 87 | .name = "keyring", |
| 86 | .def_datalen = 0, | 88 | .def_datalen = 0, |
| 89 | .preparse = keyring_preparse, | ||
| 90 | .free_preparse = keyring_free_preparse, | ||
| 87 | .instantiate = keyring_instantiate, | 91 | .instantiate = keyring_instantiate, |
| 88 | .match = user_match, | 92 | .match = user_match, |
| 89 | .revoke = keyring_revoke, | 93 | .revoke = keyring_revoke, |
| @@ -123,6 +127,21 @@ static void keyring_publish_name(struct key *keyring) | |||
| 123 | } | 127 | } |
| 124 | 128 | ||
| 125 | /* | 129 | /* |
| 130 | * Preparse a keyring payload | ||
| 131 | */ | ||
| 132 | static int keyring_preparse(struct key_preparsed_payload *prep) | ||
| 133 | { | ||
| 134 | return prep->datalen != 0 ? -EINVAL : 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | /* | ||
| 138 | * Free a preparse of a user defined key payload | ||
| 139 | */ | ||
| 140 | static void keyring_free_preparse(struct key_preparsed_payload *prep) | ||
| 141 | { | ||
| 142 | } | ||
| 143 | |||
| 144 | /* | ||
| 126 | * Initialise a keyring. | 145 | * Initialise a keyring. |
| 127 | * | 146 | * |
| 128 | * Returns 0 on success, -EINVAL if given any data. | 147 | * Returns 0 on success, -EINVAL if given any data. |
| @@ -130,17 +149,10 @@ static void keyring_publish_name(struct key *keyring) | |||
| 130 | static int keyring_instantiate(struct key *keyring, | 149 | static int keyring_instantiate(struct key *keyring, |
| 131 | struct key_preparsed_payload *prep) | 150 | struct key_preparsed_payload *prep) |
| 132 | { | 151 | { |
| 133 | int ret; | 152 | assoc_array_init(&keyring->keys); |
| 134 | 153 | /* make the keyring available by name if it has one */ | |
| 135 | ret = -EINVAL; | 154 | keyring_publish_name(keyring); |
| 136 | if (prep->datalen == 0) { | 155 | return 0; |
| 137 | assoc_array_init(&keyring->keys); | ||
| 138 | /* make the keyring available by name if it has one */ | ||
| 139 | keyring_publish_name(keyring); | ||
| 140 | ret = 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | return ret; | ||
| 144 | } | 156 | } |
| 145 | 157 | ||
| 146 | /* | 158 | /* |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 7495a93b4b90..842e6f410d50 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | #include "internal.h" | 20 | #include "internal.h" |
| 21 | #include <keys/user-type.h> | 21 | #include <keys/user-type.h> |
| 22 | 22 | ||
| 23 | static int request_key_auth_preparse(struct key_preparsed_payload *); | ||
| 24 | static void request_key_auth_free_preparse(struct key_preparsed_payload *); | ||
| 23 | static int request_key_auth_instantiate(struct key *, | 25 | static int request_key_auth_instantiate(struct key *, |
| 24 | struct key_preparsed_payload *); | 26 | struct key_preparsed_payload *); |
| 25 | static void request_key_auth_describe(const struct key *, struct seq_file *); | 27 | static void request_key_auth_describe(const struct key *, struct seq_file *); |
| @@ -33,6 +35,8 @@ static long request_key_auth_read(const struct key *, char __user *, size_t); | |||
| 33 | struct key_type key_type_request_key_auth = { | 35 | struct key_type key_type_request_key_auth = { |
| 34 | .name = ".request_key_auth", | 36 | .name = ".request_key_auth", |
| 35 | .def_datalen = sizeof(struct request_key_auth), | 37 | .def_datalen = sizeof(struct request_key_auth), |
| 38 | .preparse = request_key_auth_preparse, | ||
| 39 | .free_preparse = request_key_auth_free_preparse, | ||
| 36 | .instantiate = request_key_auth_instantiate, | 40 | .instantiate = request_key_auth_instantiate, |
| 37 | .describe = request_key_auth_describe, | 41 | .describe = request_key_auth_describe, |
| 38 | .revoke = request_key_auth_revoke, | 42 | .revoke = request_key_auth_revoke, |
| @@ -40,6 +44,15 @@ struct key_type key_type_request_key_auth = { | |||
| 40 | .read = request_key_auth_read, | 44 | .read = request_key_auth_read, |
| 41 | }; | 45 | }; |
| 42 | 46 | ||
| 47 | int request_key_auth_preparse(struct key_preparsed_payload *prep) | ||
| 48 | { | ||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | void request_key_auth_free_preparse(struct key_preparsed_payload *prep) | ||
| 53 | { | ||
| 54 | } | ||
| 55 | |||
| 43 | /* | 56 | /* |
| 44 | * Instantiate a request-key authorisation key. | 57 | * Instantiate a request-key authorisation key. |
| 45 | */ | 58 | */ |
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index faa2caeb593f..eee340011f2b 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c | |||
| @@ -27,7 +27,9 @@ static int logon_vet_description(const char *desc); | |||
| 27 | struct key_type key_type_user = { | 27 | struct key_type key_type_user = { |
| 28 | .name = "user", | 28 | .name = "user", |
| 29 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 29 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
| 30 | .instantiate = user_instantiate, | 30 | .preparse = user_preparse, |
| 31 | .free_preparse = user_free_preparse, | ||
| 32 | .instantiate = generic_key_instantiate, | ||
| 31 | .update = user_update, | 33 | .update = user_update, |
| 32 | .match = user_match, | 34 | .match = user_match, |
| 33 | .revoke = user_revoke, | 35 | .revoke = user_revoke, |
| @@ -47,7 +49,9 @@ EXPORT_SYMBOL_GPL(key_type_user); | |||
| 47 | struct key_type key_type_logon = { | 49 | struct key_type key_type_logon = { |
| 48 | .name = "logon", | 50 | .name = "logon", |
| 49 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 51 | .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
| 50 | .instantiate = user_instantiate, | 52 | .preparse = user_preparse, |
| 53 | .free_preparse = user_free_preparse, | ||
| 54 | .instantiate = generic_key_instantiate, | ||
| 51 | .update = user_update, | 55 | .update = user_update, |
| 52 | .match = user_match, | 56 | .match = user_match, |
| 53 | .revoke = user_revoke, | 57 | .revoke = user_revoke, |
| @@ -58,38 +62,37 @@ struct key_type key_type_logon = { | |||
| 58 | EXPORT_SYMBOL_GPL(key_type_logon); | 62 | EXPORT_SYMBOL_GPL(key_type_logon); |
| 59 | 63 | ||
| 60 | /* | 64 | /* |
| 61 | * instantiate a user defined key | 65 | * Preparse a user defined key payload |
| 62 | */ | 66 | */ |
| 63 | int user_instantiate(struct key *key, struct key_preparsed_payload *prep) | 67 | int user_preparse(struct key_preparsed_payload *prep) |
| 64 | { | 68 | { |
| 65 | struct user_key_payload *upayload; | 69 | struct user_key_payload *upayload; |
| 66 | size_t datalen = prep->datalen; | 70 | size_t datalen = prep->datalen; |
| 67 | int ret; | ||
| 68 | 71 | ||
| 69 | ret = -EINVAL; | ||
| 70 | if (datalen <= 0 || datalen > 32767 || !prep->data) | 72 | if (datalen <= 0 || datalen > 32767 || !prep->data) |
| 71 | goto error; | 73 | return -EINVAL; |
| 72 | |||
| 73 | ret = key_payload_reserve(key, datalen); | ||
| 74 | if (ret < 0) | ||
| 75 | goto error; | ||
| 76 | 74 | ||
| 77 | ret = -ENOMEM; | ||
| 78 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); | 75 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); |
| 79 | if (!upayload) | 76 | if (!upayload) |
| 80 | goto error; | 77 | return -ENOMEM; |
| 81 | 78 | ||
| 82 | /* attach the data */ | 79 | /* attach the data */ |
| 80 | prep->quotalen = datalen; | ||
| 81 | prep->payload[0] = upayload; | ||
| 83 | upayload->datalen = datalen; | 82 | upayload->datalen = datalen; |
| 84 | memcpy(upayload->data, prep->data, datalen); | 83 | memcpy(upayload->data, prep->data, datalen); |
| 85 | rcu_assign_keypointer(key, upayload); | 84 | return 0; |
| 86 | ret = 0; | ||
| 87 | |||
| 88 | error: | ||
| 89 | return ret; | ||
| 90 | } | 85 | } |
| 86 | EXPORT_SYMBOL_GPL(user_preparse); | ||
| 91 | 87 | ||
| 92 | EXPORT_SYMBOL_GPL(user_instantiate); | 88 | /* |
| 89 | * Free a preparse of a user defined key payload | ||
| 90 | */ | ||
| 91 | void user_free_preparse(struct key_preparsed_payload *prep) | ||
| 92 | { | ||
| 93 | kfree(prep->payload[0]); | ||
| 94 | } | ||
| 95 | EXPORT_SYMBOL_GPL(user_free_preparse); | ||
| 93 | 96 | ||
| 94 | /* | 97 | /* |
| 95 | * update a user defined key | 98 | * update a user defined key |
diff --git a/security/security.c b/security/security.c index 31614e9e96e5..e41b1a8d7644 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -845,6 +845,17 @@ int security_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
| 845 | return security_ops->kernel_create_files_as(new, inode); | 845 | return security_ops->kernel_create_files_as(new, inode); |
| 846 | } | 846 | } |
| 847 | 847 | ||
| 848 | int security_kernel_fw_from_file(struct file *file, char *buf, size_t size) | ||
| 849 | { | ||
| 850 | int ret; | ||
| 851 | |||
| 852 | ret = security_ops->kernel_fw_from_file(file, buf, size); | ||
| 853 | if (ret) | ||
| 854 | return ret; | ||
| 855 | return ima_fw_from_file(file, buf, size); | ||
| 856 | } | ||
| 857 | EXPORT_SYMBOL_GPL(security_kernel_fw_from_file); | ||
| 858 | |||
| 848 | int security_kernel_module_request(char *kmod_name) | 859 | int security_kernel_module_request(char *kmod_name) |
| 849 | { | 860 | { |
| 850 | return security_ops->kernel_module_request(kmod_name); | 861 | return security_ops->kernel_module_request(kmod_name); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 83d06db34d03..b0e940497e23 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -161,6 +161,17 @@ static int selinux_peerlbl_enabled(void) | |||
| 161 | return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled()); | 161 | return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled()); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static int selinux_netcache_avc_callback(u32 event) | ||
| 165 | { | ||
| 166 | if (event == AVC_CALLBACK_RESET) { | ||
| 167 | sel_netif_flush(); | ||
| 168 | sel_netnode_flush(); | ||
| 169 | sel_netport_flush(); | ||
| 170 | synchronize_net(); | ||
| 171 | } | ||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 164 | /* | 175 | /* |
| 165 | * initialise the security for the init task | 176 | * initialise the security for the init task |
| 166 | */ | 177 | */ |
| @@ -5993,6 +6004,9 @@ static __init int selinux_init(void) | |||
| 5993 | if (register_security(&selinux_ops)) | 6004 | if (register_security(&selinux_ops)) |
| 5994 | panic("SELinux: Unable to register with kernel.\n"); | 6005 | panic("SELinux: Unable to register with kernel.\n"); |
| 5995 | 6006 | ||
| 6007 | if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) | ||
| 6008 | panic("SELinux: Unable to register AVC netcache callback\n"); | ||
| 6009 | |||
| 5996 | if (selinux_enforcing) | 6010 | if (selinux_enforcing) |
| 5997 | printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n"); | 6011 | printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n"); |
| 5998 | else | 6012 | else |
diff --git a/security/selinux/include/netif.h b/security/selinux/include/netif.h index 43d507242b42..57c6eae81eac 100644 --- a/security/selinux/include/netif.h +++ b/security/selinux/include/netif.h | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #ifndef _SELINUX_NETIF_H_ | 17 | #ifndef _SELINUX_NETIF_H_ |
| 18 | #define _SELINUX_NETIF_H_ | 18 | #define _SELINUX_NETIF_H_ |
| 19 | 19 | ||
| 20 | void sel_netif_flush(void); | ||
| 21 | |||
| 20 | int sel_netif_sid(int ifindex, u32 *sid); | 22 | int sel_netif_sid(int ifindex, u32 *sid); |
| 21 | 23 | ||
| 22 | #endif /* _SELINUX_NETIF_H_ */ | 24 | #endif /* _SELINUX_NETIF_H_ */ |
diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h index df7a5ed6c694..937668dd3024 100644 --- a/security/selinux/include/netnode.h +++ b/security/selinux/include/netnode.h | |||
| @@ -27,6 +27,8 @@ | |||
| 27 | #ifndef _SELINUX_NETNODE_H | 27 | #ifndef _SELINUX_NETNODE_H |
| 28 | #define _SELINUX_NETNODE_H | 28 | #define _SELINUX_NETNODE_H |
| 29 | 29 | ||
| 30 | void sel_netnode_flush(void); | ||
| 31 | |||
| 30 | int sel_netnode_sid(void *addr, u16 family, u32 *sid); | 32 | int sel_netnode_sid(void *addr, u16 family, u32 *sid); |
| 31 | 33 | ||
| 32 | #endif | 34 | #endif |
diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h index 4d965b83d735..d1ce896b2cb0 100644 --- a/security/selinux/include/netport.h +++ b/security/selinux/include/netport.h | |||
| @@ -26,6 +26,8 @@ | |||
| 26 | #ifndef _SELINUX_NETPORT_H | 26 | #ifndef _SELINUX_NETPORT_H |
| 27 | #define _SELINUX_NETPORT_H | 27 | #define _SELINUX_NETPORT_H |
| 28 | 28 | ||
| 29 | void sel_netport_flush(void); | ||
| 30 | |||
| 29 | int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid); | 31 | int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid); |
| 30 | 32 | ||
| 31 | #endif | 33 | #endif |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index ce7852cf526b..d1e0b239b602 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #ifndef _SELINUX_SECURITY_H_ | 8 | #ifndef _SELINUX_SECURITY_H_ |
| 9 | #define _SELINUX_SECURITY_H_ | 9 | #define _SELINUX_SECURITY_H_ |
| 10 | 10 | ||
| 11 | #include <linux/compiler.h> | ||
| 11 | #include <linux/dcache.h> | 12 | #include <linux/dcache.h> |
| 12 | #include <linux/magic.h> | 13 | #include <linux/magic.h> |
| 13 | #include <linux/types.h> | 14 | #include <linux/types.h> |
| @@ -220,7 +221,7 @@ struct selinux_kernel_status { | |||
| 220 | /* | 221 | /* |
| 221 | * The version > 0 supports above members. | 222 | * The version > 0 supports above members. |
| 222 | */ | 223 | */ |
| 223 | } __attribute__((packed)); | 224 | } __packed; |
| 224 | 225 | ||
| 225 | extern void selinux_status_update_setenforce(int enforcing); | 226 | extern void selinux_status_update_setenforce(int enforcing); |
| 226 | extern void selinux_status_update_policyload(int seqno); | 227 | extern void selinux_status_update_policyload(int seqno); |
diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 694e9e43855f..3c3de4ca0ebc 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c | |||
| @@ -240,7 +240,7 @@ static void sel_netif_kill(int ifindex) | |||
| 240 | * Remove all entries from the network interface table. | 240 | * Remove all entries from the network interface table. |
| 241 | * | 241 | * |
| 242 | */ | 242 | */ |
| 243 | static void sel_netif_flush(void) | 243 | void sel_netif_flush(void) |
| 244 | { | 244 | { |
| 245 | int idx; | 245 | int idx; |
| 246 | struct sel_netif *netif; | 246 | struct sel_netif *netif; |
| @@ -252,15 +252,6 @@ static void sel_netif_flush(void) | |||
| 252 | spin_unlock_bh(&sel_netif_lock); | 252 | spin_unlock_bh(&sel_netif_lock); |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | static int sel_netif_avc_callback(u32 event) | ||
| 256 | { | ||
| 257 | if (event == AVC_CALLBACK_RESET) { | ||
| 258 | sel_netif_flush(); | ||
| 259 | synchronize_net(); | ||
| 260 | } | ||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 264 | static int sel_netif_netdev_notifier_handler(struct notifier_block *this, | 255 | static int sel_netif_netdev_notifier_handler(struct notifier_block *this, |
| 265 | unsigned long event, void *ptr) | 256 | unsigned long event, void *ptr) |
| 266 | { | 257 | { |
| @@ -291,10 +282,6 @@ static __init int sel_netif_init(void) | |||
| 291 | 282 | ||
| 292 | register_netdevice_notifier(&sel_netif_netdev_notifier); | 283 | register_netdevice_notifier(&sel_netif_netdev_notifier); |
| 293 | 284 | ||
| 294 | err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET); | ||
| 295 | if (err) | ||
| 296 | panic("avc_add_callback() failed, error %d\n", err); | ||
| 297 | |||
| 298 | return err; | 285 | return err; |
| 299 | } | 286 | } |
| 300 | 287 | ||
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 03a72c32afd7..ddf315260839 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
| @@ -283,7 +283,7 @@ int sel_netnode_sid(void *addr, u16 family, u32 *sid) | |||
| 283 | * Remove all entries from the network address table. | 283 | * Remove all entries from the network address table. |
| 284 | * | 284 | * |
| 285 | */ | 285 | */ |
| 286 | static void sel_netnode_flush(void) | 286 | void sel_netnode_flush(void) |
| 287 | { | 287 | { |
| 288 | unsigned int idx; | 288 | unsigned int idx; |
| 289 | struct sel_netnode *node, *node_tmp; | 289 | struct sel_netnode *node, *node_tmp; |
| @@ -300,15 +300,6 @@ static void sel_netnode_flush(void) | |||
| 300 | spin_unlock_bh(&sel_netnode_lock); | 300 | spin_unlock_bh(&sel_netnode_lock); |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | static int sel_netnode_avc_callback(u32 event) | ||
| 304 | { | ||
| 305 | if (event == AVC_CALLBACK_RESET) { | ||
| 306 | sel_netnode_flush(); | ||
| 307 | synchronize_net(); | ||
| 308 | } | ||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | static __init int sel_netnode_init(void) | 303 | static __init int sel_netnode_init(void) |
| 313 | { | 304 | { |
| 314 | int iter; | 305 | int iter; |
| @@ -322,10 +313,6 @@ static __init int sel_netnode_init(void) | |||
| 322 | sel_netnode_hash[iter].size = 0; | 313 | sel_netnode_hash[iter].size = 0; |
| 323 | } | 314 | } |
| 324 | 315 | ||
| 325 | ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET); | ||
| 326 | if (ret != 0) | ||
| 327 | panic("avc_add_callback() failed, error %d\n", ret); | ||
| 328 | |||
| 329 | return ret; | 316 | return ret; |
| 330 | } | 317 | } |
| 331 | 318 | ||
diff --git a/security/selinux/netport.c b/security/selinux/netport.c index d35379781c2c..73ac6784d091 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c | |||
| @@ -217,7 +217,7 @@ int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid) | |||
| 217 | * Remove all entries from the network address table. | 217 | * Remove all entries from the network address table. |
| 218 | * | 218 | * |
| 219 | */ | 219 | */ |
| 220 | static void sel_netport_flush(void) | 220 | void sel_netport_flush(void) |
| 221 | { | 221 | { |
| 222 | unsigned int idx; | 222 | unsigned int idx; |
| 223 | struct sel_netport *port, *port_tmp; | 223 | struct sel_netport *port, *port_tmp; |
| @@ -234,15 +234,6 @@ static void sel_netport_flush(void) | |||
| 234 | spin_unlock_bh(&sel_netport_lock); | 234 | spin_unlock_bh(&sel_netport_lock); |
| 235 | } | 235 | } |
| 236 | 236 | ||
| 237 | static int sel_netport_avc_callback(u32 event) | ||
| 238 | { | ||
| 239 | if (event == AVC_CALLBACK_RESET) { | ||
| 240 | sel_netport_flush(); | ||
| 241 | synchronize_net(); | ||
| 242 | } | ||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | static __init int sel_netport_init(void) | 237 | static __init int sel_netport_init(void) |
| 247 | { | 238 | { |
| 248 | int iter; | 239 | int iter; |
| @@ -256,10 +247,6 @@ static __init int sel_netport_init(void) | |||
| 256 | sel_netport_hash[iter].size = 0; | 247 | sel_netport_hash[iter].size = 0; |
| 257 | } | 248 | } |
| 258 | 249 | ||
| 259 | ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET); | ||
| 260 | if (ret != 0) | ||
| 261 | panic("avc_add_callback() failed, error %d\n", ret); | ||
| 262 | |||
| 263 | return ret; | 250 | return ret; |
| 264 | } | 251 | } |
| 265 | 252 | ||
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 377d148e7157..62c6773be0b7 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
| @@ -402,19 +402,14 @@ static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp) | |||
| 402 | int rc; | 402 | int rc; |
| 403 | struct cond_expr *expr = NULL, *last = NULL; | 403 | struct cond_expr *expr = NULL, *last = NULL; |
| 404 | 404 | ||
| 405 | rc = next_entry(buf, fp, sizeof(u32)); | 405 | rc = next_entry(buf, fp, sizeof(u32) * 2); |
| 406 | if (rc) | 406 | if (rc) |
| 407 | return rc; | 407 | goto err; |
| 408 | 408 | ||
| 409 | node->cur_state = le32_to_cpu(buf[0]); | 409 | node->cur_state = le32_to_cpu(buf[0]); |
| 410 | 410 | ||
| 411 | len = 0; | ||
| 412 | rc = next_entry(buf, fp, sizeof(u32)); | ||
| 413 | if (rc) | ||
| 414 | return rc; | ||
| 415 | |||
| 416 | /* expr */ | 411 | /* expr */ |
| 417 | len = le32_to_cpu(buf[0]); | 412 | len = le32_to_cpu(buf[1]); |
| 418 | 413 | ||
| 419 | for (i = 0; i < len; i++) { | 414 | for (i = 0; i < len; i++) { |
| 420 | rc = next_entry(buf, fp, sizeof(u32) * 2); | 415 | rc = next_entry(buf, fp, sizeof(u32) * 2); |
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 820313a04d49..afe6a269ec17 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c | |||
| @@ -86,51 +86,36 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src) | |||
| 86 | * | 86 | * |
| 87 | */ | 87 | */ |
| 88 | int ebitmap_netlbl_export(struct ebitmap *ebmap, | 88 | int ebitmap_netlbl_export(struct ebitmap *ebmap, |
| 89 | struct netlbl_lsm_secattr_catmap **catmap) | 89 | struct netlbl_lsm_catmap **catmap) |
| 90 | { | 90 | { |
| 91 | struct ebitmap_node *e_iter = ebmap->node; | 91 | struct ebitmap_node *e_iter = ebmap->node; |
| 92 | struct netlbl_lsm_secattr_catmap *c_iter; | 92 | unsigned long e_map; |
| 93 | u32 cmap_idx, cmap_sft; | 93 | u32 offset; |
| 94 | int i; | 94 | unsigned int iter; |
| 95 | 95 | int rc; | |
| 96 | /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, | ||
| 97 | * however, it is not always compatible with an array of unsigned long | ||
| 98 | * in ebitmap_node. | ||
| 99 | * In addition, you should pay attention the following implementation | ||
| 100 | * assumes unsigned long has a width equal with or less than 64-bit. | ||
| 101 | */ | ||
| 102 | 96 | ||
| 103 | if (e_iter == NULL) { | 97 | if (e_iter == NULL) { |
| 104 | *catmap = NULL; | 98 | *catmap = NULL; |
| 105 | return 0; | 99 | return 0; |
| 106 | } | 100 | } |
| 107 | 101 | ||
| 108 | c_iter = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | 102 | if (*catmap != NULL) |
| 109 | if (c_iter == NULL) | 103 | netlbl_catmap_free(*catmap); |
| 110 | return -ENOMEM; | 104 | *catmap = NULL; |
| 111 | *catmap = c_iter; | ||
| 112 | c_iter->startbit = e_iter->startbit & ~(NETLBL_CATMAP_SIZE - 1); | ||
| 113 | 105 | ||
| 114 | while (e_iter) { | 106 | while (e_iter) { |
| 115 | for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { | 107 | offset = e_iter->startbit; |
| 116 | unsigned int delta, e_startbit, c_endbit; | 108 | for (iter = 0; iter < EBITMAP_UNIT_NUMS; iter++) { |
| 117 | 109 | e_map = e_iter->maps[iter]; | |
| 118 | e_startbit = e_iter->startbit + i * EBITMAP_UNIT_SIZE; | 110 | if (e_map != 0) { |
| 119 | c_endbit = c_iter->startbit + NETLBL_CATMAP_SIZE; | 111 | rc = netlbl_catmap_setlong(catmap, |
| 120 | if (e_startbit >= c_endbit) { | 112 | offset, |
| 121 | c_iter->next | 113 | e_map, |
| 122 | = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | 114 | GFP_ATOMIC); |
| 123 | if (c_iter->next == NULL) | 115 | if (rc != 0) |
| 124 | goto netlbl_export_failure; | 116 | goto netlbl_export_failure; |
| 125 | c_iter = c_iter->next; | ||
| 126 | c_iter->startbit | ||
| 127 | = e_startbit & ~(NETLBL_CATMAP_SIZE - 1); | ||
| 128 | } | 117 | } |
| 129 | delta = e_startbit - c_iter->startbit; | 118 | offset += EBITMAP_UNIT_SIZE; |
| 130 | cmap_idx = delta / NETLBL_CATMAP_MAPSIZE; | ||
| 131 | cmap_sft = delta % NETLBL_CATMAP_MAPSIZE; | ||
| 132 | c_iter->bitmap[cmap_idx] | ||
| 133 | |= e_iter->maps[i] << cmap_sft; | ||
| 134 | } | 119 | } |
| 135 | e_iter = e_iter->next; | 120 | e_iter = e_iter->next; |
| 136 | } | 121 | } |
| @@ -138,7 +123,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, | |||
| 138 | return 0; | 123 | return 0; |
| 139 | 124 | ||
| 140 | netlbl_export_failure: | 125 | netlbl_export_failure: |
| 141 | netlbl_secattr_catmap_free(*catmap); | 126 | netlbl_catmap_free(*catmap); |
| 142 | return -ENOMEM; | 127 | return -ENOMEM; |
| 143 | } | 128 | } |
| 144 | 129 | ||
| @@ -153,58 +138,44 @@ netlbl_export_failure: | |||
| 153 | * | 138 | * |
| 154 | */ | 139 | */ |
| 155 | int ebitmap_netlbl_import(struct ebitmap *ebmap, | 140 | int ebitmap_netlbl_import(struct ebitmap *ebmap, |
| 156 | struct netlbl_lsm_secattr_catmap *catmap) | 141 | struct netlbl_lsm_catmap *catmap) |
| 157 | { | 142 | { |
| 143 | int rc; | ||
| 158 | struct ebitmap_node *e_iter = NULL; | 144 | struct ebitmap_node *e_iter = NULL; |
| 159 | struct ebitmap_node *emap_prev = NULL; | 145 | struct ebitmap_node *e_prev = NULL; |
| 160 | struct netlbl_lsm_secattr_catmap *c_iter = catmap; | 146 | u32 offset = 0, idx; |
| 161 | u32 c_idx, c_pos, e_idx, e_sft; | 147 | unsigned long bitmap; |
| 162 | 148 | ||
| 163 | /* NetLabel's NETLBL_CATMAP_MAPTYPE is defined as an array of u64, | 149 | for (;;) { |
| 164 | * however, it is not always compatible with an array of unsigned long | 150 | rc = netlbl_catmap_getlong(catmap, &offset, &bitmap); |
| 165 | * in ebitmap_node. | 151 | if (rc < 0) |
| 166 | * In addition, you should pay attention the following implementation | 152 | goto netlbl_import_failure; |
| 167 | * assumes unsigned long has a width equal with or less than 64-bit. | 153 | if (offset == (u32)-1) |
| 168 | */ | 154 | return 0; |
| 169 | |||
| 170 | do { | ||
| 171 | for (c_idx = 0; c_idx < NETLBL_CATMAP_MAPCNT; c_idx++) { | ||
| 172 | unsigned int delta; | ||
| 173 | u64 map = c_iter->bitmap[c_idx]; | ||
| 174 | |||
| 175 | if (!map) | ||
| 176 | continue; | ||
| 177 | 155 | ||
| 178 | c_pos = c_iter->startbit | 156 | if (e_iter == NULL || |
| 179 | + c_idx * NETLBL_CATMAP_MAPSIZE; | 157 | offset >= e_iter->startbit + EBITMAP_SIZE) { |
| 180 | if (!e_iter | 158 | e_prev = e_iter; |
| 181 | || c_pos >= e_iter->startbit + EBITMAP_SIZE) { | 159 | e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); |
| 182 | e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC); | 160 | if (e_iter == NULL) |
| 183 | if (!e_iter) | 161 | goto netlbl_import_failure; |
| 184 | goto netlbl_import_failure; | 162 | e_iter->startbit = offset & ~(EBITMAP_SIZE - 1); |
| 185 | e_iter->startbit | 163 | if (e_prev == NULL) |
| 186 | = c_pos - (c_pos % EBITMAP_SIZE); | 164 | ebmap->node = e_iter; |
| 187 | if (emap_prev == NULL) | 165 | else |
| 188 | ebmap->node = e_iter; | 166 | e_prev->next = e_iter; |
| 189 | else | 167 | ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; |
| 190 | emap_prev->next = e_iter; | ||
| 191 | emap_prev = e_iter; | ||
| 192 | } | ||
| 193 | delta = c_pos - e_iter->startbit; | ||
| 194 | e_idx = delta / EBITMAP_UNIT_SIZE; | ||
| 195 | e_sft = delta % EBITMAP_UNIT_SIZE; | ||
| 196 | while (map) { | ||
| 197 | e_iter->maps[e_idx++] |= map & (-1UL); | ||
| 198 | map = EBITMAP_SHIFT_UNIT_SIZE(map); | ||
| 199 | } | ||
| 200 | } | 168 | } |
| 201 | c_iter = c_iter->next; | ||
| 202 | } while (c_iter); | ||
| 203 | if (e_iter != NULL) | ||
| 204 | ebmap->highbit = e_iter->startbit + EBITMAP_SIZE; | ||
| 205 | else | ||
| 206 | ebitmap_destroy(ebmap); | ||
| 207 | 169 | ||
| 170 | /* offset will always be aligned to an unsigned long */ | ||
| 171 | idx = EBITMAP_NODE_INDEX(e_iter, offset); | ||
| 172 | e_iter->maps[idx] = bitmap; | ||
| 173 | |||
| 174 | /* next */ | ||
| 175 | offset += EBITMAP_UNIT_SIZE; | ||
| 176 | } | ||
| 177 | |||
| 178 | /* NOTE: we should never reach this return */ | ||
| 208 | return 0; | 179 | return 0; |
| 209 | 180 | ||
| 210 | netlbl_import_failure: | 181 | netlbl_import_failure: |
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 712c8a7b8e8b..9637b8c71085 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h | |||
| @@ -132,17 +132,17 @@ int ebitmap_write(struct ebitmap *e, void *fp); | |||
| 132 | 132 | ||
| 133 | #ifdef CONFIG_NETLABEL | 133 | #ifdef CONFIG_NETLABEL |
| 134 | int ebitmap_netlbl_export(struct ebitmap *ebmap, | 134 | int ebitmap_netlbl_export(struct ebitmap *ebmap, |
| 135 | struct netlbl_lsm_secattr_catmap **catmap); | 135 | struct netlbl_lsm_catmap **catmap); |
| 136 | int ebitmap_netlbl_import(struct ebitmap *ebmap, | 136 | int ebitmap_netlbl_import(struct ebitmap *ebmap, |
| 137 | struct netlbl_lsm_secattr_catmap *catmap); | 137 | struct netlbl_lsm_catmap *catmap); |
| 138 | #else | 138 | #else |
| 139 | static inline int ebitmap_netlbl_export(struct ebitmap *ebmap, | 139 | static inline int ebitmap_netlbl_export(struct ebitmap *ebmap, |
| 140 | struct netlbl_lsm_secattr_catmap **catmap) | 140 | struct netlbl_lsm_catmap **catmap) |
| 141 | { | 141 | { |
| 142 | return -ENOMEM; | 142 | return -ENOMEM; |
| 143 | } | 143 | } |
| 144 | static inline int ebitmap_netlbl_import(struct ebitmap *ebmap, | 144 | static inline int ebitmap_netlbl_import(struct ebitmap *ebmap, |
| 145 | struct netlbl_lsm_secattr_catmap *catmap) | 145 | struct netlbl_lsm_catmap *catmap) |
| 146 | { | 146 | { |
| 147 | return -ENOMEM; | 147 | return -ENOMEM; |
| 148 | } | 148 | } |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 9c5cdc2caaef..bc2a586f095c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -1080,6 +1080,26 @@ out: | |||
| 1080 | * binary representation file. | 1080 | * binary representation file. |
| 1081 | */ | 1081 | */ |
| 1082 | 1082 | ||
| 1083 | static int str_read(char **strp, gfp_t flags, void *fp, u32 len) | ||
| 1084 | { | ||
| 1085 | int rc; | ||
| 1086 | char *str; | ||
| 1087 | |||
| 1088 | str = kmalloc(len + 1, flags); | ||
| 1089 | if (!str) | ||
| 1090 | return -ENOMEM; | ||
| 1091 | |||
| 1092 | /* it's expected the caller should free the str */ | ||
| 1093 | *strp = str; | ||
| 1094 | |||
| 1095 | rc = next_entry(str, fp, len); | ||
| 1096 | if (rc) | ||
| 1097 | return rc; | ||
| 1098 | |||
| 1099 | str[len] = '\0'; | ||
| 1100 | return 0; | ||
| 1101 | } | ||
| 1102 | |||
| 1083 | static int perm_read(struct policydb *p, struct hashtab *h, void *fp) | 1103 | static int perm_read(struct policydb *p, struct hashtab *h, void *fp) |
| 1084 | { | 1104 | { |
| 1085 | char *key = NULL; | 1105 | char *key = NULL; |
| @@ -1100,15 +1120,9 @@ static int perm_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1100 | len = le32_to_cpu(buf[0]); | 1120 | len = le32_to_cpu(buf[0]); |
| 1101 | perdatum->value = le32_to_cpu(buf[1]); | 1121 | perdatum->value = le32_to_cpu(buf[1]); |
| 1102 | 1122 | ||
| 1103 | rc = -ENOMEM; | 1123 | rc = str_read(&key, GFP_KERNEL, fp, len); |
| 1104 | key = kmalloc(len + 1, GFP_KERNEL); | ||
| 1105 | if (!key) | ||
| 1106 | goto bad; | ||
| 1107 | |||
| 1108 | rc = next_entry(key, fp, len); | ||
| 1109 | if (rc) | 1124 | if (rc) |
| 1110 | goto bad; | 1125 | goto bad; |
| 1111 | key[len] = '\0'; | ||
| 1112 | 1126 | ||
| 1113 | rc = hashtab_insert(h, key, perdatum); | 1127 | rc = hashtab_insert(h, key, perdatum); |
| 1114 | if (rc) | 1128 | if (rc) |
| @@ -1146,15 +1160,9 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1146 | comdatum->permissions.nprim = le32_to_cpu(buf[2]); | 1160 | comdatum->permissions.nprim = le32_to_cpu(buf[2]); |
| 1147 | nel = le32_to_cpu(buf[3]); | 1161 | nel = le32_to_cpu(buf[3]); |
| 1148 | 1162 | ||
| 1149 | rc = -ENOMEM; | 1163 | rc = str_read(&key, GFP_KERNEL, fp, len); |
| 1150 | key = kmalloc(len + 1, GFP_KERNEL); | ||
| 1151 | if (!key) | ||
| 1152 | goto bad; | ||
| 1153 | |||
| 1154 | rc = next_entry(key, fp, len); | ||
| 1155 | if (rc) | 1164 | if (rc) |
| 1156 | goto bad; | 1165 | goto bad; |
| 1157 | key[len] = '\0'; | ||
| 1158 | 1166 | ||
| 1159 | for (i = 0; i < nel; i++) { | 1167 | for (i = 0; i < nel; i++) { |
| 1160 | rc = perm_read(p, comdatum->permissions.table, fp); | 1168 | rc = perm_read(p, comdatum->permissions.table, fp); |
| @@ -1321,25 +1329,14 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1321 | 1329 | ||
| 1322 | ncons = le32_to_cpu(buf[5]); | 1330 | ncons = le32_to_cpu(buf[5]); |
| 1323 | 1331 | ||
| 1324 | rc = -ENOMEM; | 1332 | rc = str_read(&key, GFP_KERNEL, fp, len); |
| 1325 | key = kmalloc(len + 1, GFP_KERNEL); | ||
| 1326 | if (!key) | ||
| 1327 | goto bad; | ||
| 1328 | |||
| 1329 | rc = next_entry(key, fp, len); | ||
| 1330 | if (rc) | 1333 | if (rc) |
| 1331 | goto bad; | 1334 | goto bad; |
| 1332 | key[len] = '\0'; | ||
| 1333 | 1335 | ||
| 1334 | if (len2) { | 1336 | if (len2) { |
| 1335 | rc = -ENOMEM; | 1337 | rc = str_read(&cladatum->comkey, GFP_KERNEL, fp, len2); |
| 1336 | cladatum->comkey = kmalloc(len2 + 1, GFP_KERNEL); | ||
| 1337 | if (!cladatum->comkey) | ||
| 1338 | goto bad; | ||
| 1339 | rc = next_entry(cladatum->comkey, fp, len2); | ||
| 1340 | if (rc) | 1338 | if (rc) |
| 1341 | goto bad; | 1339 | goto bad; |
| 1342 | cladatum->comkey[len2] = '\0'; | ||
| 1343 | 1340 | ||
| 1344 | rc = -EINVAL; | 1341 | rc = -EINVAL; |
| 1345 | cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); | 1342 | cladatum->comdatum = hashtab_search(p->p_commons.table, cladatum->comkey); |
| @@ -1422,15 +1419,9 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1422 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | 1419 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
| 1423 | role->bounds = le32_to_cpu(buf[2]); | 1420 | role->bounds = le32_to_cpu(buf[2]); |
| 1424 | 1421 | ||
| 1425 | rc = -ENOMEM; | 1422 | rc = str_read(&key, GFP_KERNEL, fp, len); |
| 1426 | key = kmalloc(len + 1, GFP_KERNEL); | ||
| 1427 | if (!key) | ||
| 1428 | goto bad; | ||
| 1429 | |||
| 1430 | rc = next_entry(key, fp, len); | ||
| 1431 | if (rc) | 1423 | if (rc) |
| 1432 | goto bad; | 1424 | goto bad; |
| 1433 | key[len] = '\0'; | ||
| 1434 | 1425 | ||
| 1435 | rc = ebitmap_read(&role->dominates, fp); | 1426 | rc = ebitmap_read(&role->dominates, fp); |
| 1436 | if (rc) | 1427 | if (rc) |
| @@ -1495,14 +1486,9 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1495 | typdatum->primary = le32_to_cpu(buf[2]); | 1486 | typdatum->primary = le32_to_cpu(buf[2]); |
| 1496 | } | 1487 | } |
| 1497 | 1488 | ||
| 1498 | rc = -ENOMEM; | 1489 | rc = str_read(&key, GFP_KERNEL, fp, len); |
| 1499 | key = kmalloc(len + 1, GFP_KERNEL); | ||
| 1500 | if (!key) | ||
| 1501 | goto bad; | ||
| 1502 | rc = next_entry(key, fp, len); | ||
| 1503 | if (rc) | 1490 | if (rc) |
| 1504 | goto bad; | 1491 | goto bad; |
| 1505 | key[len] = '\0'; | ||
| 1506 | 1492 | ||
| 1507 | rc = hashtab_insert(h, key, typdatum); | 1493 | rc = hashtab_insert(h, key, typdatum); |
| 1508 | if (rc) | 1494 | if (rc) |
| @@ -1565,14 +1551,9 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1565 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | 1551 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
| 1566 | usrdatum->bounds = le32_to_cpu(buf[2]); | 1552 | usrdatum->bounds = le32_to_cpu(buf[2]); |
| 1567 | 1553 | ||
| 1568 | rc = -ENOMEM; | 1554 | rc = str_read(&key, GFP_KERNEL, fp, len); |
| 1569 | key = kmalloc(len + 1, GFP_KERNEL); | ||
| 1570 | if (!key) | ||
| 1571 | goto bad; | ||
| 1572 | rc = next_entry(key, fp, len); | ||
| 1573 | if (rc) | 1555 | if (rc) |
| 1574 | goto bad; | 1556 | goto bad; |
| 1575 | key[len] = '\0'; | ||
| 1576 | 1557 | ||
| 1577 | rc = ebitmap_read(&usrdatum->roles, fp); | 1558 | rc = ebitmap_read(&usrdatum->roles, fp); |
| 1578 | if (rc) | 1559 | if (rc) |
| @@ -1616,14 +1597,9 @@ static int sens_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1616 | len = le32_to_cpu(buf[0]); | 1597 | len = le32_to_cpu(buf[0]); |
| 1617 | levdatum->isalias = le32_to_cpu(buf[1]); | 1598 | levdatum->isalias = le32_to_cpu(buf[1]); |
| 1618 | 1599 | ||
| 1619 | rc = -ENOMEM; | 1600 | rc = str_read(&key, GFP_ATOMIC, fp, len); |
| 1620 | key = kmalloc(len + 1, GFP_ATOMIC); | ||
| 1621 | if (!key) | ||
| 1622 | goto bad; | ||
| 1623 | rc = next_entry(key, fp, len); | ||
| 1624 | if (rc) | 1601 | if (rc) |
| 1625 | goto bad; | 1602 | goto bad; |
| 1626 | key[len] = '\0'; | ||
| 1627 | 1603 | ||
| 1628 | rc = -ENOMEM; | 1604 | rc = -ENOMEM; |
| 1629 | levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); | 1605 | levdatum->level = kmalloc(sizeof(struct mls_level), GFP_ATOMIC); |
| @@ -1664,14 +1640,9 @@ static int cat_read(struct policydb *p, struct hashtab *h, void *fp) | |||
| 1664 | catdatum->value = le32_to_cpu(buf[1]); | 1640 | catdatum->value = le32_to_cpu(buf[1]); |
| 1665 | catdatum->isalias = le32_to_cpu(buf[2]); | 1641 | catdatum->isalias = le32_to_cpu(buf[2]); |
| 1666 | 1642 | ||
| 1667 | rc = -ENOMEM; | 1643 | rc = str_read(&key, GFP_ATOMIC, fp, len); |
| 1668 | key = kmalloc(len + 1, GFP_ATOMIC); | ||
| 1669 | if (!key) | ||
| 1670 | goto bad; | ||
| 1671 | rc = next_entry(key, fp, len); | ||
| 1672 | if (rc) | 1644 | if (rc) |
| 1673 | goto bad; | 1645 | goto bad; |
| 1674 | key[len] = '\0'; | ||
| 1675 | 1646 | ||
| 1676 | rc = hashtab_insert(h, key, catdatum); | 1647 | rc = hashtab_insert(h, key, catdatum); |
| 1677 | if (rc) | 1648 | if (rc) |
| @@ -1968,18 +1939,12 @@ static int filename_trans_read(struct policydb *p, void *fp) | |||
| 1968 | goto out; | 1939 | goto out; |
| 1969 | len = le32_to_cpu(buf[0]); | 1940 | len = le32_to_cpu(buf[0]); |
| 1970 | 1941 | ||
| 1971 | rc = -ENOMEM; | ||
| 1972 | name = kmalloc(len + 1, GFP_KERNEL); | ||
| 1973 | if (!name) | ||
| 1974 | goto out; | ||
| 1975 | |||
| 1976 | ft->name = name; | ||
| 1977 | |||
| 1978 | /* path component string */ | 1942 | /* path component string */ |
| 1979 | rc = next_entry(name, fp, len); | 1943 | rc = str_read(&name, GFP_KERNEL, fp, len); |
| 1980 | if (rc) | 1944 | if (rc) |
| 1981 | goto out; | 1945 | goto out; |
| 1982 | name[len] = 0; | 1946 | |
| 1947 | ft->name = name; | ||
| 1983 | 1948 | ||
| 1984 | rc = next_entry(buf, fp, sizeof(u32) * 4); | 1949 | rc = next_entry(buf, fp, sizeof(u32) * 4); |
| 1985 | if (rc) | 1950 | if (rc) |
| @@ -2045,17 +2010,10 @@ static int genfs_read(struct policydb *p, void *fp) | |||
| 2045 | if (!newgenfs) | 2010 | if (!newgenfs) |
| 2046 | goto out; | 2011 | goto out; |
| 2047 | 2012 | ||
| 2048 | rc = -ENOMEM; | 2013 | rc = str_read(&newgenfs->fstype, GFP_KERNEL, fp, len); |
| 2049 | newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL); | ||
| 2050 | if (!newgenfs->fstype) | ||
| 2051 | goto out; | ||
| 2052 | |||
| 2053 | rc = next_entry(newgenfs->fstype, fp, len); | ||
| 2054 | if (rc) | 2014 | if (rc) |
| 2055 | goto out; | 2015 | goto out; |
| 2056 | 2016 | ||
| 2057 | newgenfs->fstype[len] = 0; | ||
| 2058 | |||
| 2059 | for (genfs_p = NULL, genfs = p->genfs; genfs; | 2017 | for (genfs_p = NULL, genfs = p->genfs; genfs; |
| 2060 | genfs_p = genfs, genfs = genfs->next) { | 2018 | genfs_p = genfs, genfs = genfs->next) { |
| 2061 | rc = -EINVAL; | 2019 | rc = -EINVAL; |
| @@ -2091,15 +2049,9 @@ static int genfs_read(struct policydb *p, void *fp) | |||
| 2091 | if (!newc) | 2049 | if (!newc) |
| 2092 | goto out; | 2050 | goto out; |
| 2093 | 2051 | ||
| 2094 | rc = -ENOMEM; | 2052 | rc = str_read(&newc->u.name, GFP_KERNEL, fp, len); |
| 2095 | newc->u.name = kmalloc(len + 1, GFP_KERNEL); | ||
| 2096 | if (!newc->u.name) | ||
| 2097 | goto out; | ||
| 2098 | |||
| 2099 | rc = next_entry(newc->u.name, fp, len); | ||
| 2100 | if (rc) | 2053 | if (rc) |
| 2101 | goto out; | 2054 | goto out; |
| 2102 | newc->u.name[len] = 0; | ||
| 2103 | 2055 | ||
| 2104 | rc = next_entry(buf, fp, sizeof(u32)); | 2056 | rc = next_entry(buf, fp, sizeof(u32)); |
| 2105 | if (rc) | 2057 | if (rc) |
| @@ -2189,16 +2141,10 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
| 2189 | goto out; | 2141 | goto out; |
| 2190 | len = le32_to_cpu(buf[0]); | 2142 | len = le32_to_cpu(buf[0]); |
| 2191 | 2143 | ||
| 2192 | rc = -ENOMEM; | 2144 | rc = str_read(&c->u.name, GFP_KERNEL, fp, len); |
| 2193 | c->u.name = kmalloc(len + 1, GFP_KERNEL); | ||
| 2194 | if (!c->u.name) | ||
| 2195 | goto out; | ||
| 2196 | |||
| 2197 | rc = next_entry(c->u.name, fp, len); | ||
| 2198 | if (rc) | 2145 | if (rc) |
| 2199 | goto out; | 2146 | goto out; |
| 2200 | 2147 | ||
| 2201 | c->u.name[len] = 0; | ||
| 2202 | rc = context_read_and_validate(&c->context[0], p, fp); | 2148 | rc = context_read_and_validate(&c->context[0], p, fp); |
| 2203 | if (rc) | 2149 | if (rc) |
| 2204 | goto out; | 2150 | goto out; |
| @@ -2240,16 +2186,11 @@ static int ocontext_read(struct policydb *p, struct policydb_compat_info *info, | |||
| 2240 | if (c->v.behavior > SECURITY_FS_USE_MAX) | 2186 | if (c->v.behavior > SECURITY_FS_USE_MAX) |
| 2241 | goto out; | 2187 | goto out; |
| 2242 | 2188 | ||
| 2243 | rc = -ENOMEM; | ||
| 2244 | len = le32_to_cpu(buf[1]); | 2189 | len = le32_to_cpu(buf[1]); |
| 2245 | c->u.name = kmalloc(len + 1, GFP_KERNEL); | 2190 | rc = str_read(&c->u.name, GFP_KERNEL, fp, len); |
| 2246 | if (!c->u.name) | ||
| 2247 | goto out; | ||
| 2248 | |||
| 2249 | rc = next_entry(c->u.name, fp, len); | ||
| 2250 | if (rc) | 2191 | if (rc) |
| 2251 | goto out; | 2192 | goto out; |
| 2252 | c->u.name[len] = 0; | 2193 | |
| 2253 | rc = context_read_and_validate(&c->context[0], p, fp); | 2194 | rc = context_read_and_validate(&c->context[0], p, fp); |
| 2254 | if (rc) | 2195 | if (rc) |
| 2255 | goto out; | 2196 | goto out; |
| @@ -2608,7 +2549,7 @@ static int mls_write_range_helper(struct mls_range *r, void *fp) | |||
| 2608 | if (!eq) | 2549 | if (!eq) |
| 2609 | buf[2] = cpu_to_le32(r->level[1].sens); | 2550 | buf[2] = cpu_to_le32(r->level[1].sens); |
| 2610 | 2551 | ||
| 2611 | BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); | 2552 | BUG_ON(items > ARRAY_SIZE(buf)); |
| 2612 | 2553 | ||
| 2613 | rc = put_entry(buf, sizeof(u32), items, fp); | 2554 | rc = put_entry(buf, sizeof(u32), items, fp); |
| 2614 | if (rc) | 2555 | if (rc) |
| @@ -2990,7 +2931,7 @@ static int role_write(void *vkey, void *datum, void *ptr) | |||
| 2990 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | 2931 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
| 2991 | buf[items++] = cpu_to_le32(role->bounds); | 2932 | buf[items++] = cpu_to_le32(role->bounds); |
| 2992 | 2933 | ||
| 2993 | BUG_ON(items > (sizeof(buf)/sizeof(buf[0]))); | 2934 | BUG_ON(items > ARRAY_SIZE(buf)); |
| 2994 | 2935 | ||
| 2995 | rc = put_entry(buf, sizeof(u32), items, fp); | 2936 | rc = put_entry(buf, sizeof(u32), items, fp); |
| 2996 | if (rc) | 2937 | if (rc) |
| @@ -3040,7 +2981,7 @@ static int type_write(void *vkey, void *datum, void *ptr) | |||
| 3040 | } else { | 2981 | } else { |
| 3041 | buf[items++] = cpu_to_le32(typdatum->primary); | 2982 | buf[items++] = cpu_to_le32(typdatum->primary); |
| 3042 | } | 2983 | } |
| 3043 | BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); | 2984 | BUG_ON(items > ARRAY_SIZE(buf)); |
| 3044 | rc = put_entry(buf, sizeof(u32), items, fp); | 2985 | rc = put_entry(buf, sizeof(u32), items, fp); |
| 3045 | if (rc) | 2986 | if (rc) |
| 3046 | return rc; | 2987 | return rc; |
| @@ -3069,7 +3010,7 @@ static int user_write(void *vkey, void *datum, void *ptr) | |||
| 3069 | buf[items++] = cpu_to_le32(usrdatum->value); | 3010 | buf[items++] = cpu_to_le32(usrdatum->value); |
| 3070 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) | 3011 | if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) |
| 3071 | buf[items++] = cpu_to_le32(usrdatum->bounds); | 3012 | buf[items++] = cpu_to_le32(usrdatum->bounds); |
| 3072 | BUG_ON(items > (sizeof(buf) / sizeof(buf[0]))); | 3013 | BUG_ON(items > ARRAY_SIZE(buf)); |
| 3073 | rc = put_entry(buf, sizeof(u32), items, fp); | 3014 | rc = put_entry(buf, sizeof(u32), items, fp); |
| 3074 | if (rc) | 3015 | if (rc) |
| 3075 | return rc; | 3016 | return rc; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 4bca49414a40..2aa9d172dc7e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -2277,7 +2277,7 @@ out: | |||
| 2277 | } | 2277 | } |
| 2278 | 2278 | ||
| 2279 | /** | 2279 | /** |
| 2280 | * security_genfs_sid - Obtain a SID for a file in a filesystem | 2280 | * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem |
| 2281 | * @fstype: filesystem type | 2281 | * @fstype: filesystem type |
| 2282 | * @path: path from root of mount | 2282 | * @path: path from root of mount |
| 2283 | * @sclass: file security class | 2283 | * @sclass: file security class |
| @@ -2286,11 +2286,13 @@ out: | |||
| 2286 | * Obtain a SID to use for a file in a filesystem that | 2286 | * Obtain a SID to use for a file in a filesystem that |
| 2287 | * cannot support xattr or use a fixed labeling behavior like | 2287 | * cannot support xattr or use a fixed labeling behavior like |
| 2288 | * transition SIDs or task SIDs. | 2288 | * transition SIDs or task SIDs. |
| 2289 | * | ||
| 2290 | * The caller must acquire the policy_rwlock before calling this function. | ||
| 2289 | */ | 2291 | */ |
| 2290 | int security_genfs_sid(const char *fstype, | 2292 | static inline int __security_genfs_sid(const char *fstype, |
| 2291 | char *path, | 2293 | char *path, |
| 2292 | u16 orig_sclass, | 2294 | u16 orig_sclass, |
| 2293 | u32 *sid) | 2295 | u32 *sid) |
| 2294 | { | 2296 | { |
| 2295 | int len; | 2297 | int len; |
| 2296 | u16 sclass; | 2298 | u16 sclass; |
| @@ -2301,8 +2303,6 @@ int security_genfs_sid(const char *fstype, | |||
| 2301 | while (path[0] == '/' && path[1] == '/') | 2303 | while (path[0] == '/' && path[1] == '/') |
| 2302 | path++; | 2304 | path++; |
| 2303 | 2305 | ||
| 2304 | read_lock(&policy_rwlock); | ||
| 2305 | |||
| 2306 | sclass = unmap_class(orig_sclass); | 2306 | sclass = unmap_class(orig_sclass); |
| 2307 | *sid = SECINITSID_UNLABELED; | 2307 | *sid = SECINITSID_UNLABELED; |
| 2308 | 2308 | ||
| @@ -2336,11 +2336,33 @@ int security_genfs_sid(const char *fstype, | |||
| 2336 | *sid = c->sid[0]; | 2336 | *sid = c->sid[0]; |
| 2337 | rc = 0; | 2337 | rc = 0; |
| 2338 | out: | 2338 | out: |
| 2339 | read_unlock(&policy_rwlock); | ||
| 2340 | return rc; | 2339 | return rc; |
| 2341 | } | 2340 | } |
| 2342 | 2341 | ||
| 2343 | /** | 2342 | /** |
| 2343 | * security_genfs_sid - Obtain a SID for a file in a filesystem | ||
| 2344 | * @fstype: filesystem type | ||
| 2345 | * @path: path from root of mount | ||
| 2346 | * @sclass: file security class | ||
| 2347 | * @sid: SID for path | ||
| 2348 | * | ||
| 2349 | * Acquire policy_rwlock before calling __security_genfs_sid() and release | ||
| 2350 | * it afterward. | ||
| 2351 | */ | ||
| 2352 | int security_genfs_sid(const char *fstype, | ||
| 2353 | char *path, | ||
| 2354 | u16 orig_sclass, | ||
| 2355 | u32 *sid) | ||
| 2356 | { | ||
| 2357 | int retval; | ||
| 2358 | |||
| 2359 | read_lock(&policy_rwlock); | ||
| 2360 | retval = __security_genfs_sid(fstype, path, orig_sclass, sid); | ||
| 2361 | read_unlock(&policy_rwlock); | ||
| 2362 | return retval; | ||
| 2363 | } | ||
| 2364 | |||
| 2365 | /** | ||
| 2344 | * security_fs_use - Determine how to handle labeling for a filesystem. | 2366 | * security_fs_use - Determine how to handle labeling for a filesystem. |
| 2345 | * @sb: superblock in question | 2367 | * @sb: superblock in question |
| 2346 | */ | 2368 | */ |
| @@ -2370,7 +2392,8 @@ int security_fs_use(struct super_block *sb) | |||
| 2370 | } | 2392 | } |
| 2371 | sbsec->sid = c->sid[0]; | 2393 | sbsec->sid = c->sid[0]; |
| 2372 | } else { | 2394 | } else { |
| 2373 | rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, &sbsec->sid); | 2395 | rc = __security_genfs_sid(fstype, "/", SECCLASS_DIR, |
| 2396 | &sbsec->sid); | ||
| 2374 | if (rc) { | 2397 | if (rc) { |
| 2375 | sbsec->behavior = SECURITY_FS_USE_NONE; | 2398 | sbsec->behavior = SECURITY_FS_USE_NONE; |
| 2376 | rc = 0; | 2399 | rc = 0; |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index c062e9467b62..f97d0842e621 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
| @@ -457,19 +457,16 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, | |||
| 457 | 457 | ||
| 458 | sap->flags |= NETLBL_SECATTR_MLS_CAT; | 458 | sap->flags |= NETLBL_SECATTR_MLS_CAT; |
| 459 | sap->attr.mls.lvl = level; | 459 | sap->attr.mls.lvl = level; |
| 460 | sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | 460 | sap->attr.mls.cat = NULL; |
| 461 | if (!sap->attr.mls.cat) | ||
| 462 | return -ENOMEM; | ||
| 463 | sap->attr.mls.cat->startbit = 0; | ||
| 464 | 461 | ||
| 465 | for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) | 462 | for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) |
| 466 | for (m = 0x80; m != 0; m >>= 1, cat++) { | 463 | for (m = 0x80; m != 0; m >>= 1, cat++) { |
| 467 | if ((m & *cp) == 0) | 464 | if ((m & *cp) == 0) |
| 468 | continue; | 465 | continue; |
| 469 | rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, | 466 | rc = netlbl_catmap_setbit(&sap->attr.mls.cat, |
| 470 | cat, GFP_ATOMIC); | 467 | cat, GFP_ATOMIC); |
| 471 | if (rc < 0) { | 468 | if (rc < 0) { |
| 472 | netlbl_secattr_catmap_free(sap->attr.mls.cat); | 469 | netlbl_catmap_free(sap->attr.mls.cat); |
| 473 | return rc; | 470 | return rc; |
| 474 | } | 471 | } |
| 475 | } | 472 | } |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index f2c30801ce41..e6ab307ce86e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -3209,9 +3209,9 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, | |||
| 3209 | break; | 3209 | break; |
| 3210 | } | 3210 | } |
| 3211 | for (acat = -1, kcat = -1; acat == kcat; ) { | 3211 | for (acat = -1, kcat = -1; acat == kcat; ) { |
| 3212 | acat = netlbl_secattr_catmap_walk( | 3212 | acat = netlbl_catmap_walk(sap->attr.mls.cat, |
| 3213 | sap->attr.mls.cat, acat + 1); | 3213 | acat + 1); |
| 3214 | kcat = netlbl_secattr_catmap_walk( | 3214 | kcat = netlbl_catmap_walk( |
| 3215 | skp->smk_netlabel.attr.mls.cat, | 3215 | skp->smk_netlabel.attr.mls.cat, |
| 3216 | kcat + 1); | 3216 | kcat + 1); |
| 3217 | if (acat < 0 || kcat < 0) | 3217 | if (acat < 0 || kcat < 0) |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 32b248820840..3c720ff10591 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
| @@ -787,7 +787,7 @@ static int cipso_seq_show(struct seq_file *s, void *v) | |||
| 787 | struct list_head *list = v; | 787 | struct list_head *list = v; |
| 788 | struct smack_known *skp = | 788 | struct smack_known *skp = |
| 789 | list_entry(list, struct smack_known, list); | 789 | list_entry(list, struct smack_known, list); |
| 790 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; | 790 | struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; |
| 791 | char sep = '/'; | 791 | char sep = '/'; |
| 792 | int i; | 792 | int i; |
| 793 | 793 | ||
| @@ -804,8 +804,8 @@ static int cipso_seq_show(struct seq_file *s, void *v) | |||
| 804 | 804 | ||
| 805 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); | 805 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); |
| 806 | 806 | ||
| 807 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; | 807 | for (i = netlbl_catmap_walk(cmp, 0); i >= 0; |
| 808 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { | 808 | i = netlbl_catmap_walk(cmp, i + 1)) { |
| 809 | seq_printf(s, "%c%d", sep, i); | 809 | seq_printf(s, "%c%d", sep, i); |
| 810 | sep = ','; | 810 | sep = ','; |
| 811 | } | 811 | } |
| @@ -926,7 +926,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf, | |||
| 926 | 926 | ||
| 927 | rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); | 927 | rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); |
| 928 | if (rc >= 0) { | 928 | if (rc >= 0) { |
| 929 | netlbl_secattr_catmap_free(skp->smk_netlabel.attr.mls.cat); | 929 | netlbl_catmap_free(skp->smk_netlabel.attr.mls.cat); |
| 930 | skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat; | 930 | skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat; |
| 931 | skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; | 931 | skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; |
| 932 | rc = count; | 932 | rc = count; |
| @@ -976,14 +976,14 @@ static int cipso2_seq_show(struct seq_file *s, void *v) | |||
| 976 | struct list_head *list = v; | 976 | struct list_head *list = v; |
| 977 | struct smack_known *skp = | 977 | struct smack_known *skp = |
| 978 | list_entry(list, struct smack_known, list); | 978 | list_entry(list, struct smack_known, list); |
| 979 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; | 979 | struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat; |
| 980 | char sep = '/'; | 980 | char sep = '/'; |
| 981 | int i; | 981 | int i; |
| 982 | 982 | ||
| 983 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); | 983 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); |
| 984 | 984 | ||
| 985 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; | 985 | for (i = netlbl_catmap_walk(cmp, 0); i >= 0; |
| 986 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { | 986 | i = netlbl_catmap_walk(cmp, i + 1)) { |
| 987 | seq_printf(s, "%c%d", sep, i); | 987 | seq_printf(s, "%c%d", sep, i); |
| 988 | sep = ','; | 988 | sep = ','; |
| 989 | } | 989 | } |
