diff options
| author | Paul Moore <pmoore@redhat.com> | 2014-08-05 15:44:22 -0400 |
|---|---|---|
| committer | Paul Moore <pmoore@redhat.com> | 2014-08-05 15:44:22 -0400 |
| commit | aa9e0de81b5b257f6dae48efe2ed5f255f066497 (patch) | |
| tree | 9b0b791d5912368006115427e74105cfe26750bd /security | |
| parent | 4fbe63d1c773cceef3fe1f6ed0c9c268f4f24760 (diff) | |
| parent | 19583ca584d6f574384e17fe7613dfaeadcdc4a6 (diff) | |
Merge tag 'v3.16' into next
Linux 3.16
Diffstat (limited to 'security')
27 files changed, 490 insertions, 175 deletions
diff --git a/security/capability.c b/security/capability.c index ad0d4de69944..e76373de3129 100644 --- a/security/capability.c +++ b/security/capability.c | |||
| @@ -879,7 +879,7 @@ static void cap_key_free(struct key *key) | |||
| 879 | } | 879 | } |
| 880 | 880 | ||
| 881 | static int cap_key_permission(key_ref_t key_ref, const struct cred *cred, | 881 | static int cap_key_permission(key_ref_t key_ref, const struct cred *cred, |
| 882 | key_perm_t perm) | 882 | unsigned perm) |
| 883 | { | 883 | { |
| 884 | return 0; | 884 | return 0; |
| 885 | } | 885 | } |
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/keys/internal.h b/security/keys/internal.h index 80b2aac4f50c..5f20da01fd8d 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
| @@ -176,20 +176,11 @@ extern int key_task_permission(const key_ref_t key_ref, | |||
| 176 | /* | 176 | /* |
| 177 | * Check to see whether permission is granted to use a key in the desired way. | 177 | * Check to see whether permission is granted to use a key in the desired way. |
| 178 | */ | 178 | */ |
| 179 | static inline int key_permission(const key_ref_t key_ref, key_perm_t perm) | 179 | static inline int key_permission(const key_ref_t key_ref, unsigned perm) |
| 180 | { | 180 | { |
| 181 | return key_task_permission(key_ref, current_cred(), perm); | 181 | return key_task_permission(key_ref, current_cred(), perm); |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | /* required permissions */ | ||
| 185 | #define KEY_VIEW 0x01 /* require permission to view attributes */ | ||
| 186 | #define KEY_READ 0x02 /* require permission to read content */ | ||
| 187 | #define KEY_WRITE 0x04 /* require permission to update / modify */ | ||
| 188 | #define KEY_SEARCH 0x08 /* require permission to search (keyring) or find (key) */ | ||
| 189 | #define KEY_LINK 0x10 /* require permission to link */ | ||
| 190 | #define KEY_SETATTR 0x20 /* require permission to change attributes */ | ||
| 191 | #define KEY_ALL 0x3f /* all the above permissions */ | ||
| 192 | |||
| 193 | /* | 184 | /* |
| 194 | * Authorisation record for request_key(). | 185 | * Authorisation record for request_key(). |
| 195 | */ | 186 | */ |
diff --git a/security/keys/key.c b/security/keys/key.c index 6e21c11e48bc..2048a110e7f1 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
| @@ -714,7 +714,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref, | |||
| 714 | int ret; | 714 | int ret; |
| 715 | 715 | ||
| 716 | /* need write permission on the key to update it */ | 716 | /* need write permission on the key to update it */ |
| 717 | ret = key_permission(key_ref, KEY_WRITE); | 717 | ret = key_permission(key_ref, KEY_NEED_WRITE); |
| 718 | if (ret < 0) | 718 | if (ret < 0) |
| 719 | goto error; | 719 | goto error; |
| 720 | 720 | ||
| @@ -838,7 +838,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
| 838 | 838 | ||
| 839 | /* if we're going to allocate a new key, we're going to have | 839 | /* if we're going to allocate a new key, we're going to have |
| 840 | * to modify the keyring */ | 840 | * to modify the keyring */ |
| 841 | ret = key_permission(keyring_ref, KEY_WRITE); | 841 | ret = key_permission(keyring_ref, KEY_NEED_WRITE); |
| 842 | if (ret < 0) { | 842 | if (ret < 0) { |
| 843 | key_ref = ERR_PTR(ret); | 843 | key_ref = ERR_PTR(ret); |
| 844 | goto error_link_end; | 844 | goto error_link_end; |
| @@ -928,7 +928,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
| 928 | key_check(key); | 928 | key_check(key); |
| 929 | 929 | ||
| 930 | /* the key must be writable */ | 930 | /* the key must be writable */ |
| 931 | ret = key_permission(key_ref, KEY_WRITE); | 931 | ret = key_permission(key_ref, KEY_NEED_WRITE); |
| 932 | if (ret < 0) | 932 | if (ret < 0) |
| 933 | goto error; | 933 | goto error; |
| 934 | 934 | ||
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index cee72ce64222..cd5bd0cef25d 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
| @@ -111,7 +111,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | /* find the target keyring (which must be writable) */ | 113 | /* find the target keyring (which must be writable) */ |
| 114 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); | 114 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); |
| 115 | if (IS_ERR(keyring_ref)) { | 115 | if (IS_ERR(keyring_ref)) { |
| 116 | ret = PTR_ERR(keyring_ref); | 116 | ret = PTR_ERR(keyring_ref); |
| 117 | goto error3; | 117 | goto error3; |
| @@ -195,7 +195,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
| 195 | dest_ref = NULL; | 195 | dest_ref = NULL; |
| 196 | if (destringid) { | 196 | if (destringid) { |
| 197 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, | 197 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
| 198 | KEY_WRITE); | 198 | KEY_NEED_WRITE); |
| 199 | if (IS_ERR(dest_ref)) { | 199 | if (IS_ERR(dest_ref)) { |
| 200 | ret = PTR_ERR(dest_ref); | 200 | ret = PTR_ERR(dest_ref); |
| 201 | goto error3; | 201 | goto error3; |
| @@ -253,7 +253,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create) | |||
| 253 | long ret; | 253 | long ret; |
| 254 | 254 | ||
| 255 | lflags = create ? KEY_LOOKUP_CREATE : 0; | 255 | lflags = create ? KEY_LOOKUP_CREATE : 0; |
| 256 | key_ref = lookup_user_key(id, lflags, KEY_SEARCH); | 256 | key_ref = lookup_user_key(id, lflags, KEY_NEED_SEARCH); |
| 257 | if (IS_ERR(key_ref)) { | 257 | if (IS_ERR(key_ref)) { |
| 258 | ret = PTR_ERR(key_ref); | 258 | ret = PTR_ERR(key_ref); |
| 259 | goto error; | 259 | goto error; |
| @@ -334,7 +334,7 @@ long keyctl_update_key(key_serial_t id, | |||
| 334 | } | 334 | } |
| 335 | 335 | ||
| 336 | /* find the target key (which must be writable) */ | 336 | /* find the target key (which must be writable) */ |
| 337 | key_ref = lookup_user_key(id, 0, KEY_WRITE); | 337 | key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE); |
| 338 | if (IS_ERR(key_ref)) { | 338 | if (IS_ERR(key_ref)) { |
| 339 | ret = PTR_ERR(key_ref); | 339 | ret = PTR_ERR(key_ref); |
| 340 | goto error2; | 340 | goto error2; |
| @@ -365,12 +365,12 @@ long keyctl_revoke_key(key_serial_t id) | |||
| 365 | key_ref_t key_ref; | 365 | key_ref_t key_ref; |
| 366 | long ret; | 366 | long ret; |
| 367 | 367 | ||
| 368 | key_ref = lookup_user_key(id, 0, KEY_WRITE); | 368 | key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE); |
| 369 | if (IS_ERR(key_ref)) { | 369 | if (IS_ERR(key_ref)) { |
| 370 | ret = PTR_ERR(key_ref); | 370 | ret = PTR_ERR(key_ref); |
| 371 | if (ret != -EACCES) | 371 | if (ret != -EACCES) |
| 372 | goto error; | 372 | goto error; |
| 373 | key_ref = lookup_user_key(id, 0, KEY_SETATTR); | 373 | key_ref = lookup_user_key(id, 0, KEY_NEED_SETATTR); |
| 374 | if (IS_ERR(key_ref)) { | 374 | if (IS_ERR(key_ref)) { |
| 375 | ret = PTR_ERR(key_ref); | 375 | ret = PTR_ERR(key_ref); |
| 376 | goto error; | 376 | goto error; |
| @@ -401,7 +401,7 @@ long keyctl_invalidate_key(key_serial_t id) | |||
| 401 | 401 | ||
| 402 | kenter("%d", id); | 402 | kenter("%d", id); |
| 403 | 403 | ||
| 404 | key_ref = lookup_user_key(id, 0, KEY_SEARCH); | 404 | key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH); |
| 405 | if (IS_ERR(key_ref)) { | 405 | if (IS_ERR(key_ref)) { |
| 406 | ret = PTR_ERR(key_ref); | 406 | ret = PTR_ERR(key_ref); |
| 407 | goto error; | 407 | goto error; |
| @@ -428,7 +428,7 @@ long keyctl_keyring_clear(key_serial_t ringid) | |||
| 428 | key_ref_t keyring_ref; | 428 | key_ref_t keyring_ref; |
| 429 | long ret; | 429 | long ret; |
| 430 | 430 | ||
| 431 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); | 431 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); |
| 432 | if (IS_ERR(keyring_ref)) { | 432 | if (IS_ERR(keyring_ref)) { |
| 433 | ret = PTR_ERR(keyring_ref); | 433 | ret = PTR_ERR(keyring_ref); |
| 434 | 434 | ||
| @@ -470,13 +470,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) | |||
| 470 | key_ref_t keyring_ref, key_ref; | 470 | key_ref_t keyring_ref, key_ref; |
| 471 | long ret; | 471 | long ret; |
| 472 | 472 | ||
| 473 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); | 473 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); |
| 474 | if (IS_ERR(keyring_ref)) { | 474 | if (IS_ERR(keyring_ref)) { |
| 475 | ret = PTR_ERR(keyring_ref); | 475 | ret = PTR_ERR(keyring_ref); |
| 476 | goto error; | 476 | goto error; |
| 477 | } | 477 | } |
| 478 | 478 | ||
| 479 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); | 479 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_NEED_LINK); |
| 480 | if (IS_ERR(key_ref)) { | 480 | if (IS_ERR(key_ref)) { |
| 481 | ret = PTR_ERR(key_ref); | 481 | ret = PTR_ERR(key_ref); |
| 482 | goto error2; | 482 | goto error2; |
| @@ -505,7 +505,7 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) | |||
| 505 | key_ref_t keyring_ref, key_ref; | 505 | key_ref_t keyring_ref, key_ref; |
| 506 | long ret; | 506 | long ret; |
| 507 | 507 | ||
| 508 | keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); | 508 | keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_WRITE); |
| 509 | if (IS_ERR(keyring_ref)) { | 509 | if (IS_ERR(keyring_ref)) { |
| 510 | ret = PTR_ERR(keyring_ref); | 510 | ret = PTR_ERR(keyring_ref); |
| 511 | goto error; | 511 | goto error; |
| @@ -548,7 +548,7 @@ long keyctl_describe_key(key_serial_t keyid, | |||
| 548 | char *tmpbuf; | 548 | char *tmpbuf; |
| 549 | long ret; | 549 | long ret; |
| 550 | 550 | ||
| 551 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); | 551 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); |
| 552 | if (IS_ERR(key_ref)) { | 552 | if (IS_ERR(key_ref)) { |
| 553 | /* viewing a key under construction is permitted if we have the | 553 | /* viewing a key under construction is permitted if we have the |
| 554 | * authorisation token handy */ | 554 | * authorisation token handy */ |
| @@ -639,7 +639,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
| 639 | } | 639 | } |
| 640 | 640 | ||
| 641 | /* get the keyring at which to begin the search */ | 641 | /* get the keyring at which to begin the search */ |
| 642 | keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); | 642 | keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_SEARCH); |
| 643 | if (IS_ERR(keyring_ref)) { | 643 | if (IS_ERR(keyring_ref)) { |
| 644 | ret = PTR_ERR(keyring_ref); | 644 | ret = PTR_ERR(keyring_ref); |
| 645 | goto error2; | 645 | goto error2; |
| @@ -649,7 +649,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
| 649 | dest_ref = NULL; | 649 | dest_ref = NULL; |
| 650 | if (destringid) { | 650 | if (destringid) { |
| 651 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, | 651 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
| 652 | KEY_WRITE); | 652 | KEY_NEED_WRITE); |
| 653 | if (IS_ERR(dest_ref)) { | 653 | if (IS_ERR(dest_ref)) { |
| 654 | ret = PTR_ERR(dest_ref); | 654 | ret = PTR_ERR(dest_ref); |
| 655 | goto error3; | 655 | goto error3; |
| @@ -676,7 +676,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
| 676 | 676 | ||
| 677 | /* link the resulting key to the destination keyring if we can */ | 677 | /* link the resulting key to the destination keyring if we can */ |
| 678 | if (dest_ref) { | 678 | if (dest_ref) { |
| 679 | ret = key_permission(key_ref, KEY_LINK); | 679 | ret = key_permission(key_ref, KEY_NEED_LINK); |
| 680 | if (ret < 0) | 680 | if (ret < 0) |
| 681 | goto error6; | 681 | goto error6; |
| 682 | 682 | ||
| @@ -727,7 +727,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |||
| 727 | key = key_ref_to_ptr(key_ref); | 727 | key = key_ref_to_ptr(key_ref); |
| 728 | 728 | ||
| 729 | /* see if we can read it directly */ | 729 | /* see if we can read it directly */ |
| 730 | ret = key_permission(key_ref, KEY_READ); | 730 | ret = key_permission(key_ref, KEY_NEED_READ); |
| 731 | if (ret == 0) | 731 | if (ret == 0) |
| 732 | goto can_read_key; | 732 | goto can_read_key; |
| 733 | if (ret != -EACCES) | 733 | if (ret != -EACCES) |
| @@ -799,7 +799,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group) | |||
| 799 | goto error; | 799 | goto error; |
| 800 | 800 | ||
| 801 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, | 801 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| 802 | KEY_SETATTR); | 802 | KEY_NEED_SETATTR); |
| 803 | if (IS_ERR(key_ref)) { | 803 | if (IS_ERR(key_ref)) { |
| 804 | ret = PTR_ERR(key_ref); | 804 | ret = PTR_ERR(key_ref); |
| 805 | goto error; | 805 | goto error; |
| @@ -905,7 +905,7 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |||
| 905 | goto error; | 905 | goto error; |
| 906 | 906 | ||
| 907 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, | 907 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| 908 | KEY_SETATTR); | 908 | KEY_NEED_SETATTR); |
| 909 | if (IS_ERR(key_ref)) { | 909 | if (IS_ERR(key_ref)) { |
| 910 | ret = PTR_ERR(key_ref); | 910 | ret = PTR_ERR(key_ref); |
| 911 | goto error; | 911 | goto error; |
| @@ -947,7 +947,7 @@ static long get_instantiation_keyring(key_serial_t ringid, | |||
| 947 | 947 | ||
| 948 | /* if a specific keyring is nominated by ID, then use that */ | 948 | /* if a specific keyring is nominated by ID, then use that */ |
| 949 | if (ringid > 0) { | 949 | if (ringid > 0) { |
| 950 | dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); | 950 | dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); |
| 951 | if (IS_ERR(dkref)) | 951 | if (IS_ERR(dkref)) |
| 952 | return PTR_ERR(dkref); | 952 | return PTR_ERR(dkref); |
| 953 | *_dest_keyring = key_ref_to_ptr(dkref); | 953 | *_dest_keyring = key_ref_to_ptr(dkref); |
| @@ -1315,7 +1315,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |||
| 1315 | long ret; | 1315 | long ret; |
| 1316 | 1316 | ||
| 1317 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, | 1317 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
| 1318 | KEY_SETATTR); | 1318 | KEY_NEED_SETATTR); |
| 1319 | if (IS_ERR(key_ref)) { | 1319 | if (IS_ERR(key_ref)) { |
| 1320 | /* setting the timeout on a key under construction is permitted | 1320 | /* setting the timeout on a key under construction is permitted |
| 1321 | * if we have the authorisation token handy */ | 1321 | * if we have the authorisation token handy */ |
| @@ -1418,7 +1418,7 @@ long keyctl_get_security(key_serial_t keyid, | |||
| 1418 | char *context; | 1418 | char *context; |
| 1419 | long ret; | 1419 | long ret; |
| 1420 | 1420 | ||
| 1421 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); | 1421 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); |
| 1422 | if (IS_ERR(key_ref)) { | 1422 | if (IS_ERR(key_ref)) { |
| 1423 | if (PTR_ERR(key_ref) != -EACCES) | 1423 | if (PTR_ERR(key_ref) != -EACCES) |
| 1424 | return PTR_ERR(key_ref); | 1424 | return PTR_ERR(key_ref); |
| @@ -1482,7 +1482,7 @@ long keyctl_session_to_parent(void) | |||
| 1482 | struct cred *cred; | 1482 | struct cred *cred; |
| 1483 | int ret; | 1483 | int ret; |
| 1484 | 1484 | ||
| 1485 | keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); | 1485 | keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_NEED_LINK); |
| 1486 | if (IS_ERR(keyring_r)) | 1486 | if (IS_ERR(keyring_r)) |
| 1487 | return PTR_ERR(keyring_r); | 1487 | return PTR_ERR(keyring_r); |
| 1488 | 1488 | ||
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 2fb2576dc644..9cf2575f0d97 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -541,7 +541,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data) | |||
| 541 | /* key must have search permissions */ | 541 | /* key must have search permissions */ |
| 542 | if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) && | 542 | if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) && |
| 543 | key_task_permission(make_key_ref(key, ctx->possessed), | 543 | key_task_permission(make_key_ref(key, ctx->possessed), |
| 544 | ctx->cred, KEY_SEARCH) < 0) { | 544 | ctx->cred, KEY_NEED_SEARCH) < 0) { |
| 545 | ctx->result = ERR_PTR(-EACCES); | 545 | ctx->result = ERR_PTR(-EACCES); |
| 546 | kleave(" = %d [!perm]", ctx->skipped_ret); | 546 | kleave(" = %d [!perm]", ctx->skipped_ret); |
| 547 | goto skipped; | 547 | goto skipped; |
| @@ -721,7 +721,7 @@ ascend_to_node: | |||
| 721 | /* Search a nested keyring */ | 721 | /* Search a nested keyring */ |
| 722 | if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) && | 722 | if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM) && |
| 723 | key_task_permission(make_key_ref(key, ctx->possessed), | 723 | key_task_permission(make_key_ref(key, ctx->possessed), |
| 724 | ctx->cred, KEY_SEARCH) < 0) | 724 | ctx->cred, KEY_NEED_SEARCH) < 0) |
| 725 | continue; | 725 | continue; |
| 726 | 726 | ||
| 727 | /* stack the current position */ | 727 | /* stack the current position */ |
| @@ -843,7 +843,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
| 843 | return ERR_PTR(-ENOTDIR); | 843 | return ERR_PTR(-ENOTDIR); |
| 844 | 844 | ||
| 845 | if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM)) { | 845 | if (!(ctx->flags & KEYRING_SEARCH_NO_CHECK_PERM)) { |
| 846 | err = key_task_permission(keyring_ref, ctx->cred, KEY_SEARCH); | 846 | err = key_task_permission(keyring_ref, ctx->cred, KEY_NEED_SEARCH); |
| 847 | if (err < 0) | 847 | if (err < 0) |
| 848 | return ERR_PTR(err); | 848 | return ERR_PTR(err); |
| 849 | } | 849 | } |
| @@ -973,7 +973,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
| 973 | 973 | ||
| 974 | if (!skip_perm_check && | 974 | if (!skip_perm_check && |
| 975 | key_permission(make_key_ref(keyring, 0), | 975 | key_permission(make_key_ref(keyring, 0), |
| 976 | KEY_SEARCH) < 0) | 976 | KEY_NEED_SEARCH) < 0) |
| 977 | continue; | 977 | continue; |
| 978 | 978 | ||
| 979 | /* we've got a match but we might end up racing with | 979 | /* we've got a match but we might end up racing with |
diff --git a/security/keys/permission.c b/security/keys/permission.c index efcc0c855a0d..732cc0beffdf 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | * permissions bits or the LSM check. | 28 | * permissions bits or the LSM check. |
| 29 | */ | 29 | */ |
| 30 | int key_task_permission(const key_ref_t key_ref, const struct cred *cred, | 30 | int key_task_permission(const key_ref_t key_ref, const struct cred *cred, |
| 31 | key_perm_t perm) | 31 | unsigned perm) |
| 32 | { | 32 | { |
| 33 | struct key *key; | 33 | struct key *key; |
| 34 | key_perm_t kperm; | 34 | key_perm_t kperm; |
| @@ -68,7 +68,7 @@ use_these_perms: | |||
| 68 | if (is_key_possessed(key_ref)) | 68 | if (is_key_possessed(key_ref)) |
| 69 | kperm |= key->perm >> 24; | 69 | kperm |= key->perm >> 24; |
| 70 | 70 | ||
| 71 | kperm = kperm & perm & KEY_ALL; | 71 | kperm = kperm & perm & KEY_NEED_ALL; |
| 72 | 72 | ||
| 73 | if (kperm != perm) | 73 | if (kperm != perm) |
| 74 | return -EACCES; | 74 | return -EACCES; |
diff --git a/security/keys/persistent.c b/security/keys/persistent.c index 0ad3ee283781..c9fae5ea89fe 100644 --- a/security/keys/persistent.c +++ b/security/keys/persistent.c | |||
| @@ -108,7 +108,7 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid, | |||
| 108 | return PTR_ERR(persistent_ref); | 108 | return PTR_ERR(persistent_ref); |
| 109 | 109 | ||
| 110 | found: | 110 | found: |
| 111 | ret = key_task_permission(persistent_ref, current_cred(), KEY_LINK); | 111 | ret = key_task_permission(persistent_ref, current_cred(), KEY_NEED_LINK); |
| 112 | if (ret == 0) { | 112 | if (ret == 0) { |
| 113 | persistent = key_ref_to_ptr(persistent_ref); | 113 | persistent = key_ref_to_ptr(persistent_ref); |
| 114 | ret = key_link(key_ref_to_ptr(dest_ref), persistent); | 114 | ret = key_link(key_ref_to_ptr(dest_ref), persistent); |
| @@ -151,7 +151,7 @@ long keyctl_get_persistent(uid_t _uid, key_serial_t destid) | |||
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | /* There must be a destination keyring */ | 153 | /* There must be a destination keyring */ |
| 154 | dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_WRITE); | 154 | dest_ref = lookup_user_key(destid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE); |
| 155 | if (IS_ERR(dest_ref)) | 155 | if (IS_ERR(dest_ref)) |
| 156 | return PTR_ERR(dest_ref); | 156 | return PTR_ERR(dest_ref); |
| 157 | if (key_ref_to_ptr(dest_ref)->type != &key_type_keyring) { | 157 | if (key_ref_to_ptr(dest_ref)->type != &key_type_keyring) { |
diff --git a/security/keys/proc.c b/security/keys/proc.c index 88e9a466940f..d3f6f2fd21db 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
| @@ -218,7 +218,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
| 218 | * - the caller holds a spinlock, and thus the RCU read lock, making our | 218 | * - the caller holds a spinlock, and thus the RCU read lock, making our |
| 219 | * access to __current_cred() safe | 219 | * access to __current_cred() safe |
| 220 | */ | 220 | */ |
| 221 | rc = key_task_permission(key_ref, ctx.cred, KEY_VIEW); | 221 | rc = key_task_permission(key_ref, ctx.cred, KEY_NEED_VIEW); |
| 222 | if (rc < 0) | 222 | if (rc < 0) |
| 223 | return 0; | 223 | return 0; |
| 224 | 224 | ||
diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c index 8c0af08760c8..b68faa1a5cfd 100644 --- a/security/keys/sysctl.c +++ b/security/keys/sysctl.c | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | 15 | ||
| 16 | static const int zero, one = 1, max = INT_MAX; | 16 | static const int zero, one = 1, max = INT_MAX; |
| 17 | 17 | ||
| 18 | ctl_table key_sysctls[] = { | 18 | struct ctl_table key_sysctls[] = { |
| 19 | { | 19 | { |
| 20 | .procname = "maxkeys", | 20 | .procname = "maxkeys", |
| 21 | .data = &key_quota_maxkeys, | 21 | .data = &key_quota_maxkeys, |
diff --git a/security/security.c b/security/security.c index 8b774f362a3d..31614e9e96e5 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -1425,7 +1425,7 @@ void security_key_free(struct key *key) | |||
| 1425 | } | 1425 | } |
| 1426 | 1426 | ||
| 1427 | int security_key_permission(key_ref_t key_ref, | 1427 | int security_key_permission(key_ref_t key_ref, |
| 1428 | const struct cred *cred, key_perm_t perm) | 1428 | const struct cred *cred, unsigned perm) |
| 1429 | { | 1429 | { |
| 1430 | return security_ops->key_permission(key_ref, cred, perm); | 1430 | return security_ops->key_permission(key_ref, cred, perm); |
| 1431 | } | 1431 | } |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 39bc8c94b969..b0e940497e23 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -5736,7 +5736,7 @@ static void selinux_key_free(struct key *k) | |||
| 5736 | 5736 | ||
| 5737 | static int selinux_key_permission(key_ref_t key_ref, | 5737 | static int selinux_key_permission(key_ref_t key_ref, |
| 5738 | const struct cred *cred, | 5738 | const struct cred *cred, |
| 5739 | key_perm_t perm) | 5739 | unsigned perm) |
| 5740 | { | 5740 | { |
| 5741 | struct key *key; | 5741 | struct key *key; |
| 5742 | struct key_security_struct *ksec; | 5742 | struct key_security_struct *ksec; |
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 } }, |
diff --git a/security/smack/smack.h b/security/smack/smack.h index d072fd32212d..020307ef0972 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
| @@ -80,8 +80,8 @@ struct superblock_smack { | |||
| 80 | 80 | ||
| 81 | struct socket_smack { | 81 | struct socket_smack { |
| 82 | struct smack_known *smk_out; /* outbound label */ | 82 | struct smack_known *smk_out; /* outbound label */ |
| 83 | char *smk_in; /* inbound label */ | 83 | struct smack_known *smk_in; /* inbound label */ |
| 84 | char *smk_packet; /* TCP peer label */ | 84 | struct smack_known *smk_packet; /* TCP peer label */ |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | /* | 87 | /* |
| @@ -133,7 +133,7 @@ struct smk_port_label { | |||
| 133 | struct list_head list; | 133 | struct list_head list; |
| 134 | struct sock *smk_sock; /* socket initialized on */ | 134 | struct sock *smk_sock; /* socket initialized on */ |
| 135 | unsigned short smk_port; /* the port number */ | 135 | unsigned short smk_port; /* the port number */ |
| 136 | char *smk_in; /* incoming label */ | 136 | struct smack_known *smk_in; /* inbound label */ |
| 137 | struct smack_known *smk_out; /* outgoing label */ | 137 | struct smack_known *smk_out; /* outgoing label */ |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| @@ -177,6 +177,14 @@ struct smk_port_label { | |||
| 177 | #define SMACK_CIPSO_MAXCATNUM 184 /* 23 * 8 */ | 177 | #define SMACK_CIPSO_MAXCATNUM 184 /* 23 * 8 */ |
| 178 | 178 | ||
| 179 | /* | 179 | /* |
| 180 | * Ptrace rules | ||
| 181 | */ | ||
| 182 | #define SMACK_PTRACE_DEFAULT 0 | ||
| 183 | #define SMACK_PTRACE_EXACT 1 | ||
| 184 | #define SMACK_PTRACE_DRACONIAN 2 | ||
| 185 | #define SMACK_PTRACE_MAX SMACK_PTRACE_DRACONIAN | ||
| 186 | |||
| 187 | /* | ||
| 180 | * Flags for untraditional access modes. | 188 | * Flags for untraditional access modes. |
| 181 | * It shouldn't be necessary to avoid conflicts with definitions | 189 | * It shouldn't be necessary to avoid conflicts with definitions |
| 182 | * in fs.h, but do so anyway. | 190 | * in fs.h, but do so anyway. |
| @@ -225,6 +233,7 @@ struct inode_smack *new_inode_smack(char *); | |||
| 225 | */ | 233 | */ |
| 226 | int smk_access_entry(char *, char *, struct list_head *); | 234 | int smk_access_entry(char *, char *, struct list_head *); |
| 227 | int smk_access(struct smack_known *, char *, int, struct smk_audit_info *); | 235 | int smk_access(struct smack_known *, char *, int, struct smk_audit_info *); |
| 236 | int smk_tskacc(struct task_smack *, char *, u32, struct smk_audit_info *); | ||
| 228 | int smk_curacc(char *, u32, struct smk_audit_info *); | 237 | int smk_curacc(char *, u32, struct smk_audit_info *); |
| 229 | struct smack_known *smack_from_secid(const u32); | 238 | struct smack_known *smack_from_secid(const u32); |
| 230 | char *smk_parse_smack(const char *string, int len); | 239 | char *smk_parse_smack(const char *string, int len); |
| @@ -244,6 +253,7 @@ extern struct smack_known *smack_net_ambient; | |||
| 244 | extern struct smack_known *smack_onlycap; | 253 | extern struct smack_known *smack_onlycap; |
| 245 | extern struct smack_known *smack_syslog_label; | 254 | extern struct smack_known *smack_syslog_label; |
| 246 | extern const char *smack_cipso_option; | 255 | extern const char *smack_cipso_option; |
| 256 | extern int smack_ptrace_rule; | ||
| 247 | 257 | ||
| 248 | extern struct smack_known smack_known_floor; | 258 | extern struct smack_known smack_known_floor; |
| 249 | extern struct smack_known smack_known_hat; | 259 | extern struct smack_known smack_known_hat; |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 732df7b91227..f97d0842e621 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
| @@ -192,20 +192,21 @@ out_audit: | |||
| 192 | } | 192 | } |
| 193 | 193 | ||
| 194 | /** | 194 | /** |
| 195 | * smk_curacc - determine if current has a specific access to an object | 195 | * smk_tskacc - determine if a task has a specific access to an object |
| 196 | * @tsp: a pointer to the subject task | ||
| 196 | * @obj_label: a pointer to the object's Smack label | 197 | * @obj_label: a pointer to the object's Smack label |
| 197 | * @mode: the access requested, in "MAY" format | 198 | * @mode: the access requested, in "MAY" format |
| 198 | * @a : common audit data | 199 | * @a : common audit data |
| 199 | * | 200 | * |
| 200 | * This function checks the current subject label/object label pair | 201 | * This function checks the subject task's label/object label pair |
| 201 | * in the access rule list and returns 0 if the access is permitted, | 202 | * in the access rule list and returns 0 if the access is permitted, |
| 202 | * non zero otherwise. It allows that current may have the capability | 203 | * non zero otherwise. It allows that the task may have the capability |
| 203 | * to override the rules. | 204 | * to override the rules. |
| 204 | */ | 205 | */ |
| 205 | int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) | 206 | int smk_tskacc(struct task_smack *subject, char *obj_label, |
| 207 | u32 mode, struct smk_audit_info *a) | ||
| 206 | { | 208 | { |
| 207 | struct task_smack *tsp = current_security(); | 209 | struct smack_known *skp = smk_of_task(subject); |
| 208 | struct smack_known *skp = smk_of_task(tsp); | ||
| 209 | int may; | 210 | int may; |
| 210 | int rc; | 211 | int rc; |
| 211 | 212 | ||
| @@ -219,7 +220,7 @@ int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) | |||
| 219 | * it can further restrict access. | 220 | * it can further restrict access. |
| 220 | */ | 221 | */ |
| 221 | may = smk_access_entry(skp->smk_known, obj_label, | 222 | may = smk_access_entry(skp->smk_known, obj_label, |
| 222 | &tsp->smk_rules); | 223 | &subject->smk_rules); |
| 223 | if (may < 0) | 224 | if (may < 0) |
| 224 | goto out_audit; | 225 | goto out_audit; |
| 225 | if ((mode & may) == mode) | 226 | if ((mode & may) == mode) |
| @@ -241,6 +242,24 @@ out_audit: | |||
| 241 | return rc; | 242 | return rc; |
| 242 | } | 243 | } |
| 243 | 244 | ||
| 245 | /** | ||
| 246 | * smk_curacc - determine if current has a specific access to an object | ||
| 247 | * @obj_label: a pointer to the object's Smack label | ||
| 248 | * @mode: the access requested, in "MAY" format | ||
| 249 | * @a : common audit data | ||
| 250 | * | ||
| 251 | * This function checks the current subject label/object label pair | ||
| 252 | * in the access rule list and returns 0 if the access is permitted, | ||
| 253 | * non zero otherwise. It allows that current may have the capability | ||
| 254 | * to override the rules. | ||
| 255 | */ | ||
| 256 | int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) | ||
| 257 | { | ||
| 258 | struct task_smack *tsp = current_security(); | ||
| 259 | |||
| 260 | return smk_tskacc(tsp, obj_label, mode, a); | ||
| 261 | } | ||
| 262 | |||
| 244 | #ifdef CONFIG_AUDIT | 263 | #ifdef CONFIG_AUDIT |
| 245 | /** | 264 | /** |
| 246 | * smack_str_from_perm : helper to transalate an int to a | 265 | * smack_str_from_perm : helper to transalate an int to a |
| @@ -285,7 +304,10 @@ static void smack_log_callback(struct audit_buffer *ab, void *a) | |||
| 285 | audit_log_untrustedstring(ab, sad->subject); | 304 | audit_log_untrustedstring(ab, sad->subject); |
| 286 | audit_log_format(ab, " object="); | 305 | audit_log_format(ab, " object="); |
| 287 | audit_log_untrustedstring(ab, sad->object); | 306 | audit_log_untrustedstring(ab, sad->object); |
| 288 | audit_log_format(ab, " requested=%s", sad->request); | 307 | if (sad->request[0] == '\0') |
| 308 | audit_log_format(ab, " labels_differ"); | ||
| 309 | else | ||
| 310 | audit_log_format(ab, " requested=%s", sad->request); | ||
| 289 | } | 311 | } |
| 290 | 312 | ||
| 291 | /** | 313 | /** |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c32bba566df9..e6ab307ce86e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -157,6 +157,74 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, | |||
| 157 | return rc; | 157 | return rc; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | /** | ||
| 161 | * smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_* | ||
| 162 | * @mode - input mode in form of PTRACE_MODE_* | ||
| 163 | * | ||
| 164 | * Returns a converted MAY_* mode usable by smack rules | ||
| 165 | */ | ||
| 166 | static inline unsigned int smk_ptrace_mode(unsigned int mode) | ||
| 167 | { | ||
| 168 | switch (mode) { | ||
| 169 | case PTRACE_MODE_READ: | ||
| 170 | return MAY_READ; | ||
| 171 | case PTRACE_MODE_ATTACH: | ||
| 172 | return MAY_READWRITE; | ||
| 173 | } | ||
| 174 | |||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | /** | ||
| 179 | * smk_ptrace_rule_check - helper for ptrace access | ||
| 180 | * @tracer: tracer process | ||
| 181 | * @tracee_label: label of the process that's about to be traced, | ||
| 182 | * the pointer must originate from smack structures | ||
| 183 | * @mode: ptrace attachment mode (PTRACE_MODE_*) | ||
| 184 | * @func: name of the function that called us, used for audit | ||
| 185 | * | ||
| 186 | * Returns 0 on access granted, -error on error | ||
| 187 | */ | ||
| 188 | static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label, | ||
| 189 | unsigned int mode, const char *func) | ||
| 190 | { | ||
| 191 | int rc; | ||
| 192 | struct smk_audit_info ad, *saip = NULL; | ||
| 193 | struct task_smack *tsp; | ||
| 194 | struct smack_known *skp; | ||
| 195 | |||
| 196 | if ((mode & PTRACE_MODE_NOAUDIT) == 0) { | ||
| 197 | smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK); | ||
| 198 | smk_ad_setfield_u_tsk(&ad, tracer); | ||
| 199 | saip = &ad; | ||
| 200 | } | ||
| 201 | |||
| 202 | tsp = task_security(tracer); | ||
| 203 | skp = smk_of_task(tsp); | ||
| 204 | |||
| 205 | if ((mode & PTRACE_MODE_ATTACH) && | ||
| 206 | (smack_ptrace_rule == SMACK_PTRACE_EXACT || | ||
| 207 | smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) { | ||
| 208 | if (skp->smk_known == tracee_label) | ||
| 209 | rc = 0; | ||
| 210 | else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN) | ||
| 211 | rc = -EACCES; | ||
| 212 | else if (capable(CAP_SYS_PTRACE)) | ||
| 213 | rc = 0; | ||
| 214 | else | ||
| 215 | rc = -EACCES; | ||
| 216 | |||
| 217 | if (saip) | ||
| 218 | smack_log(skp->smk_known, tracee_label, 0, rc, saip); | ||
| 219 | |||
| 220 | return rc; | ||
| 221 | } | ||
| 222 | |||
| 223 | /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */ | ||
| 224 | rc = smk_tskacc(tsp, tracee_label, smk_ptrace_mode(mode), saip); | ||
| 225 | return rc; | ||
| 226 | } | ||
| 227 | |||
| 160 | /* | 228 | /* |
| 161 | * LSM hooks. | 229 | * LSM hooks. |
| 162 | * We he, that is fun! | 230 | * We he, that is fun! |
| @@ -165,16 +233,15 @@ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, | |||
| 165 | /** | 233 | /** |
| 166 | * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH | 234 | * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH |
| 167 | * @ctp: child task pointer | 235 | * @ctp: child task pointer |
| 168 | * @mode: ptrace attachment mode | 236 | * @mode: ptrace attachment mode (PTRACE_MODE_*) |
| 169 | * | 237 | * |
| 170 | * Returns 0 if access is OK, an error code otherwise | 238 | * Returns 0 if access is OK, an error code otherwise |
| 171 | * | 239 | * |
| 172 | * Do the capability checks, and require read and write. | 240 | * Do the capability checks. |
| 173 | */ | 241 | */ |
| 174 | static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) | 242 | static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) |
| 175 | { | 243 | { |
| 176 | int rc; | 244 | int rc; |
| 177 | struct smk_audit_info ad; | ||
| 178 | struct smack_known *skp; | 245 | struct smack_known *skp; |
| 179 | 246 | ||
| 180 | rc = cap_ptrace_access_check(ctp, mode); | 247 | rc = cap_ptrace_access_check(ctp, mode); |
| @@ -182,10 +249,8 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) | |||
| 182 | return rc; | 249 | return rc; |
| 183 | 250 | ||
| 184 | skp = smk_of_task(task_security(ctp)); | 251 | skp = smk_of_task(task_security(ctp)); |
| 185 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | ||
| 186 | smk_ad_setfield_u_tsk(&ad, ctp); | ||
| 187 | 252 | ||
| 188 | rc = smk_curacc(skp->smk_known, mode, &ad); | 253 | rc = smk_ptrace_rule_check(current, skp->smk_known, mode, __func__); |
| 189 | return rc; | 254 | return rc; |
| 190 | } | 255 | } |
| 191 | 256 | ||
| @@ -195,23 +260,21 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) | |||
| 195 | * | 260 | * |
| 196 | * Returns 0 if access is OK, an error code otherwise | 261 | * Returns 0 if access is OK, an error code otherwise |
| 197 | * | 262 | * |
| 198 | * Do the capability checks, and require read and write. | 263 | * Do the capability checks, and require PTRACE_MODE_ATTACH. |
| 199 | */ | 264 | */ |
| 200 | static int smack_ptrace_traceme(struct task_struct *ptp) | 265 | static int smack_ptrace_traceme(struct task_struct *ptp) |
| 201 | { | 266 | { |
| 202 | int rc; | 267 | int rc; |
| 203 | struct smk_audit_info ad; | ||
| 204 | struct smack_known *skp; | 268 | struct smack_known *skp; |
| 205 | 269 | ||
| 206 | rc = cap_ptrace_traceme(ptp); | 270 | rc = cap_ptrace_traceme(ptp); |
| 207 | if (rc != 0) | 271 | if (rc != 0) |
| 208 | return rc; | 272 | return rc; |
| 209 | 273 | ||
| 210 | skp = smk_of_task(task_security(ptp)); | 274 | skp = smk_of_task(current_security()); |
| 211 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); | ||
| 212 | smk_ad_setfield_u_tsk(&ad, ptp); | ||
| 213 | 275 | ||
| 214 | rc = smk_curacc(skp->smk_known, MAY_READWRITE, &ad); | 276 | rc = smk_ptrace_rule_check(ptp, skp->smk_known, |
| 277 | PTRACE_MODE_ATTACH, __func__); | ||
| 215 | return rc; | 278 | return rc; |
| 216 | } | 279 | } |
| 217 | 280 | ||
| @@ -413,9 +476,11 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
| 413 | * Initialize the root inode. | 476 | * Initialize the root inode. |
| 414 | */ | 477 | */ |
| 415 | isp = inode->i_security; | 478 | isp = inode->i_security; |
| 416 | if (inode->i_security == NULL) { | 479 | if (isp == NULL) { |
| 417 | inode->i_security = new_inode_smack(sp->smk_root); | 480 | isp = new_inode_smack(sp->smk_root); |
| 418 | isp = inode->i_security; | 481 | if (isp == NULL) |
| 482 | return -ENOMEM; | ||
| 483 | inode->i_security = isp; | ||
| 419 | } else | 484 | } else |
| 420 | isp->smk_inode = sp->smk_root; | 485 | isp->smk_inode = sp->smk_root; |
| 421 | 486 | ||
| @@ -453,7 +518,7 @@ static int smack_sb_statfs(struct dentry *dentry) | |||
| 453 | * smack_bprm_set_creds - set creds for exec | 518 | * smack_bprm_set_creds - set creds for exec |
| 454 | * @bprm: the exec information | 519 | * @bprm: the exec information |
| 455 | * | 520 | * |
| 456 | * Returns 0 if it gets a blob, -ENOMEM otherwise | 521 | * Returns 0 if it gets a blob, -EPERM if exec forbidden and -ENOMEM otherwise |
| 457 | */ | 522 | */ |
| 458 | static int smack_bprm_set_creds(struct linux_binprm *bprm) | 523 | static int smack_bprm_set_creds(struct linux_binprm *bprm) |
| 459 | { | 524 | { |
| @@ -473,7 +538,22 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) | |||
| 473 | if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) | 538 | if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) |
| 474 | return 0; | 539 | return 0; |
| 475 | 540 | ||
| 476 | if (bprm->unsafe) | 541 | if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { |
| 542 | struct task_struct *tracer; | ||
| 543 | rc = 0; | ||
| 544 | |||
| 545 | rcu_read_lock(); | ||
| 546 | tracer = ptrace_parent(current); | ||
| 547 | if (likely(tracer != NULL)) | ||
| 548 | rc = smk_ptrace_rule_check(tracer, | ||
| 549 | isp->smk_task->smk_known, | ||
| 550 | PTRACE_MODE_ATTACH, | ||
| 551 | __func__); | ||
| 552 | rcu_read_unlock(); | ||
| 553 | |||
| 554 | if (rc != 0) | ||
| 555 | return rc; | ||
| 556 | } else if (bprm->unsafe) | ||
| 477 | return -EPERM; | 557 | return -EPERM; |
| 478 | 558 | ||
| 479 | bsp->smk_task = isp->smk_task; | 559 | bsp->smk_task = isp->smk_task; |
| @@ -880,18 +960,20 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, | |||
| 880 | return; | 960 | return; |
| 881 | } | 961 | } |
| 882 | 962 | ||
| 883 | skp = smk_import_entry(value, size); | ||
| 884 | if (strcmp(name, XATTR_NAME_SMACK) == 0) { | 963 | if (strcmp(name, XATTR_NAME_SMACK) == 0) { |
| 964 | skp = smk_import_entry(value, size); | ||
| 885 | if (skp != NULL) | 965 | if (skp != NULL) |
| 886 | isp->smk_inode = skp->smk_known; | 966 | isp->smk_inode = skp->smk_known; |
| 887 | else | 967 | else |
| 888 | isp->smk_inode = smack_known_invalid.smk_known; | 968 | isp->smk_inode = smack_known_invalid.smk_known; |
| 889 | } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { | 969 | } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { |
| 970 | skp = smk_import_entry(value, size); | ||
| 890 | if (skp != NULL) | 971 | if (skp != NULL) |
| 891 | isp->smk_task = skp; | 972 | isp->smk_task = skp; |
| 892 | else | 973 | else |
| 893 | isp->smk_task = &smack_known_invalid; | 974 | isp->smk_task = &smack_known_invalid; |
| 894 | } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { | 975 | } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { |
| 976 | skp = smk_import_entry(value, size); | ||
| 895 | if (skp != NULL) | 977 | if (skp != NULL) |
| 896 | isp->smk_mmap = skp; | 978 | isp->smk_mmap = skp; |
| 897 | else | 979 | else |
| @@ -938,24 +1020,37 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name) | |||
| 938 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || | 1020 | strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || |
| 939 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || | 1021 | strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || |
| 940 | strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 || | 1022 | strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 || |
| 941 | strcmp(name, XATTR_NAME_SMACKMMAP)) { | 1023 | strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { |
| 942 | if (!smack_privileged(CAP_MAC_ADMIN)) | 1024 | if (!smack_privileged(CAP_MAC_ADMIN)) |
| 943 | rc = -EPERM; | 1025 | rc = -EPERM; |
| 944 | } else | 1026 | } else |
| 945 | rc = cap_inode_removexattr(dentry, name); | 1027 | rc = cap_inode_removexattr(dentry, name); |
| 946 | 1028 | ||
| 1029 | if (rc != 0) | ||
| 1030 | return rc; | ||
| 1031 | |||
| 947 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); | 1032 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); |
| 948 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); | 1033 | smk_ad_setfield_u_fs_path_dentry(&ad, dentry); |
| 949 | if (rc == 0) | ||
| 950 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); | ||
| 951 | 1034 | ||
| 952 | if (rc == 0) { | 1035 | rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); |
| 953 | isp = dentry->d_inode->i_security; | 1036 | if (rc != 0) |
| 1037 | return rc; | ||
| 1038 | |||
| 1039 | isp = dentry->d_inode->i_security; | ||
| 1040 | /* | ||
| 1041 | * Don't do anything special for these. | ||
| 1042 | * XATTR_NAME_SMACKIPIN | ||
| 1043 | * XATTR_NAME_SMACKIPOUT | ||
| 1044 | * XATTR_NAME_SMACKEXEC | ||
| 1045 | */ | ||
| 1046 | if (strcmp(name, XATTR_NAME_SMACK) == 0) | ||
| 954 | isp->smk_task = NULL; | 1047 | isp->smk_task = NULL; |
| 1048 | else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) | ||
| 955 | isp->smk_mmap = NULL; | 1049 | isp->smk_mmap = NULL; |
| 956 | } | 1050 | else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) |
| 1051 | isp->smk_flags &= ~SMK_INODE_TRANSMUTE; | ||
| 957 | 1052 | ||
| 958 | return rc; | 1053 | return 0; |
| 959 | } | 1054 | } |
| 960 | 1055 | ||
| 961 | /** | 1056 | /** |
| @@ -1000,7 +1095,7 @@ static int smack_inode_getsecurity(const struct inode *inode, | |||
| 1000 | ssp = sock->sk->sk_security; | 1095 | ssp = sock->sk->sk_security; |
| 1001 | 1096 | ||
| 1002 | if (strcmp(name, XATTR_SMACK_IPIN) == 0) | 1097 | if (strcmp(name, XATTR_SMACK_IPIN) == 0) |
| 1003 | isp = ssp->smk_in; | 1098 | isp = ssp->smk_in->smk_known; |
| 1004 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) | 1099 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) |
| 1005 | isp = ssp->smk_out->smk_known; | 1100 | isp = ssp->smk_out->smk_known; |
| 1006 | else | 1101 | else |
| @@ -1367,19 +1462,32 @@ static int smack_file_receive(struct file *file) | |||
| 1367 | /** | 1462 | /** |
| 1368 | * smack_file_open - Smack dentry open processing | 1463 | * smack_file_open - Smack dentry open processing |
| 1369 | * @file: the object | 1464 | * @file: the object |
| 1370 | * @cred: unused | 1465 | * @cred: task credential |
| 1371 | * | 1466 | * |
| 1372 | * Set the security blob in the file structure. | 1467 | * Set the security blob in the file structure. |
| 1468 | * Allow the open only if the task has read access. There are | ||
| 1469 | * many read operations (e.g. fstat) that you can do with an | ||
| 1470 | * fd even if you have the file open write-only. | ||
| 1373 | * | 1471 | * |
| 1374 | * Returns 0 | 1472 | * Returns 0 |
| 1375 | */ | 1473 | */ |
| 1376 | static int smack_file_open(struct file *file, const struct cred *cred) | 1474 | static int smack_file_open(struct file *file, const struct cred *cred) |
| 1377 | { | 1475 | { |
| 1476 | struct task_smack *tsp = cred->security; | ||
| 1378 | struct inode_smack *isp = file_inode(file)->i_security; | 1477 | struct inode_smack *isp = file_inode(file)->i_security; |
| 1478 | struct smk_audit_info ad; | ||
| 1479 | int rc; | ||
| 1379 | 1480 | ||
| 1380 | file->f_security = isp->smk_inode; | 1481 | if (smack_privileged(CAP_MAC_OVERRIDE)) |
| 1482 | return 0; | ||
| 1381 | 1483 | ||
| 1382 | return 0; | 1484 | smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); |
| 1485 | smk_ad_setfield_u_fs_path(&ad, file->f_path); | ||
| 1486 | rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad); | ||
| 1487 | if (rc == 0) | ||
| 1488 | file->f_security = isp->smk_inode; | ||
| 1489 | |||
| 1490 | return rc; | ||
| 1383 | } | 1491 | } |
| 1384 | 1492 | ||
| 1385 | /* | 1493 | /* |
| @@ -1764,7 +1872,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) | |||
| 1764 | if (ssp == NULL) | 1872 | if (ssp == NULL) |
| 1765 | return -ENOMEM; | 1873 | return -ENOMEM; |
| 1766 | 1874 | ||
| 1767 | ssp->smk_in = skp->smk_known; | 1875 | ssp->smk_in = skp; |
| 1768 | ssp->smk_out = skp; | 1876 | ssp->smk_out = skp; |
| 1769 | ssp->smk_packet = NULL; | 1877 | ssp->smk_packet = NULL; |
| 1770 | 1878 | ||
| @@ -2004,7 +2112,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, | |||
| 2004 | 2112 | ||
| 2005 | if (act == SMK_RECEIVING) { | 2113 | if (act == SMK_RECEIVING) { |
| 2006 | skp = smack_net_ambient; | 2114 | skp = smack_net_ambient; |
| 2007 | object = ssp->smk_in; | 2115 | object = ssp->smk_in->smk_known; |
| 2008 | } else { | 2116 | } else { |
| 2009 | skp = ssp->smk_out; | 2117 | skp = ssp->smk_out; |
| 2010 | object = smack_net_ambient->smk_known; | 2118 | object = smack_net_ambient->smk_known; |
| @@ -2034,9 +2142,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, | |||
| 2034 | list_for_each_entry(spp, &smk_ipv6_port_list, list) { | 2142 | list_for_each_entry(spp, &smk_ipv6_port_list, list) { |
| 2035 | if (spp->smk_port != port) | 2143 | if (spp->smk_port != port) |
| 2036 | continue; | 2144 | continue; |
| 2037 | object = spp->smk_in; | 2145 | object = spp->smk_in->smk_known; |
| 2038 | if (act == SMK_CONNECTING) | 2146 | if (act == SMK_CONNECTING) |
| 2039 | ssp->smk_packet = spp->smk_out->smk_known; | 2147 | ssp->smk_packet = spp->smk_out; |
| 2040 | break; | 2148 | break; |
| 2041 | } | 2149 | } |
| 2042 | 2150 | ||
| @@ -2076,7 +2184,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
| 2076 | int rc = 0; | 2184 | int rc = 0; |
| 2077 | 2185 | ||
| 2078 | if (value == NULL || size > SMK_LONGLABEL || size == 0) | 2186 | if (value == NULL || size > SMK_LONGLABEL || size == 0) |
| 2079 | return -EACCES; | 2187 | return -EINVAL; |
| 2080 | 2188 | ||
| 2081 | skp = smk_import_entry(value, size); | 2189 | skp = smk_import_entry(value, size); |
| 2082 | if (skp == NULL) | 2190 | if (skp == NULL) |
| @@ -2100,7 +2208,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
| 2100 | ssp = sock->sk->sk_security; | 2208 | ssp = sock->sk->sk_security; |
| 2101 | 2209 | ||
| 2102 | if (strcmp(name, XATTR_SMACK_IPIN) == 0) | 2210 | if (strcmp(name, XATTR_SMACK_IPIN) == 0) |
| 2103 | ssp->smk_in = skp->smk_known; | 2211 | ssp->smk_in = skp; |
| 2104 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { | 2212 | else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { |
| 2105 | ssp->smk_out = skp; | 2213 | ssp->smk_out = skp; |
| 2106 | if (sock->sk->sk_family == PF_INET) { | 2214 | if (sock->sk->sk_family == PF_INET) { |
| @@ -2713,6 +2821,15 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
| 2713 | * of the superblock. | 2821 | * of the superblock. |
| 2714 | */ | 2822 | */ |
| 2715 | if (opt_dentry->d_parent == opt_dentry) { | 2823 | if (opt_dentry->d_parent == opt_dentry) { |
| 2824 | if (sbp->s_magic == CGROUP_SUPER_MAGIC) { | ||
| 2825 | /* | ||
| 2826 | * The cgroup filesystem is never mounted, | ||
| 2827 | * so there's no opportunity to set the mount | ||
| 2828 | * options. | ||
| 2829 | */ | ||
| 2830 | sbsp->smk_root = smack_known_star.smk_known; | ||
| 2831 | sbsp->smk_default = smack_known_star.smk_known; | ||
| 2832 | } | ||
| 2716 | isp->smk_inode = sbsp->smk_root; | 2833 | isp->smk_inode = sbsp->smk_root; |
| 2717 | isp->smk_flags |= SMK_INODE_INSTANT; | 2834 | isp->smk_flags |= SMK_INODE_INSTANT; |
| 2718 | goto unlockandout; | 2835 | goto unlockandout; |
| @@ -2726,16 +2843,20 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
| 2726 | */ | 2843 | */ |
| 2727 | switch (sbp->s_magic) { | 2844 | switch (sbp->s_magic) { |
| 2728 | case SMACK_MAGIC: | 2845 | case SMACK_MAGIC: |
| 2846 | case PIPEFS_MAGIC: | ||
| 2847 | case SOCKFS_MAGIC: | ||
| 2848 | case CGROUP_SUPER_MAGIC: | ||
| 2729 | /* | 2849 | /* |
| 2730 | * Casey says that it's a little embarrassing | 2850 | * Casey says that it's a little embarrassing |
| 2731 | * that the smack file system doesn't do | 2851 | * that the smack file system doesn't do |
| 2732 | * extended attributes. | 2852 | * extended attributes. |
| 2733 | */ | 2853 | * |
| 2734 | final = smack_known_star.smk_known; | ||
| 2735 | break; | ||
| 2736 | case PIPEFS_MAGIC: | ||
| 2737 | /* | ||
| 2738 | * Casey says pipes are easy (?) | 2854 | * Casey says pipes are easy (?) |
| 2855 | * | ||
| 2856 | * Socket access is controlled by the socket | ||
| 2857 | * structures associated with the task involved. | ||
| 2858 | * | ||
| 2859 | * Cgroupfs is special | ||
| 2739 | */ | 2860 | */ |
| 2740 | final = smack_known_star.smk_known; | 2861 | final = smack_known_star.smk_known; |
| 2741 | break; | 2862 | break; |
| @@ -2747,13 +2868,6 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
| 2747 | */ | 2868 | */ |
| 2748 | final = ckp->smk_known; | 2869 | final = ckp->smk_known; |
| 2749 | break; | 2870 | break; |
| 2750 | case SOCKFS_MAGIC: | ||
| 2751 | /* | ||
| 2752 | * Socket access is controlled by the socket | ||
| 2753 | * structures associated with the task involved. | ||
| 2754 | */ | ||
| 2755 | final = smack_known_star.smk_known; | ||
| 2756 | break; | ||
| 2757 | case PROC_SUPER_MAGIC: | 2871 | case PROC_SUPER_MAGIC: |
| 2758 | /* | 2872 | /* |
| 2759 | * Casey says procfs appears not to care. | 2873 | * Casey says procfs appears not to care. |
| @@ -2959,30 +3073,34 @@ static int smack_unix_stream_connect(struct sock *sock, | |||
| 2959 | struct sock *other, struct sock *newsk) | 3073 | struct sock *other, struct sock *newsk) |
| 2960 | { | 3074 | { |
| 2961 | struct smack_known *skp; | 3075 | struct smack_known *skp; |
| 3076 | struct smack_known *okp; | ||
| 2962 | struct socket_smack *ssp = sock->sk_security; | 3077 | struct socket_smack *ssp = sock->sk_security; |
| 2963 | struct socket_smack *osp = other->sk_security; | 3078 | struct socket_smack *osp = other->sk_security; |
| 2964 | struct socket_smack *nsp = newsk->sk_security; | 3079 | struct socket_smack *nsp = newsk->sk_security; |
| 2965 | struct smk_audit_info ad; | 3080 | struct smk_audit_info ad; |
| 2966 | int rc = 0; | 3081 | int rc = 0; |
| 2967 | |||
| 2968 | #ifdef CONFIG_AUDIT | 3082 | #ifdef CONFIG_AUDIT |
| 2969 | struct lsm_network_audit net; | 3083 | struct lsm_network_audit net; |
| 2970 | |||
| 2971 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | ||
| 2972 | smk_ad_setfield_u_net_sk(&ad, other); | ||
| 2973 | #endif | 3084 | #endif |
| 2974 | 3085 | ||
| 2975 | if (!smack_privileged(CAP_MAC_OVERRIDE)) { | 3086 | if (!smack_privileged(CAP_MAC_OVERRIDE)) { |
| 2976 | skp = ssp->smk_out; | 3087 | skp = ssp->smk_out; |
| 2977 | rc = smk_access(skp, osp->smk_in, MAY_WRITE, &ad); | 3088 | okp = osp->smk_out; |
| 3089 | #ifdef CONFIG_AUDIT | ||
| 3090 | smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); | ||
| 3091 | smk_ad_setfield_u_net_sk(&ad, other); | ||
| 3092 | #endif | ||
| 3093 | rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad); | ||
| 3094 | if (rc == 0) | ||
| 3095 | rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL); | ||
| 2978 | } | 3096 | } |
| 2979 | 3097 | ||
| 2980 | /* | 3098 | /* |
| 2981 | * Cross reference the peer labels for SO_PEERSEC. | 3099 | * Cross reference the peer labels for SO_PEERSEC. |
| 2982 | */ | 3100 | */ |
| 2983 | if (rc == 0) { | 3101 | if (rc == 0) { |
| 2984 | nsp->smk_packet = ssp->smk_out->smk_known; | 3102 | nsp->smk_packet = ssp->smk_out; |
| 2985 | ssp->smk_packet = osp->smk_out->smk_known; | 3103 | ssp->smk_packet = osp->smk_out; |
| 2986 | } | 3104 | } |
| 2987 | 3105 | ||
| 2988 | return rc; | 3106 | return rc; |
| @@ -3014,7 +3132,7 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other) | |||
| 3014 | return 0; | 3132 | return 0; |
| 3015 | 3133 | ||
| 3016 | skp = ssp->smk_out; | 3134 | skp = ssp->smk_out; |
| 3017 | return smk_access(skp, osp->smk_in, MAY_WRITE, &ad); | 3135 | return smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad); |
| 3018 | } | 3136 | } |
| 3019 | 3137 | ||
| 3020 | /** | 3138 | /** |
| @@ -3109,7 +3227,7 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, | |||
| 3109 | if (found) | 3227 | if (found) |
| 3110 | return skp; | 3228 | return skp; |
| 3111 | 3229 | ||
| 3112 | if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) | 3230 | if (ssp != NULL && ssp->smk_in == &smack_known_star) |
| 3113 | return &smack_known_web; | 3231 | return &smack_known_web; |
| 3114 | return &smack_known_star; | 3232 | return &smack_known_star; |
| 3115 | } | 3233 | } |
| @@ -3228,7 +3346,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 3228 | * This is the simplist possible security model | 3346 | * This is the simplist possible security model |
| 3229 | * for networking. | 3347 | * for networking. |
| 3230 | */ | 3348 | */ |
| 3231 | rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); | 3349 | rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad); |
| 3232 | if (rc != 0) | 3350 | if (rc != 0) |
| 3233 | netlbl_skbuff_err(skb, rc, 0); | 3351 | netlbl_skbuff_err(skb, rc, 0); |
| 3234 | break; | 3352 | break; |
| @@ -3263,7 +3381,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock, | |||
| 3263 | 3381 | ||
| 3264 | ssp = sock->sk->sk_security; | 3382 | ssp = sock->sk->sk_security; |
| 3265 | if (ssp->smk_packet != NULL) { | 3383 | if (ssp->smk_packet != NULL) { |
| 3266 | rcp = ssp->smk_packet; | 3384 | rcp = ssp->smk_packet->smk_known; |
| 3267 | slen = strlen(rcp) + 1; | 3385 | slen = strlen(rcp) + 1; |
| 3268 | } | 3386 | } |
| 3269 | 3387 | ||
| @@ -3348,7 +3466,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent) | |||
| 3348 | return; | 3466 | return; |
| 3349 | 3467 | ||
| 3350 | ssp = sk->sk_security; | 3468 | ssp = sk->sk_security; |
| 3351 | ssp->smk_in = skp->smk_known; | 3469 | ssp->smk_in = skp; |
| 3352 | ssp->smk_out = skp; | 3470 | ssp->smk_out = skp; |
| 3353 | /* cssp->smk_packet is already set in smack_inet_csk_clone() */ | 3471 | /* cssp->smk_packet is already set in smack_inet_csk_clone() */ |
| 3354 | } | 3472 | } |
| @@ -3408,7 +3526,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 3408 | * Receiving a packet requires that the other end be able to write | 3526 | * Receiving a packet requires that the other end be able to write |
| 3409 | * here. Read access is not required. | 3527 | * here. Read access is not required. |
| 3410 | */ | 3528 | */ |
| 3411 | rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); | 3529 | rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad); |
| 3412 | if (rc != 0) | 3530 | if (rc != 0) |
| 3413 | return rc; | 3531 | return rc; |
| 3414 | 3532 | ||
| @@ -3452,7 +3570,7 @@ static void smack_inet_csk_clone(struct sock *sk, | |||
| 3452 | 3570 | ||
| 3453 | if (req->peer_secid != 0) { | 3571 | if (req->peer_secid != 0) { |
| 3454 | skp = smack_from_secid(req->peer_secid); | 3572 | skp = smack_from_secid(req->peer_secid); |
| 3455 | ssp->smk_packet = skp->smk_known; | 3573 | ssp->smk_packet = skp; |
| 3456 | } else | 3574 | } else |
| 3457 | ssp->smk_packet = NULL; | 3575 | ssp->smk_packet = NULL; |
| 3458 | } | 3576 | } |
| @@ -3506,11 +3624,12 @@ static void smack_key_free(struct key *key) | |||
| 3506 | * an error code otherwise | 3624 | * an error code otherwise |
| 3507 | */ | 3625 | */ |
| 3508 | static int smack_key_permission(key_ref_t key_ref, | 3626 | static int smack_key_permission(key_ref_t key_ref, |
| 3509 | const struct cred *cred, key_perm_t perm) | 3627 | const struct cred *cred, unsigned perm) |
| 3510 | { | 3628 | { |
| 3511 | struct key *keyp; | 3629 | struct key *keyp; |
| 3512 | struct smk_audit_info ad; | 3630 | struct smk_audit_info ad; |
| 3513 | struct smack_known *tkp = smk_of_task(cred->security); | 3631 | struct smack_known *tkp = smk_of_task(cred->security); |
| 3632 | int request = 0; | ||
| 3514 | 3633 | ||
| 3515 | keyp = key_ref_to_ptr(key_ref); | 3634 | keyp = key_ref_to_ptr(key_ref); |
| 3516 | if (keyp == NULL) | 3635 | if (keyp == NULL) |
| @@ -3531,7 +3650,11 @@ static int smack_key_permission(key_ref_t key_ref, | |||
| 3531 | ad.a.u.key_struct.key = keyp->serial; | 3650 | ad.a.u.key_struct.key = keyp->serial; |
| 3532 | ad.a.u.key_struct.key_desc = keyp->description; | 3651 | ad.a.u.key_struct.key_desc = keyp->description; |
| 3533 | #endif | 3652 | #endif |
| 3534 | return smk_access(tkp, keyp->security, MAY_READWRITE, &ad); | 3653 | if (perm & KEY_NEED_READ) |
| 3654 | request = MAY_READ; | ||
| 3655 | if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR)) | ||
| 3656 | request = MAY_WRITE; | ||
| 3657 | return smk_access(tkp, keyp->security, request, &ad); | ||
| 3535 | } | 3658 | } |
| 3536 | #endif /* CONFIG_KEYS */ | 3659 | #endif /* CONFIG_KEYS */ |
| 3537 | 3660 | ||
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 893b06b93f6d..3c720ff10591 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
| @@ -53,6 +53,7 @@ enum smk_inos { | |||
| 53 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ | 53 | SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */ |
| 54 | SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ | 54 | SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */ |
| 55 | SMK_SYSLOG = 20, /* change syslog label) */ | 55 | SMK_SYSLOG = 20, /* change syslog label) */ |
| 56 | SMK_PTRACE = 21, /* set ptrace rule */ | ||
| 56 | }; | 57 | }; |
| 57 | 58 | ||
| 58 | /* | 59 | /* |
| @@ -101,6 +102,15 @@ struct smack_known *smack_onlycap; | |||
| 101 | struct smack_known *smack_syslog_label; | 102 | struct smack_known *smack_syslog_label; |
| 102 | 103 | ||
| 103 | /* | 104 | /* |
| 105 | * Ptrace current rule | ||
| 106 | * SMACK_PTRACE_DEFAULT regular smack ptrace rules (/proc based) | ||
| 107 | * SMACK_PTRACE_EXACT labels must match, but can be overriden with | ||
| 108 | * CAP_SYS_PTRACE | ||
| 109 | * SMACK_PTRACE_DRACONIAN lables must match, CAP_SYS_PTRACE has no effect | ||
| 110 | */ | ||
| 111 | int smack_ptrace_rule = SMACK_PTRACE_DEFAULT; | ||
| 112 | |||
| 113 | /* | ||
| 104 | * Certain IP addresses may be designated as single label hosts. | 114 | * Certain IP addresses may be designated as single label hosts. |
| 105 | * Packets are sent there unlabeled, but only from tasks that | 115 | * Packets are sent there unlabeled, but only from tasks that |
| 106 | * can write to the specified label. | 116 | * can write to the specified label. |
| @@ -1183,7 +1193,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
| 1183 | 1193 | ||
| 1184 | data[count] = '\0'; | 1194 | data[count] = '\0'; |
| 1185 | 1195 | ||
| 1186 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%d %s", | 1196 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%u %s", |
| 1187 | &host[0], &host[1], &host[2], &host[3], &m, smack); | 1197 | &host[0], &host[1], &host[2], &host[3], &m, smack); |
| 1188 | if (rc != 6) { | 1198 | if (rc != 6) { |
| 1189 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", | 1199 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", |
| @@ -2244,6 +2254,68 @@ static const struct file_operations smk_syslog_ops = { | |||
| 2244 | 2254 | ||
| 2245 | 2255 | ||
| 2246 | /** | 2256 | /** |
| 2257 | * smk_read_ptrace - read() for /smack/ptrace | ||
| 2258 | * @filp: file pointer, not actually used | ||
| 2259 | * @buf: where to put the result | ||
| 2260 | * @count: maximum to send along | ||
| 2261 | * @ppos: where to start | ||
| 2262 | * | ||
| 2263 | * Returns number of bytes read or error code, as appropriate | ||
| 2264 | */ | ||
| 2265 | static ssize_t smk_read_ptrace(struct file *filp, char __user *buf, | ||
| 2266 | size_t count, loff_t *ppos) | ||
| 2267 | { | ||
| 2268 | char temp[32]; | ||
| 2269 | ssize_t rc; | ||
| 2270 | |||
| 2271 | if (*ppos != 0) | ||
| 2272 | return 0; | ||
| 2273 | |||
| 2274 | sprintf(temp, "%d\n", smack_ptrace_rule); | ||
| 2275 | rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); | ||
| 2276 | return rc; | ||
| 2277 | } | ||
| 2278 | |||
| 2279 | /** | ||
| 2280 | * smk_write_ptrace - write() for /smack/ptrace | ||
| 2281 | * @file: file pointer | ||
| 2282 | * @buf: data from user space | ||
| 2283 | * @count: bytes sent | ||
| 2284 | * @ppos: where to start - must be 0 | ||
| 2285 | */ | ||
| 2286 | static ssize_t smk_write_ptrace(struct file *file, const char __user *buf, | ||
| 2287 | size_t count, loff_t *ppos) | ||
| 2288 | { | ||
| 2289 | char temp[32]; | ||
| 2290 | int i; | ||
| 2291 | |||
| 2292 | if (!smack_privileged(CAP_MAC_ADMIN)) | ||
| 2293 | return -EPERM; | ||
| 2294 | |||
| 2295 | if (*ppos != 0 || count >= sizeof(temp) || count == 0) | ||
| 2296 | return -EINVAL; | ||
| 2297 | |||
| 2298 | if (copy_from_user(temp, buf, count) != 0) | ||
| 2299 | return -EFAULT; | ||
| 2300 | |||
| 2301 | temp[count] = '\0'; | ||
| 2302 | |||
| 2303 | if (sscanf(temp, "%d", &i) != 1) | ||
| 2304 | return -EINVAL; | ||
| 2305 | if (i < SMACK_PTRACE_DEFAULT || i > SMACK_PTRACE_MAX) | ||
| 2306 | return -EINVAL; | ||
| 2307 | smack_ptrace_rule = i; | ||
| 2308 | |||
| 2309 | return count; | ||
| 2310 | } | ||
| 2311 | |||
| 2312 | static const struct file_operations smk_ptrace_ops = { | ||
| 2313 | .write = smk_write_ptrace, | ||
| 2314 | .read = smk_read_ptrace, | ||
| 2315 | .llseek = default_llseek, | ||
| 2316 | }; | ||
| 2317 | |||
| 2318 | /** | ||
| 2247 | * smk_fill_super - fill the smackfs superblock | 2319 | * smk_fill_super - fill the smackfs superblock |
| 2248 | * @sb: the empty superblock | 2320 | * @sb: the empty superblock |
| 2249 | * @data: unused | 2321 | * @data: unused |
| @@ -2296,6 +2368,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
| 2296 | "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, | 2368 | "change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR}, |
| 2297 | [SMK_SYSLOG] = { | 2369 | [SMK_SYSLOG] = { |
| 2298 | "syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR}, | 2370 | "syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR}, |
| 2371 | [SMK_PTRACE] = { | ||
| 2372 | "ptrace", &smk_ptrace_ops, S_IRUGO|S_IWUSR}, | ||
| 2299 | /* last one */ | 2373 | /* last one */ |
| 2300 | {""} | 2374 | {""} |
| 2301 | }; | 2375 | }; |
