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 | } |