diff options
| author | James Morris <james.l.morris@oracle.com> | 2014-07-16 12:10:27 -0400 |
|---|---|---|
| committer | James Morris <james.l.morris@oracle.com> | 2014-07-16 12:10:27 -0400 |
| commit | bd89bb78f35fd175db7a9cfc504d789b6ca0f7b0 (patch) | |
| tree | dee9f8b31f3d6d2fb141541da88e1cc1329b017e /security | |
| parent | f01387d2693813eb5271a3448e6a082322c7d75d (diff) | |
| parent | 1795cd9b3a91d4b5473c97f491d63892442212ab (diff) | |
Sync with the changes pushed by Serge in the last merge window.
Diffstat (limited to 'security')
| -rw-r--r-- | security/device_cgroup.c | 33 | ||||
| -rw-r--r-- | security/integrity/evm/Kconfig | 42 | ||||
| -rw-r--r-- | security/integrity/evm/evm.h | 5 | ||||
| -rw-r--r-- | security/integrity/evm/evm_crypto.c | 2 | ||||
| -rw-r--r-- | security/integrity/evm/evm_main.c | 29 | ||||
| -rw-r--r-- | security/integrity/ima/ima_api.c | 10 | ||||
| -rw-r--r-- | security/integrity/ima/ima_appraise.c | 10 | ||||
| -rw-r--r-- | security/integrity/ima/ima_crypto.c | 32 | ||||
| -rw-r--r-- | security/integrity/ima/ima_main.c | 27 | ||||
| -rw-r--r-- | security/integrity/ima/ima_policy.c | 6 | ||||
| -rw-r--r-- | security/integrity/integrity.h | 1 | ||||
| -rw-r--r-- | security/selinux/include/classmap.h | 2 |
12 files changed, 147 insertions, 52 deletions
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 9134dbf70d3e..d9d69e6930ed 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
| @@ -182,7 +182,7 @@ static inline bool is_devcg_online(const struct dev_cgroup *devcg) | |||
| 182 | static int devcgroup_online(struct cgroup_subsys_state *css) | 182 | static int devcgroup_online(struct cgroup_subsys_state *css) |
| 183 | { | 183 | { |
| 184 | struct dev_cgroup *dev_cgroup = css_to_devcgroup(css); | 184 | struct dev_cgroup *dev_cgroup = css_to_devcgroup(css); |
| 185 | struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css_parent(css)); | 185 | struct dev_cgroup *parent_dev_cgroup = css_to_devcgroup(css->parent); |
| 186 | int ret = 0; | 186 | int ret = 0; |
| 187 | 187 | ||
| 188 | mutex_lock(&devcgroup_mutex); | 188 | mutex_lock(&devcgroup_mutex); |
| @@ -455,7 +455,7 @@ static bool verify_new_ex(struct dev_cgroup *dev_cgroup, | |||
| 455 | static int parent_has_perm(struct dev_cgroup *childcg, | 455 | static int parent_has_perm(struct dev_cgroup *childcg, |
| 456 | struct dev_exception_item *ex) | 456 | struct dev_exception_item *ex) |
| 457 | { | 457 | { |
| 458 | struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css)); | 458 | struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent); |
| 459 | 459 | ||
| 460 | if (!parent) | 460 | if (!parent) |
| 461 | return 1; | 461 | return 1; |
| @@ -476,7 +476,7 @@ static int parent_has_perm(struct dev_cgroup *childcg, | |||
| 476 | static bool parent_allows_removal(struct dev_cgroup *childcg, | 476 | static bool parent_allows_removal(struct dev_cgroup *childcg, |
| 477 | struct dev_exception_item *ex) | 477 | struct dev_exception_item *ex) |
| 478 | { | 478 | { |
| 479 | struct dev_cgroup *parent = css_to_devcgroup(css_parent(&childcg->css)); | 479 | struct dev_cgroup *parent = css_to_devcgroup(childcg->css.parent); |
| 480 | 480 | ||
| 481 | if (!parent) | 481 | if (!parent) |
| 482 | return true; | 482 | return true; |
| @@ -587,13 +587,6 @@ static int propagate_exception(struct dev_cgroup *devcg_root, | |||
| 587 | return rc; | 587 | return rc; |
| 588 | } | 588 | } |
| 589 | 589 | ||
| 590 | static inline bool has_children(struct dev_cgroup *devcgroup) | ||
| 591 | { | ||
| 592 | struct cgroup *cgrp = devcgroup->css.cgroup; | ||
| 593 | |||
| 594 | return !list_empty(&cgrp->children); | ||
| 595 | } | ||
| 596 | |||
| 597 | /* | 590 | /* |
| 598 | * Modify the exception list using allow/deny rules. | 591 | * Modify the exception list using allow/deny rules. |
| 599 | * CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD | 592 | * CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD |
| @@ -614,7 +607,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
| 614 | char temp[12]; /* 11 + 1 characters needed for a u32 */ | 607 | char temp[12]; /* 11 + 1 characters needed for a u32 */ |
| 615 | int count, rc = 0; | 608 | int count, rc = 0; |
| 616 | struct dev_exception_item ex; | 609 | struct dev_exception_item ex; |
| 617 | struct dev_cgroup *parent = css_to_devcgroup(css_parent(&devcgroup->css)); | 610 | struct dev_cgroup *parent = css_to_devcgroup(devcgroup->css.parent); |
| 618 | 611 | ||
| 619 | if (!capable(CAP_SYS_ADMIN)) | 612 | if (!capable(CAP_SYS_ADMIN)) |
| 620 | return -EPERM; | 613 | return -EPERM; |
| @@ -626,7 +619,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
| 626 | case 'a': | 619 | case 'a': |
| 627 | switch (filetype) { | 620 | switch (filetype) { |
| 628 | case DEVCG_ALLOW: | 621 | case DEVCG_ALLOW: |
| 629 | if (has_children(devcgroup)) | 622 | if (css_has_online_children(&devcgroup->css)) |
| 630 | return -EINVAL; | 623 | return -EINVAL; |
| 631 | 624 | ||
| 632 | if (!may_allow_all(parent)) | 625 | if (!may_allow_all(parent)) |
| @@ -642,7 +635,7 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
| 642 | return rc; | 635 | return rc; |
| 643 | break; | 636 | break; |
| 644 | case DEVCG_DENY: | 637 | case DEVCG_DENY: |
| 645 | if (has_children(devcgroup)) | 638 | if (css_has_online_children(&devcgroup->css)) |
| 646 | return -EINVAL; | 639 | return -EINVAL; |
| 647 | 640 | ||
| 648 | dev_exception_clean(devcgroup); | 641 | dev_exception_clean(devcgroup); |
| @@ -767,27 +760,27 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
| 767 | return rc; | 760 | return rc; |
| 768 | } | 761 | } |
| 769 | 762 | ||
| 770 | static int devcgroup_access_write(struct cgroup_subsys_state *css, | 763 | static ssize_t devcgroup_access_write(struct kernfs_open_file *of, |
| 771 | struct cftype *cft, char *buffer) | 764 | char *buf, size_t nbytes, loff_t off) |
| 772 | { | 765 | { |
| 773 | int retval; | 766 | int retval; |
| 774 | 767 | ||
| 775 | mutex_lock(&devcgroup_mutex); | 768 | mutex_lock(&devcgroup_mutex); |
| 776 | retval = devcgroup_update_access(css_to_devcgroup(css), | 769 | retval = devcgroup_update_access(css_to_devcgroup(of_css(of)), |
| 777 | cft->private, buffer); | 770 | of_cft(of)->private, strstrip(buf)); |
| 778 | mutex_unlock(&devcgroup_mutex); | 771 | mutex_unlock(&devcgroup_mutex); |
| 779 | return retval; | 772 | return retval ?: nbytes; |
| 780 | } | 773 | } |
| 781 | 774 | ||
| 782 | static struct cftype dev_cgroup_files[] = { | 775 | static struct cftype dev_cgroup_files[] = { |
| 783 | { | 776 | { |
| 784 | .name = "allow", | 777 | .name = "allow", |
| 785 | .write_string = devcgroup_access_write, | 778 | .write = devcgroup_access_write, |
| 786 | .private = DEVCG_ALLOW, | 779 | .private = DEVCG_ALLOW, |
| 787 | }, | 780 | }, |
| 788 | { | 781 | { |
| 789 | .name = "deny", | 782 | .name = "deny", |
| 790 | .write_string = devcgroup_access_write, | 783 | .write = devcgroup_access_write, |
| 791 | .private = DEVCG_DENY, | 784 | .private = DEVCG_DENY, |
| 792 | }, | 785 | }, |
| 793 | { | 786 | { |
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig index d35b4915b00d..d606f3d12d6b 100644 --- a/security/integrity/evm/Kconfig +++ b/security/integrity/evm/Kconfig | |||
| @@ -12,15 +12,41 @@ config EVM | |||
| 12 | 12 | ||
| 13 | If you are unsure how to answer this question, answer N. | 13 | If you are unsure how to answer this question, answer N. |
| 14 | 14 | ||
| 15 | config EVM_HMAC_VERSION | 15 | if EVM |
| 16 | int "EVM HMAC version" | 16 | |
| 17 | menu "EVM options" | ||
| 18 | |||
| 19 | config EVM_ATTR_FSUUID | ||
| 20 | bool "FSUUID (version 2)" | ||
| 21 | default y | ||
| 17 | depends on EVM | 22 | depends on EVM |
| 18 | default 2 | ||
| 19 | help | 23 | help |
| 20 | This options adds EVM HMAC version support. | 24 | Include filesystem UUID for HMAC calculation. |
| 21 | 1 - original version | 25 | |
| 22 | 2 - add per filesystem unique identifier (UUID) (default) | 26 | Default value is 'selected', which is former version 2. |
| 27 | if 'not selected', it is former version 1 | ||
| 23 | 28 | ||
| 24 | WARNING: changing the HMAC calculation method or adding | 29 | WARNING: changing the HMAC calculation method or adding |
| 25 | additional info to the calculation, requires existing EVM | 30 | additional info to the calculation, requires existing EVM |
| 26 | labeled file systems to be relabeled. | 31 | labeled file systems to be relabeled. |
| 32 | |||
| 33 | config EVM_EXTRA_SMACK_XATTRS | ||
| 34 | bool "Additional SMACK xattrs" | ||
| 35 | depends on EVM && SECURITY_SMACK | ||
| 36 | default n | ||
| 37 | help | ||
| 38 | Include additional SMACK xattrs for HMAC calculation. | ||
| 39 | |||
| 40 | In addition to the original security xattrs (eg. security.selinux, | ||
| 41 | security.SMACK64, security.capability, and security.ima) included | ||
| 42 | in the HMAC calculation, enabling this option includes newly defined | ||
| 43 | Smack xattrs: security.SMACK64EXEC, security.SMACK64TRANSMUTE and | ||
| 44 | security.SMACK64MMAP. | ||
| 45 | |||
| 46 | WARNING: changing the HMAC calculation method or adding | ||
| 47 | additional info to the calculation, requires existing EVM | ||
| 48 | labeled file systems to be relabeled. | ||
| 49 | |||
| 50 | endmenu | ||
| 51 | |||
| 52 | endif | ||
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 37c88ddb3cfe..88bfe77efa1c 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h | |||
| @@ -24,7 +24,10 @@ | |||
| 24 | extern int evm_initialized; | 24 | extern int evm_initialized; |
| 25 | extern char *evm_hmac; | 25 | extern char *evm_hmac; |
| 26 | extern char *evm_hash; | 26 | extern char *evm_hash; |
| 27 | extern int evm_hmac_version; | 27 | |
| 28 | #define EVM_ATTR_FSUUID 0x0001 | ||
| 29 | |||
| 30 | extern int evm_hmac_attrs; | ||
| 28 | 31 | ||
| 29 | extern struct crypto_shash *hmac_tfm; | 32 | extern struct crypto_shash *hmac_tfm; |
| 30 | extern struct crypto_shash *hash_tfm; | 33 | extern struct crypto_shash *hash_tfm; |
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 6b540f1822e0..5e9687f02e1b 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c | |||
| @@ -112,7 +112,7 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, | |||
| 112 | hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); | 112 | hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid); |
| 113 | hmac_misc.mode = inode->i_mode; | 113 | hmac_misc.mode = inode->i_mode; |
| 114 | crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); | 114 | crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); |
| 115 | if (evm_hmac_version > 1) | 115 | if (evm_hmac_attrs & EVM_ATTR_FSUUID) |
| 116 | crypto_shash_update(desc, inode->i_sb->s_uuid, | 116 | crypto_shash_update(desc, inode->i_sb->s_uuid, |
| 117 | sizeof(inode->i_sb->s_uuid)); | 117 | sizeof(inode->i_sb->s_uuid)); |
| 118 | crypto_shash_final(desc, digest); | 118 | crypto_shash_final(desc, digest); |
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 6e0bd933b6a9..3bcb80df4d01 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c | |||
| @@ -32,7 +32,7 @@ static char *integrity_status_msg[] = { | |||
| 32 | }; | 32 | }; |
| 33 | char *evm_hmac = "hmac(sha1)"; | 33 | char *evm_hmac = "hmac(sha1)"; |
| 34 | char *evm_hash = "sha1"; | 34 | char *evm_hash = "sha1"; |
| 35 | int evm_hmac_version = CONFIG_EVM_HMAC_VERSION; | 35 | int evm_hmac_attrs; |
| 36 | 36 | ||
| 37 | char *evm_config_xattrnames[] = { | 37 | char *evm_config_xattrnames[] = { |
| 38 | #ifdef CONFIG_SECURITY_SELINUX | 38 | #ifdef CONFIG_SECURITY_SELINUX |
| @@ -40,6 +40,11 @@ char *evm_config_xattrnames[] = { | |||
| 40 | #endif | 40 | #endif |
| 41 | #ifdef CONFIG_SECURITY_SMACK | 41 | #ifdef CONFIG_SECURITY_SMACK |
| 42 | XATTR_NAME_SMACK, | 42 | XATTR_NAME_SMACK, |
| 43 | #ifdef CONFIG_EVM_EXTRA_SMACK_XATTRS | ||
| 44 | XATTR_NAME_SMACKEXEC, | ||
| 45 | XATTR_NAME_SMACKTRANSMUTE, | ||
| 46 | XATTR_NAME_SMACKMMAP, | ||
| 47 | #endif | ||
| 43 | #endif | 48 | #endif |
| 44 | #ifdef CONFIG_IMA_APPRAISE | 49 | #ifdef CONFIG_IMA_APPRAISE |
| 45 | XATTR_NAME_IMA, | 50 | XATTR_NAME_IMA, |
| @@ -57,6 +62,14 @@ static int __init evm_set_fixmode(char *str) | |||
| 57 | } | 62 | } |
| 58 | __setup("evm=", evm_set_fixmode); | 63 | __setup("evm=", evm_set_fixmode); |
| 59 | 64 | ||
| 65 | static void __init evm_init_config(void) | ||
| 66 | { | ||
| 67 | #ifdef CONFIG_EVM_ATTR_FSUUID | ||
| 68 | evm_hmac_attrs |= EVM_ATTR_FSUUID; | ||
| 69 | #endif | ||
| 70 | pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs); | ||
| 71 | } | ||
| 72 | |||
| 60 | static int evm_find_protected_xattrs(struct dentry *dentry) | 73 | static int evm_find_protected_xattrs(struct dentry *dentry) |
| 61 | { | 74 | { |
| 62 | struct inode *inode = dentry->d_inode; | 75 | struct inode *inode = dentry->d_inode; |
| @@ -287,12 +300,20 @@ out: | |||
| 287 | * @xattr_value: pointer to the new extended attribute value | 300 | * @xattr_value: pointer to the new extended attribute value |
| 288 | * @xattr_value_len: pointer to the new extended attribute value length | 301 | * @xattr_value_len: pointer to the new extended attribute value length |
| 289 | * | 302 | * |
| 290 | * Updating 'security.evm' requires CAP_SYS_ADMIN privileges and that | 303 | * Before allowing the 'security.evm' protected xattr to be updated, |
| 291 | * the current value is valid. | 304 | * verify the existing value is valid. As only the kernel should have |
| 305 | * access to the EVM encrypted key needed to calculate the HMAC, prevent | ||
| 306 | * userspace from writing HMAC value. Writing 'security.evm' requires | ||
| 307 | * requires CAP_SYS_ADMIN privileges. | ||
| 292 | */ | 308 | */ |
| 293 | int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, | 309 | int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, |
| 294 | const void *xattr_value, size_t xattr_value_len) | 310 | const void *xattr_value, size_t xattr_value_len) |
| 295 | { | 311 | { |
| 312 | const struct evm_ima_xattr_data *xattr_data = xattr_value; | ||
| 313 | |||
| 314 | if ((strcmp(xattr_name, XATTR_NAME_EVM) == 0) | ||
| 315 | && (xattr_data->type == EVM_XATTR_HMAC)) | ||
| 316 | return -EPERM; | ||
| 296 | return evm_protect_xattr(dentry, xattr_name, xattr_value, | 317 | return evm_protect_xattr(dentry, xattr_name, xattr_value, |
| 297 | xattr_value_len); | 318 | xattr_value_len); |
| 298 | } | 319 | } |
| @@ -432,6 +453,8 @@ static int __init init_evm(void) | |||
| 432 | { | 453 | { |
| 433 | int error; | 454 | int error; |
| 434 | 455 | ||
| 456 | evm_init_config(); | ||
| 457 | |||
| 435 | error = evm_init_secfs(); | 458 | error = evm_init_secfs(); |
| 436 | if (error < 0) { | 459 | if (error < 0) { |
| 437 | pr_info("Error registering secfs\n"); | 460 | pr_info("Error registering secfs\n"); |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index ba9e4d792dd5..d9cd5ce14d2b 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
| @@ -199,6 +199,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, | |||
| 199 | struct evm_ima_xattr_data **xattr_value, | 199 | struct evm_ima_xattr_data **xattr_value, |
| 200 | int *xattr_len) | 200 | int *xattr_len) |
| 201 | { | 201 | { |
| 202 | const char *audit_cause = "failed"; | ||
| 202 | struct inode *inode = file_inode(file); | 203 | struct inode *inode = file_inode(file); |
| 203 | const char *filename = file->f_dentry->d_name.name; | 204 | const char *filename = file->f_dentry->d_name.name; |
| 204 | int result = 0; | 205 | int result = 0; |
| @@ -213,6 +214,12 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, | |||
| 213 | if (!(iint->flags & IMA_COLLECTED)) { | 214 | if (!(iint->flags & IMA_COLLECTED)) { |
| 214 | u64 i_version = file_inode(file)->i_version; | 215 | u64 i_version = file_inode(file)->i_version; |
| 215 | 216 | ||
| 217 | if (file->f_flags & O_DIRECT) { | ||
| 218 | audit_cause = "failed(directio)"; | ||
| 219 | result = -EACCES; | ||
| 220 | goto out; | ||
| 221 | } | ||
| 222 | |||
| 216 | /* use default hash algorithm */ | 223 | /* use default hash algorithm */ |
| 217 | hash.hdr.algo = ima_hash_algo; | 224 | hash.hdr.algo = ima_hash_algo; |
| 218 | 225 | ||
| @@ -233,9 +240,10 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, | |||
| 233 | result = -ENOMEM; | 240 | result = -ENOMEM; |
| 234 | } | 241 | } |
| 235 | } | 242 | } |
| 243 | out: | ||
| 236 | if (result) | 244 | if (result) |
| 237 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, | 245 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, |
| 238 | filename, "collect_data", "failed", | 246 | filename, "collect_data", audit_cause, |
| 239 | result, 0); | 247 | result, 0); |
| 240 | return result; | 248 | return result; |
| 241 | } | 249 | } |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 291bf0f3a46d..d3113d4aaa3c 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
| @@ -341,7 +341,7 @@ static int ima_protect_xattr(struct dentry *dentry, const char *xattr_name, | |||
| 341 | return 0; | 341 | return 0; |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | static void ima_reset_appraise_flags(struct inode *inode) | 344 | static void ima_reset_appraise_flags(struct inode *inode, int digsig) |
| 345 | { | 345 | { |
| 346 | struct integrity_iint_cache *iint; | 346 | struct integrity_iint_cache *iint; |
| 347 | 347 | ||
| @@ -353,18 +353,22 @@ static void ima_reset_appraise_flags(struct inode *inode) | |||
| 353 | return; | 353 | return; |
| 354 | 354 | ||
| 355 | iint->flags &= ~IMA_DONE_MASK; | 355 | iint->flags &= ~IMA_DONE_MASK; |
| 356 | if (digsig) | ||
| 357 | iint->flags |= IMA_DIGSIG; | ||
| 356 | return; | 358 | return; |
| 357 | } | 359 | } |
| 358 | 360 | ||
| 359 | int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, | 361 | int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, |
| 360 | const void *xattr_value, size_t xattr_value_len) | 362 | const void *xattr_value, size_t xattr_value_len) |
| 361 | { | 363 | { |
| 364 | const struct evm_ima_xattr_data *xvalue = xattr_value; | ||
| 362 | int result; | 365 | int result; |
| 363 | 366 | ||
| 364 | result = ima_protect_xattr(dentry, xattr_name, xattr_value, | 367 | result = ima_protect_xattr(dentry, xattr_name, xattr_value, |
| 365 | xattr_value_len); | 368 | xattr_value_len); |
| 366 | if (result == 1) { | 369 | if (result == 1) { |
| 367 | ima_reset_appraise_flags(dentry->d_inode); | 370 | ima_reset_appraise_flags(dentry->d_inode, |
| 371 | (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0); | ||
| 368 | result = 0; | 372 | result = 0; |
| 369 | } | 373 | } |
| 370 | return result; | 374 | return result; |
| @@ -376,7 +380,7 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) | |||
| 376 | 380 | ||
| 377 | result = ima_protect_xattr(dentry, xattr_name, NULL, 0); | 381 | result = ima_protect_xattr(dentry, xattr_name, NULL, 0); |
| 378 | if (result == 1) { | 382 | if (result == 1) { |
| 379 | ima_reset_appraise_flags(dentry->d_inode); | 383 | ima_reset_appraise_flags(dentry->d_inode, 0); |
| 380 | result = 0; | 384 | result = 0; |
| 381 | } | 385 | } |
| 382 | return result; | 386 | return result; |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 1bde8e627766..ccd0ac8fa9a0 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
| @@ -27,6 +27,36 @@ | |||
| 27 | 27 | ||
| 28 | static struct crypto_shash *ima_shash_tfm; | 28 | static struct crypto_shash *ima_shash_tfm; |
| 29 | 29 | ||
| 30 | /** | ||
| 31 | * ima_kernel_read - read file content | ||
| 32 | * | ||
| 33 | * This is a function for reading file content instead of kernel_read(). | ||
| 34 | * It does not perform locking checks to ensure it cannot be blocked. | ||
| 35 | * It does not perform security checks because it is irrelevant for IMA. | ||
| 36 | * | ||
| 37 | */ | ||
| 38 | static int ima_kernel_read(struct file *file, loff_t offset, | ||
| 39 | char *addr, unsigned long count) | ||
| 40 | { | ||
| 41 | mm_segment_t old_fs; | ||
| 42 | char __user *buf = addr; | ||
| 43 | ssize_t ret; | ||
| 44 | |||
| 45 | if (!(file->f_mode & FMODE_READ)) | ||
| 46 | return -EBADF; | ||
| 47 | if (!file->f_op->read && !file->f_op->aio_read) | ||
| 48 | return -EINVAL; | ||
| 49 | |||
| 50 | old_fs = get_fs(); | ||
| 51 | set_fs(get_ds()); | ||
| 52 | if (file->f_op->read) | ||
| 53 | ret = file->f_op->read(file, buf, count, &offset); | ||
| 54 | else | ||
| 55 | ret = do_sync_read(file, buf, count, &offset); | ||
| 56 | set_fs(old_fs); | ||
| 57 | return ret; | ||
| 58 | } | ||
| 59 | |||
| 30 | int ima_init_crypto(void) | 60 | int ima_init_crypto(void) |
| 31 | { | 61 | { |
| 32 | long rc; | 62 | long rc; |
| @@ -104,7 +134,7 @@ static int ima_calc_file_hash_tfm(struct file *file, | |||
| 104 | while (offset < i_size) { | 134 | while (offset < i_size) { |
| 105 | int rbuf_len; | 135 | int rbuf_len; |
| 106 | 136 | ||
| 107 | rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE); | 137 | rbuf_len = ima_kernel_read(file, offset, rbuf, PAGE_SIZE); |
| 108 | if (rbuf_len < 0) { | 138 | if (rbuf_len < 0) { |
| 109 | rc = rbuf_len; | 139 | rc = rbuf_len; |
| 110 | break; | 140 | break; |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 52ac6cf41f88..09baa335ebc7 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
| @@ -81,7 +81,6 @@ static void ima_rdwr_violation_check(struct file *file) | |||
| 81 | { | 81 | { |
| 82 | struct inode *inode = file_inode(file); | 82 | struct inode *inode = file_inode(file); |
| 83 | fmode_t mode = file->f_mode; | 83 | fmode_t mode = file->f_mode; |
| 84 | int must_measure; | ||
| 85 | bool send_tomtou = false, send_writers = false; | 84 | bool send_tomtou = false, send_writers = false; |
| 86 | char *pathbuf = NULL; | 85 | char *pathbuf = NULL; |
| 87 | const char *pathname; | 86 | const char *pathname; |
| @@ -92,18 +91,19 @@ static void ima_rdwr_violation_check(struct file *file) | |||
| 92 | mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */ | 91 | mutex_lock(&inode->i_mutex); /* file metadata: permissions, xattr */ |
| 93 | 92 | ||
| 94 | if (mode & FMODE_WRITE) { | 93 | if (mode & FMODE_WRITE) { |
| 95 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) | 94 | if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) { |
| 96 | send_tomtou = true; | 95 | struct integrity_iint_cache *iint; |
| 97 | goto out; | 96 | iint = integrity_iint_find(inode); |
| 97 | /* IMA_MEASURE is set from reader side */ | ||
| 98 | if (iint && (iint->flags & IMA_MEASURE)) | ||
| 99 | send_tomtou = true; | ||
| 100 | } | ||
| 101 | } else { | ||
| 102 | if ((atomic_read(&inode->i_writecount) > 0) && | ||
| 103 | ima_must_measure(inode, MAY_READ, FILE_CHECK)) | ||
| 104 | send_writers = true; | ||
| 98 | } | 105 | } |
| 99 | 106 | ||
| 100 | must_measure = ima_must_measure(inode, MAY_READ, FILE_CHECK); | ||
| 101 | if (!must_measure) | ||
| 102 | goto out; | ||
| 103 | |||
| 104 | if (atomic_read(&inode->i_writecount) > 0) | ||
| 105 | send_writers = true; | ||
| 106 | out: | ||
| 107 | mutex_unlock(&inode->i_mutex); | 107 | mutex_unlock(&inode->i_mutex); |
| 108 | 108 | ||
| 109 | if (!send_tomtou && !send_writers) | 109 | if (!send_tomtou && !send_writers) |
| @@ -214,8 +214,11 @@ static int process_measurement(struct file *file, const char *filename, | |||
| 214 | xattr_ptr = &xattr_value; | 214 | xattr_ptr = &xattr_value; |
| 215 | 215 | ||
| 216 | rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len); | 216 | rc = ima_collect_measurement(iint, file, xattr_ptr, &xattr_len); |
| 217 | if (rc != 0) | 217 | if (rc != 0) { |
| 218 | if (file->f_flags & O_DIRECT) | ||
| 219 | rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES; | ||
| 218 | goto out_digsig; | 220 | goto out_digsig; |
| 221 | } | ||
| 219 | 222 | ||
| 220 | pathname = filename ?: ima_d_path(&file->f_path, &pathbuf); | 223 | pathname = filename ?: ima_d_path(&file->f_path, &pathbuf); |
| 221 | 224 | ||
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 93873a450ff7..40a7488f6721 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
| @@ -353,7 +353,7 @@ enum { | |||
| 353 | Opt_obj_user, Opt_obj_role, Opt_obj_type, | 353 | Opt_obj_user, Opt_obj_role, Opt_obj_type, |
| 354 | Opt_subj_user, Opt_subj_role, Opt_subj_type, | 354 | Opt_subj_user, Opt_subj_role, Opt_subj_type, |
| 355 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner, | 355 | Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner, |
| 356 | Opt_appraise_type, Opt_fsuuid | 356 | Opt_appraise_type, Opt_fsuuid, Opt_permit_directio |
| 357 | }; | 357 | }; |
| 358 | 358 | ||
| 359 | static match_table_t policy_tokens = { | 359 | static match_table_t policy_tokens = { |
| @@ -375,6 +375,7 @@ static match_table_t policy_tokens = { | |||
| 375 | {Opt_uid, "uid=%s"}, | 375 | {Opt_uid, "uid=%s"}, |
| 376 | {Opt_fowner, "fowner=%s"}, | 376 | {Opt_fowner, "fowner=%s"}, |
| 377 | {Opt_appraise_type, "appraise_type=%s"}, | 377 | {Opt_appraise_type, "appraise_type=%s"}, |
| 378 | {Opt_permit_directio, "permit_directio"}, | ||
| 378 | {Opt_err, NULL} | 379 | {Opt_err, NULL} |
| 379 | }; | 380 | }; |
| 380 | 381 | ||
| @@ -622,6 +623,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) | |||
| 622 | else | 623 | else |
| 623 | result = -EINVAL; | 624 | result = -EINVAL; |
| 624 | break; | 625 | break; |
| 626 | case Opt_permit_directio: | ||
| 627 | entry->flags |= IMA_PERMIT_DIRECTIO; | ||
| 628 | break; | ||
| 625 | case Opt_err: | 629 | case Opt_err: |
| 626 | ima_log_string(ab, "UNKNOWN", p); | 630 | ima_log_string(ab, "UNKNOWN", p); |
| 627 | result = -EINVAL; | 631 | result = -EINVAL; |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 2fb5e53e927f..33c0a70f6b15 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #define IMA_ACTION_FLAGS 0xff000000 | 30 | #define IMA_ACTION_FLAGS 0xff000000 |
| 31 | #define IMA_DIGSIG 0x01000000 | 31 | #define IMA_DIGSIG 0x01000000 |
| 32 | #define IMA_DIGSIG_REQUIRED 0x02000000 | 32 | #define IMA_DIGSIG_REQUIRED 0x02000000 |
| 33 | #define IMA_PERMIT_DIRECTIO 0x04000000 | ||
| 33 | 34 | ||
| 34 | #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ | 35 | #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ |
| 35 | IMA_APPRAISE_SUBMASK) | 36 | IMA_APPRAISE_SUBMASK) |
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index 14d04e63b1f0..be491a74c1ed 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h | |||
| @@ -147,7 +147,7 @@ struct security_class_mapping secclass_map[] = { | |||
| 147 | { "peer", { "recv", NULL } }, | 147 | { "peer", { "recv", NULL } }, |
| 148 | { "capability2", | 148 | { "capability2", |
| 149 | { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", | 149 | { "mac_override", "mac_admin", "syslog", "wake_alarm", "block_suspend", |
| 150 | NULL } }, | 150 | "audit_read", NULL } }, |
| 151 | { "kernel_service", { "use_as_override", "create_files_as", NULL } }, | 151 | { "kernel_service", { "use_as_override", "create_files_as", NULL } }, |
| 152 | { "tun_socket", | 152 | { "tun_socket", |
| 153 | { COMMON_SOCK_PERMS, "attach_queue", NULL } }, | 153 | { COMMON_SOCK_PERMS, "attach_queue", NULL } }, |
