diff options
| author | Stephen Smalley <sds@tycho.nsa.gov> | 2010-01-14 17:28:10 -0500 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2010-01-17 17:54:26 -0500 |
| commit | 19439d05b88dafc4e55d9ffce84ccc27cf8b2bcc (patch) | |
| tree | e529e1bbba49f30684c3b88a67df1d62ba3e11b1 /security | |
| parent | 8d9525048c74786205b99f3fcd05a839721edfb7 (diff) | |
selinux: change the handling of unknown classes
If allow_unknown==deny, SELinux treats an undefined kernel security
class as an error condition rather than as a typical permission denial
and thus does not allow permissions on undefined classes even when in
permissive mode. Change the SELinux logic so that this case is handled
as a typical permission denial, subject to the usual permissive mode and
permissive domain handling.
Also drop the 'requested' argument from security_compute_av() and
helpers as it is a legacy of the original security server interface and
is unused.
Changes:
- Handle permissive domains consistently by moving up the test for a
permissive domain.
- Make security_compute_av_user() consistent with security_compute_av();
the only difference now is that security_compute_av() performs mapping
between the kernel-private class and permission indices and the policy
values. In the userspace case, this mapping is handled by libselinux.
- Moved avd_init inside the policy lock.
Based in part on a patch by Paul Moore <paul.moore@hp.com>.
Reported-by: Andrew Worsley <amworsley@gmail.com>
Signed-off-by: Stephen D. Smalley <sds@tycho.nsa.gov>
Reviewed-by: Paul Moore <paul.moore@hp.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security')
| -rw-r--r-- | security/selinux/avc.c | 5 | ||||
| -rw-r--r-- | security/selinux/include/security.h | 10 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 7 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 186 |
4 files changed, 88 insertions, 120 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index f2dde268165a..3ee9b6a8beb6 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
| @@ -746,9 +746,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
| 746 | else | 746 | else |
| 747 | avd = &avd_entry; | 747 | avd = &avd_entry; |
| 748 | 748 | ||
| 749 | rc = security_compute_av(ssid, tsid, tclass, requested, avd); | 749 | security_compute_av(ssid, tsid, tclass, avd); |
| 750 | if (rc) | ||
| 751 | goto out; | ||
| 752 | rcu_read_lock(); | 750 | rcu_read_lock(); |
| 753 | node = avc_insert(ssid, tsid, tclass, avd); | 751 | node = avc_insert(ssid, tsid, tclass, avd); |
| 754 | } else { | 752 | } else { |
| @@ -770,7 +768,6 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
| 770 | } | 768 | } |
| 771 | 769 | ||
| 772 | rcu_read_unlock(); | 770 | rcu_read_unlock(); |
| 773 | out: | ||
| 774 | return rc; | 771 | return rc; |
| 775 | } | 772 | } |
| 776 | 773 | ||
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 2553266ad793..022cf067aa3f 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
| @@ -96,13 +96,11 @@ struct av_decision { | |||
| 96 | /* definitions of av_decision.flags */ | 96 | /* definitions of av_decision.flags */ |
| 97 | #define AVD_FLAGS_PERMISSIVE 0x0001 | 97 | #define AVD_FLAGS_PERMISSIVE 0x0001 |
| 98 | 98 | ||
| 99 | int security_compute_av(u32 ssid, u32 tsid, | 99 | void security_compute_av(u32 ssid, u32 tsid, |
| 100 | u16 tclass, u32 requested, | 100 | u16 tclass, struct av_decision *avd); |
| 101 | struct av_decision *avd); | ||
| 102 | 101 | ||
| 103 | int security_compute_av_user(u32 ssid, u32 tsid, | 102 | void security_compute_av_user(u32 ssid, u32 tsid, |
| 104 | u16 tclass, u32 requested, | 103 | u16 tclass, struct av_decision *avd); |
| 105 | struct av_decision *avd); | ||
| 106 | 104 | ||
| 107 | int security_transition_sid(u32 ssid, u32 tsid, | 105 | int security_transition_sid(u32 ssid, u32 tsid, |
| 108 | u16 tclass, u32 *out_sid); | 106 | u16 tclass, u32 *out_sid); |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index fab36fdf2769..b7bb0f5ec07c 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -494,7 +494,6 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
| 494 | char *scon, *tcon; | 494 | char *scon, *tcon; |
| 495 | u32 ssid, tsid; | 495 | u32 ssid, tsid; |
| 496 | u16 tclass; | 496 | u16 tclass; |
| 497 | u32 req; | ||
| 498 | struct av_decision avd; | 497 | struct av_decision avd; |
| 499 | ssize_t length; | 498 | ssize_t length; |
| 500 | 499 | ||
| @@ -512,7 +511,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
| 512 | goto out; | 511 | goto out; |
| 513 | 512 | ||
| 514 | length = -EINVAL; | 513 | length = -EINVAL; |
| 515 | if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4) | 514 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
| 516 | goto out2; | 515 | goto out2; |
| 517 | 516 | ||
| 518 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); | 517 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); |
| @@ -522,9 +521,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
| 522 | if (length < 0) | 521 | if (length < 0) |
| 523 | goto out2; | 522 | goto out2; |
| 524 | 523 | ||
| 525 | length = security_compute_av_user(ssid, tsid, tclass, req, &avd); | 524 | security_compute_av_user(ssid, tsid, tclass, &avd); |
| 526 | if (length < 0) | ||
| 527 | goto out2; | ||
| 528 | 525 | ||
| 529 | length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, | 526 | length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, |
| 530 | "%x %x %x %x %u %x", | 527 | "%x %x %x %x %u %x", |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 07ddc81d7b57..9ec24169ccd7 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -87,11 +87,10 @@ static u32 latest_granting; | |||
| 87 | static int context_struct_to_string(struct context *context, char **scontext, | 87 | static int context_struct_to_string(struct context *context, char **scontext, |
| 88 | u32 *scontext_len); | 88 | u32 *scontext_len); |
| 89 | 89 | ||
| 90 | static int context_struct_compute_av(struct context *scontext, | 90 | static void context_struct_compute_av(struct context *scontext, |
| 91 | struct context *tcontext, | 91 | struct context *tcontext, |
| 92 | u16 tclass, | 92 | u16 tclass, |
| 93 | u32 requested, | 93 | struct av_decision *avd); |
| 94 | struct av_decision *avd); | ||
| 95 | 94 | ||
| 96 | struct selinux_mapping { | 95 | struct selinux_mapping { |
| 97 | u16 value; /* policy value */ | 96 | u16 value; /* policy value */ |
| @@ -196,23 +195,6 @@ static u16 unmap_class(u16 tclass) | |||
| 196 | return tclass; | 195 | return tclass; |
| 197 | } | 196 | } |
| 198 | 197 | ||
| 199 | static u32 unmap_perm(u16 tclass, u32 tperm) | ||
| 200 | { | ||
| 201 | if (tclass < current_mapping_size) { | ||
| 202 | unsigned i; | ||
| 203 | u32 kperm = 0; | ||
| 204 | |||
| 205 | for (i = 0; i < current_mapping[tclass].num_perms; i++) | ||
| 206 | if (tperm & (1<<i)) { | ||
| 207 | kperm |= current_mapping[tclass].perms[i]; | ||
| 208 | tperm &= ~(1<<i); | ||
| 209 | } | ||
| 210 | return kperm; | ||
| 211 | } | ||
| 212 | |||
| 213 | return tperm; | ||
| 214 | } | ||
| 215 | |||
| 216 | static void map_decision(u16 tclass, struct av_decision *avd, | 198 | static void map_decision(u16 tclass, struct av_decision *avd, |
| 217 | int allow_unknown) | 199 | int allow_unknown) |
| 218 | { | 200 | { |
| @@ -532,7 +514,6 @@ out: | |||
| 532 | static void type_attribute_bounds_av(struct context *scontext, | 514 | static void type_attribute_bounds_av(struct context *scontext, |
| 533 | struct context *tcontext, | 515 | struct context *tcontext, |
| 534 | u16 tclass, | 516 | u16 tclass, |
| 535 | u32 requested, | ||
| 536 | struct av_decision *avd) | 517 | struct av_decision *avd) |
| 537 | { | 518 | { |
| 538 | struct context lo_scontext; | 519 | struct context lo_scontext; |
| @@ -553,7 +534,6 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 553 | context_struct_compute_av(&lo_scontext, | 534 | context_struct_compute_av(&lo_scontext, |
| 554 | tcontext, | 535 | tcontext, |
| 555 | tclass, | 536 | tclass, |
| 556 | requested, | ||
| 557 | &lo_avd); | 537 | &lo_avd); |
| 558 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 538 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
| 559 | return; /* no masked permission */ | 539 | return; /* no masked permission */ |
| @@ -569,7 +549,6 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 569 | context_struct_compute_av(scontext, | 549 | context_struct_compute_av(scontext, |
| 570 | &lo_tcontext, | 550 | &lo_tcontext, |
| 571 | tclass, | 551 | tclass, |
| 572 | requested, | ||
| 573 | &lo_avd); | 552 | &lo_avd); |
| 574 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 553 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
| 575 | return; /* no masked permission */ | 554 | return; /* no masked permission */ |
| @@ -586,7 +565,6 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 586 | context_struct_compute_av(&lo_scontext, | 565 | context_struct_compute_av(&lo_scontext, |
| 587 | &lo_tcontext, | 566 | &lo_tcontext, |
| 588 | tclass, | 567 | tclass, |
| 589 | requested, | ||
| 590 | &lo_avd); | 568 | &lo_avd); |
| 591 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 569 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
| 592 | return; /* no masked permission */ | 570 | return; /* no masked permission */ |
| @@ -607,11 +585,10 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 607 | * Compute access vectors based on a context structure pair for | 585 | * Compute access vectors based on a context structure pair for |
| 608 | * the permissions in a particular class. | 586 | * the permissions in a particular class. |
| 609 | */ | 587 | */ |
| 610 | static int context_struct_compute_av(struct context *scontext, | ||
