diff options
Diffstat (limited to 'security/selinux')
| -rw-r--r-- | security/selinux/avc.c | 22 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 41 | ||||
| -rw-r--r-- | security/selinux/include/security.h | 13 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 12 | ||||
| -rw-r--r-- | security/selinux/ss/context.h | 12 | ||||
| -rw-r--r-- | security/selinux/ss/mls.c | 48 | ||||
| -rw-r--r-- | security/selinux/ss/mls.h | 2 | ||||
| -rw-r--r-- | security/selinux/ss/mls_types.h | 7 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.c | 127 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.h | 10 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 273 |
11 files changed, 302 insertions, 265 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index f2dde268165a..db0fd9f33499 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
| @@ -489,17 +489,14 @@ void avc_audit(u32 ssid, u32 tsid, | |||
| 489 | struct common_audit_data stack_data; | 489 | struct common_audit_data stack_data; |
| 490 | u32 denied, audited; | 490 | u32 denied, audited; |
| 491 | denied = requested & ~avd->allowed; | 491 | denied = requested & ~avd->allowed; |
| 492 | if (denied) { | 492 | if (denied) |
| 493 | audited = denied; | 493 | audited = denied & avd->auditdeny; |
| 494 | if (!(audited & avd->auditdeny)) | 494 | else if (result) |
| 495 | return; | ||
| 496 | } else if (result) { | ||
| 497 | audited = denied = requested; | 495 | audited = denied = requested; |
| 498 | } else { | 496 | else |
| 499 | audited = requested; | 497 | audited = requested & avd->auditallow; |
| 500 | if (!(audited & avd->auditallow)) | 498 | if (!audited) |
| 501 | return; | 499 | return; |
| 502 | } | ||
| 503 | if (!a) { | 500 | if (!a) { |
| 504 | a = &stack_data; | 501 | a = &stack_data; |
| 505 | memset(a, 0, sizeof(*a)); | 502 | memset(a, 0, sizeof(*a)); |
| @@ -746,9 +743,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
| 746 | else | 743 | else |
| 747 | avd = &avd_entry; | 744 | avd = &avd_entry; |
| 748 | 745 | ||
| 749 | rc = security_compute_av(ssid, tsid, tclass, requested, avd); | 746 | security_compute_av(ssid, tsid, tclass, avd); |
| 750 | if (rc) | ||
| 751 | goto out; | ||
| 752 | rcu_read_lock(); | 747 | rcu_read_lock(); |
| 753 | node = avc_insert(ssid, tsid, tclass, avd); | 748 | node = avc_insert(ssid, tsid, tclass, avd); |
| 754 | } else { | 749 | } else { |
| @@ -770,7 +765,6 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
| 770 | } | 765 | } |
| 771 | 766 | ||
| 772 | rcu_read_unlock(); | 767 | rcu_read_unlock(); |
| 773 | out: | ||
| 774 | return rc; | 768 | return rc; |
| 775 | } | 769 | } |
| 776 | 770 | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9a2ee845e9d4..5feecb41009d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -76,6 +76,7 @@ | |||
| 76 | #include <linux/selinux.h> | 76 | #include <linux/selinux.h> |
| 77 | #include <linux/mutex.h> | 77 | #include <linux/mutex.h> |
| 78 | #include <linux/posix-timers.h> | 78 | #include <linux/posix-timers.h> |
| 79 | #include <linux/syslog.h> | ||
| 79 | 80 | ||
| 80 | #include "avc.h" | 81 | #include "avc.h" |
| 81 | #include "objsec.h" | 82 | #include "objsec.h" |
| @@ -125,13 +126,6 @@ __setup("selinux=", selinux_enabled_setup); | |||
| 125 | int selinux_enabled = 1; | 126 | int selinux_enabled = 1; |
| 126 | #endif | 127 | #endif |
| 127 | 128 | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Minimal support for a secondary security module, | ||
| 131 | * just to allow the use of the capability module. | ||
| 132 | */ | ||
| 133 | static struct security_operations *secondary_ops; | ||
| 134 | |||
| 135 | /* Lists of inode and superblock security structures initialized | 129 | /* Lists of inode and superblock security structures initialized |
| 136 | before the policy was loaded. */ | 130 | before the policy was loaded. */ |
| 137 | static LIST_HEAD(superblock_security_head); | 131 | static LIST_HEAD(superblock_security_head); |
| @@ -2049,29 +2043,30 @@ static int selinux_quota_on(struct dentry *dentry) | |||
| 2049 | return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); | 2043 | return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); |
| 2050 | } | 2044 | } |
| 2051 | 2045 | ||
| 2052 | static int selinux_syslog(int type) | 2046 | static int selinux_syslog(int type, bool from_file) |
| 2053 | { | 2047 | { |
| 2054 | int rc; | 2048 | int rc; |
| 2055 | 2049 | ||
| 2056 | rc = cap_syslog(type); | 2050 | rc = cap_syslog(type, from_file); |
| 2057 | if (rc) | 2051 | if (rc) |
| 2058 | return rc; | 2052 | return rc; |
| 2059 | 2053 | ||
| 2060 | switch (type) { | 2054 | switch (type) { |
| 2061 | case 3: /* Read last kernel messages */ | 2055 | case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ |
| 2062 | case 10: /* Return size of the log buffer */ | 2056 | case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ |
| 2063 | rc = task_has_system(current, SYSTEM__SYSLOG_READ); | 2057 | rc = task_has_system(current, SYSTEM__SYSLOG_READ); |
| 2064 | break; | 2058 | break; |
| 2065 | case 6: /* Disable logging to console */ | 2059 | case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ |
| 2066 | case 7: /* Enable logging to console */ | 2060 | case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ |
| 2067 | case 8: /* Set level of messages printed to console */ | 2061 | /* Set level of messages printed to console */ |
| 2062 | case SYSLOG_ACTION_CONSOLE_LEVEL: | ||
| 2068 | rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); | 2063 | rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); |
| 2069 | break; | 2064 | break; |
| 2070 | case 0: /* Close log */ | 2065 | case SYSLOG_ACTION_CLOSE: /* Close log */ |
| 2071 | case 1: /* Open log */ | 2066 | case SYSLOG_ACTION_OPEN: /* Open log */ |
| 2072 | case 2: /* Read from log */ | 2067 | case SYSLOG_ACTION_READ: /* Read from log */ |
| 2073 | case 4: /* Read/clear last kernel messages */ | 2068 | case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */ |
| 2074 | case 5: /* Clear ring buffer */ | 2069 | case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */ |
| 2075 | default: | 2070 | default: |
| 2076 | rc = task_has_system(current, SYSTEM__SYSLOG_MOD); | 2071 | rc = task_has_system(current, SYSTEM__SYSLOG_MOD); |
| 2077 | break; | 2072 | break; |
| @@ -3334,7 +3329,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) | |||
| 3334 | 3329 | ||
| 3335 | if (ret == 0) | 3330 | if (ret == 0) |
| 3336 | tsec->create_sid = isec->sid; | 3331 | tsec->create_sid = isec->sid; |
| 3337 | return 0; | 3332 | return ret; |
| 3338 | } | 3333 | } |
| 3339 | 3334 | ||
| 3340 | static int selinux_kernel_module_request(char *kmod_name) | 3335 | static int selinux_kernel_module_request(char *kmod_name) |
| @@ -5672,9 +5667,6 @@ static __init int selinux_init(void) | |||
| 5672 | 0, SLAB_PANIC, NULL); | 5667 | 0, SLAB_PANIC, NULL); |
| 5673 | avc_init(); | 5668 | avc_init(); |
| 5674 | 5669 | ||
| 5675 | secondary_ops = security_ops; | ||
| 5676 | if (!secondary_ops) | ||
| 5677 | panic("SELinux: No initial security operations\n"); | ||
| 5678 | if (register_security(&selinux_ops)) | 5670 | if (register_security(&selinux_ops)) |
| 5679 | panic("SELinux: Unable to register with kernel.\n"); | 5671 | panic("SELinux: Unable to register with kernel.\n"); |
| 5680 | 5672 | ||
| @@ -5835,8 +5827,7 @@ int selinux_disable(void) | |||
| 5835 | selinux_disabled = 1; | 5827 | selinux_disabled = 1; |
| 5836 | selinux_enabled = 0; | 5828 | selinux_enabled = 0; |
| 5837 | 5829 | ||
| 5838 | /* Reset security_ops to the secondary module, dummy or capability. */ | 5830 | reset_security_ops(); |
| 5839 | security_ops = secondary_ops; | ||
| 5840 | 5831 | ||
| 5841 | /* Try to destroy the avc node cache */ | 5832 | /* Try to destroy the avc node cache */ |
| 5842 | avc_disable(); | 5833 | avc_disable(); |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 2553266ad793..1f7c2491d3dc 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
| @@ -57,7 +57,6 @@ | |||
| 57 | struct netlbl_lsm_secattr; | 57 | struct netlbl_lsm_secattr; |
| 58 | 58 | ||
| 59 | extern int selinux_enabled; | 59 | extern int selinux_enabled; |
| 60 | extern int selinux_mls_enabled; | ||
| 61 | 60 | ||
| 62 | /* Policy capabilities */ | 61 | /* Policy capabilities */ |
| 63 | enum { | 62 | enum { |
| @@ -80,6 +79,8 @@ extern int selinux_policycap_openperm; | |||
| 80 | /* limitation of boundary depth */ | 79 | /* limitation of boundary depth */ |
| 81 | #define POLICYDB_BOUNDS_MAXDEPTH 4 | 80 | #define POLICYDB_BOUNDS_MAXDEPTH 4 |
| 82 | 81 | ||
| 82 | int security_mls_enabled(void); | ||
| 83 | |||
| 83 | int security_load_policy(void *data, size_t len); | 84 | int security_load_policy(void *data, size_t len); |
| 84 | 85 | ||
| 85 | int security_policycap_supported(unsigned int req_cap); | 86 | int security_policycap_supported(unsigned int req_cap); |
| @@ -96,13 +97,11 @@ struct av_decision { | |||
| 96 | /* definitions of av_decision.flags */ | 97 | /* definitions of av_decision.flags */ |
| 97 | #define AVD_FLAGS_PERMISSIVE 0x0001 | 98 | #define AVD_FLAGS_PERMISSIVE 0x0001 |
| 98 | 99 | ||
| 99 | int security_compute_av(u32 ssid, u32 tsid, | 100 | void security_compute_av(u32 ssid, u32 tsid, |
| 100 | u16 tclass, u32 requested, | 101 | u16 tclass, struct av_decision *avd); |
| 101 | struct av_decision *avd); | ||
| 102 | 102 | ||
| 103 | int security_compute_av_user(u32 ssid, u32 tsid, | 103 | void security_compute_av_user(u32 ssid, u32 tsid, |
| 104 | u16 tclass, u32 requested, | 104 | u16 tclass, struct av_decision *avd); |
| 105 | struct av_decision *avd); | ||
| 106 | 105 | ||
| 107 | int security_transition_sid(u32 ssid, u32 tsid, | 106 | int security_transition_sid(u32 ssid, u32 tsid, |
| 108 | u16 tclass, u32 *out_sid); | 107 | u16 tclass, u32 *out_sid); |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index fab36fdf2769..cd191bbec03c 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -282,7 +282,8 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf, | |||
| 282 | char tmpbuf[TMPBUFLEN]; | 282 | char tmpbuf[TMPBUFLEN]; |
| 283 | ssize_t length; | 283 | ssize_t length; |
| 284 | 284 | ||
| 285 | length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled); | 285 | length = scnprintf(tmpbuf, TMPBUFLEN, "%d", |
| 286 | security_mls_enabled()); | ||
| 286 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); | 287 | return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); |
| 287 | } | 288 | } |
| 288 | 289 | ||
| @@ -494,7 +495,6 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
| 494 | char *scon, *tcon; | 495 | char *scon, *tcon; |
| 495 | u32 ssid, tsid; | 496 | u32 ssid, tsid; |
| 496 | u16 tclass; | 497 | u16 tclass; |
| 497 | u32 req; | ||
| 498 | struct av_decision avd; | 498 | struct av_decision avd; |
| 499 | ssize_t length; | 499 | ssize_t length; |
| 500 | 500 | ||
| @@ -512,7 +512,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
| 512 | goto out; | 512 | goto out; |
| 513 | 513 | ||
| 514 | length = -EINVAL; | 514 | length = -EINVAL; |
| 515 | if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4) | 515 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
| 516 | goto out2; | 516 | goto out2; |
| 517 | 517 | ||
| 518 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); | 518 | length = security_context_to_sid(scon, strlen(scon)+1, &ssid); |
| @@ -522,9 +522,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
| 522 | if (length < 0) | 522 | if (length < 0) |
| 523 | goto out2; | 523 | goto out2; |
| 524 | 524 | ||
| 525 | length = security_compute_av_user(ssid, tsid, tclass, req, &avd); | 525 | security_compute_av_user(ssid, tsid, tclass, &avd); |
| 526 | if (length < 0) | ||
| 527 | goto out2; | ||
| 528 | 526 | ||
| 529 | length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, | 527 | length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, |
| 530 | "%x %x %x %x %u %x", | 528 | "%x %x %x %x %u %x", |
| @@ -979,6 +977,8 @@ static int sel_make_bools(void) | |||
| 979 | u32 sid; | 977 | u32 sid; |
| 980 | 978 | ||
| 981 | /* remove any existing files */ | 979 | /* remove any existing files */ |
| 980 | for (i = 0; i < bool_num; i++) | ||
| 981 | kfree(bool_pending_names[i]); | ||
| 982 | kfree(bool_pending_names); | 982 | kfree(bool_pending_names); |
| 983 | kfree(bool_pending_values); | 983 | kfree(bool_pending_values); |
| 984 | bool_pending_names = NULL; | 984 | bool_pending_names = NULL; |
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index d9dd7a2f6a8a..45e8fb0515f8 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h | |||
| @@ -41,9 +41,6 @@ static inline int mls_context_cpy(struct context *dst, struct context *src) | |||
| 41 | { | 41 | { |
| 42 | int rc; | 42 | int rc; |
| 43 | 43 | ||
| 44 | if (!selinux_mls_enabled) | ||
| 45 | return 0; | ||
| 46 | |||
| 47 | dst->range.level[0].sens = src->range.level[0].sens; | 44 | dst->range.level[0].sens = src->range.level[0].sens; |
| 48 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); | 45 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); |
| 49 | if (rc) | 46 | if (rc) |
| @@ -64,9 +61,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src) | |||
| 64 | { | 61 | { |
| 65 | int rc; | 62 | int rc; |
| 66 | 63 | ||
| 67 | if (!selinux_mls_enabled) | ||
| 68 | return 0; | ||
| 69 | |||
| 70 | dst->range.level[0].sens = src->range.level[0].sens; | 64 | dst->range.level[0].sens = src->range.level[0].sens; |
| 71 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); | 65 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); |
| 72 | if (rc) | 66 | if (rc) |
| @@ -82,9 +76,6 @@ out: | |||
| 82 | 76 | ||
| 83 | static inline int mls_context_cmp(struct context *c1, struct context *c2) | 77 | static inline int mls_context_cmp(struct context *c1, struct context *c2) |
| 84 | { | 78 | { |
| 85 | if (!selinux_mls_enabled) | ||
| 86 | return 1; | ||
| 87 | |||
| 88 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && | 79 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && |
| 89 | ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && | 80 | ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && |
| 90 | (c1->range.level[1].sens == c2->range.level[1].sens) && | 81 | (c1->range.level[1].sens == c2->range.level[1].sens) && |
| @@ -93,9 +84,6 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2) | |||
| 93 | 84 | ||
| 94 | static inline void mls_context_destroy(struct context *c) | 85 | static inline void mls_context_destroy(struct context *c) |
| 95 | { | 86 | { |
| 96 | if (!selinux_mls_enabled) | ||
| 97 | return; | ||
| 98 | |||
| 99 | ebitmap_destroy(&c->range.level[0].cat); | 87 | ebitmap_destroy(&c->range.level[0].cat); |
| 100 | ebitmap_destroy(&c->range.level[1].cat); | 88 | ebitmap_destroy(&c->range.level[1].cat); |
| 101 | mls_context_init(c); | 89 | mls_context_init(c); |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 3f2b2706b5bb..372b773f8210 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
| @@ -39,7 +39,7 @@ int mls_compute_context_len(struct context *context) | |||
| 39 | struct ebitmap *e; | 39 | struct ebitmap *e; |
| 40 | struct ebitmap_node *node; | 40 | struct ebitmap_node *node; |
| 41 | 41 | ||
| 42 | if (!selinux_mls_enabled) | 42 | if (!policydb.mls_enabled) |
| 43 | return 0; | 43 | return 0; |
| 44 | 44 | ||
| 45 | len = 1; /* for the beginning ":" */ | 45 | len = 1; /* for the beginning ":" */ |
| @@ -93,7 +93,7 @@ void mls_sid_to_context(struct context *context, | |||
| 93 | struct ebitmap *e; | 93 | struct ebitmap *e; |
| 94 | struct ebitmap_node *node; | 94 | struct ebitmap_node *node; |
| 95 | 95 | ||
| 96 | if (!selinux_mls_enabled) | 96 | if (!policydb.mls_enabled) |
| 97 | return; | 97 | return; |
| 98 | 98 | ||
| 99 | scontextp = *scontext; | 99 | scontextp = *scontext; |
| @@ -200,7 +200,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c) | |||
| 200 | { | 200 | { |
| 201 | struct user_datum *usrdatum; | 201 | struct user_datum *usrdatum; |
| 202 | 202 | ||
| 203 | if (!selinux_mls_enabled) | 203 | if (!p->mls_enabled) |
| 204 | return 1; | 204 | return 1; |
| 205 | 205 | ||
| 206 | if (!mls_range_isvalid(p, &c->range)) | 206 | if (!mls_range_isvalid(p, &c->range)) |
| @@ -253,7 +253,7 @@ int mls_context_to_sid(struct policydb *pol, | |||
| 253 | struct cat_datum *catdatum, *rngdatum; | 253 | struct cat_datum *catdatum, *rngdatum; |
| 254 | int l, rc = -EINVAL; | 254 | int l, rc = -EINVAL; |
| 255 | 255 | ||
| 256 | if (!selinux_mls_enabled) { | 256 | if (!pol->mls_enabled) { |
| 257 | if (def_sid != SECSID_NULL && oldc) | 257 | if (def_sid != SECSID_NULL && oldc) |
| 258 | *scontext += strlen(*scontext)+1; | 258 | *scontext += strlen(*scontext)+1; |
| 259 | return 0; | 259 | return 0; |
| @@ -387,7 +387,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) | |||
| 387 | char *tmpstr, *freestr; | 387 | char *tmpstr, *freestr; |
| 388 | int rc; | 388 | int rc; |
| 389 | 389 | ||
| 390 | if (!selinux_mls_enabled) | 390 | if (!policydb.mls_enabled) |
| 391 | return -EINVAL; | 391 | return -EINVAL; |
| 392 | 392 | ||
| 393 | /* we need freestr because mls_context_to_sid will change | 393 | /* we need freestr because mls_context_to_sid will change |
| @@ -407,7 +407,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) | |||
| 407 | /* | 407 | /* |
| 408 | * Copies the MLS range `range' into `context'. | 408 | * Copies the MLS range `range' into `context'. |
| 409 | */ | 409 | */ |
| 410 | static inline int mls_range_set(struct context *context, | 410 | int mls_range_set(struct context *context, |
| 411 | struct mls_range *range) | 411 | struct mls_range *range) |
| 412 | { | 412 | { |
| 413 | int l, rc = 0; | 413 | int l, rc = 0; |
| @@ -427,7 +427,7 @@ static inline int mls_range_set(struct context *context, | |||
| 427 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, | 427 | int mls_setup_user_range(struct context *fromcon, struct user_datum *user, |
| 428 | struct context *usercon) | 428 | struct context *usercon) |
| 429 | { | 429 | { |
| 430 | if (selinux_mls_enabled) { | 430 | if (policydb.mls_enabled) { |
| 431 | struct mls_level *fromcon_sen = &(fromcon->range.level[0]); | 431 | struct mls_level *fromcon_sen = &(fromcon->range.level[0]); |
| 432 | struct mls_level *fromcon_clr = &(fromcon->range.level[1]); | 432 | struct mls_level *fromcon_clr = &(fromcon->range.level[1]); |
| 433 | struct mls_level *user_low = &(user->range.level[0]); | 433 | struct mls_level *user_low = &(user->range.level[0]); |
| @@ -477,7 +477,7 @@ int mls_convert_context(struct policydb *oldp, | |||
| 477 | struct ebitmap_node *node; | 477 | struct ebitmap_node *node; |
| 478 | int l, i; | 478 | int l, i; |
| 479 | 479 | ||
| 480 | if (!selinux_mls_enabled) | 480 | if (!policydb.mls_enabled) |
| 481 | return 0; | 481 | return 0; |
| 482 | 482 | ||
| 483 | for (l = 0; l < 2; l++) { | 483 | for (l = 0; l < 2; l++) { |
| @@ -513,23 +513,21 @@ int mls_compute_sid(struct context *scontext, | |||
| 513 | u32 specified, | 513 | u32 specified, |
| 514 | struct context *newcontext) | 514 | struct context *newcontext) |
| 515 | { | 515 | { |
| 516 | struct range_trans *rtr; | 516 | struct range_trans rtr; |
| 517 | struct mls_range *r; | ||
| 517 | 518 | ||
| 518 | if (!selinux_mls_enabled) | 519 | if (!policydb.mls_enabled) |
| 519 | return 0; | 520 | return 0; |
| 520 | 521 | ||
| 521 | switch (specified) { | 522 | switch (specified) { |
| 522 | case AVTAB_TRANSITION: | 523 | case AVTAB_TRANSITION: |
| 523 | /* Look for a range transition rule. */ | 524 | /* Look for a range transition rule. */ |
| 524 | for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { | 525 | rtr.source_type = scontext->type; |
| 525 | if (rtr->source_type == scontext->type && | 526 | rtr.target_type = tcontext->type; |
| 526 | rtr->target_type == tcontext->type && | 527 | rtr.target_class = tclass; |
| 527 | rtr->target_class == tclass) { | 528 | r = hashtab_search(policydb.range_tr, &rtr); |
| 528 | /* Set the range from the rule */ | 529 | if (r) |
| 529 | return mls_range_set(newcontext, | 530 | return mls_range_set(newcontext, r); |
| 530 | &rtr->target_range); | ||
| 531 | } | ||
| 532 | } | ||
| 533 | /* Fallthrough */ | 531 | /* Fallthrough */ |
| 534 | case AVTAB_CHANGE: | 532 | case AVTAB_CHANGE: |
| 535 | if (tclass == policydb.process_class) | 533 | if (tclass == policydb.process_class) |
| @@ -541,8 +539,8 @@ int mls_compute_sid(struct context *scontext, | |||
| 541 | case AVTAB_MEMBER: | 539 | case AVTAB_MEMBER: |
| 542 | /* Use the process effective MLS attributes. */ | 540 | /* Use the process effective MLS attributes. */ |
| 543 | return mls_context_cpy_low(newcontext, scontext); | 541 | return mls_context_cpy_low(newcontext, scontext); |
| 544 | default: | 542 | |
| 545 | return -EINVAL; | 543 | /* fall through */ |
| 546 | } | 544 | } |
| 547 | return -EINVAL; | 545 | return -EINVAL; |
| 548 | } | 546 | } |
| @@ -561,7 +559,7 @@ int mls_compute_sid(struct context *scontext, | |||
| 561 | void mls_export_netlbl_lvl(struct context *context, | 559 | void mls_export_netlbl_lvl(struct context *context, |
| 562 | struct netlbl_lsm_secattr *secattr) | 560 | struct netlbl_lsm_secattr *secattr) |
| 563 | { | 561 | { |
| 564 | if (!selinux_mls_enabled) | 562 | if (!policydb.mls_enabled) |
| 565 | return; | 563 | return; |
| 566 | 564 | ||
| 567 | secattr->attr.mls.lvl = context->range.level[0].sens - 1; | 565 | secattr->attr.mls.lvl = context->range.level[0].sens - 1; |
| @@ -581,7 +579,7 @@ void mls_export_netlbl_lvl(struct context *context, | |||
| 581 | void mls_import_netlbl_lvl(struct context *context, | 579 | void mls_import_netlbl_lvl(struct context *context, |
| 582 | struct netlbl_lsm_secattr *secattr) | 580 | struct netlbl_lsm_secattr *secattr) |
| 583 | { | 581 | { |
| 584 | if (!selinux_mls_enabled) | 582 | if (!policydb.mls_enabled) |
| 585 | return; | 583 | return; |
| 586 | 584 | ||
| 587 | context->range.level[0].sens = secattr->attr.mls.lvl + 1; | 585 | context->range.level[0].sens = secattr->attr.mls.lvl + 1; |
| @@ -603,7 +601,7 @@ int mls_export_netlbl_cat(struct context *context, | |||
| 603 | { | 601 | { |
| 604 | int rc; | 602 | int rc; |
| 605 | 603 | ||
| 606 | if (!selinux_mls_enabled) | 604 | if (!policydb.mls_enabled) |
| 607 | return 0; | 605 | return 0; |
| 608 | 606 | ||
| 609 | rc = ebitmap_netlbl_export(&context->range.level[0].cat, | 607 | rc = ebitmap_netlbl_export(&context->range.level[0].cat, |
| @@ -631,7 +629,7 @@ int mls_import_netlbl_cat(struct context *context, | |||
| 631 | { | 629 | { |
| 632 | int rc; | 630 | int rc; |
| 633 | 631 | ||
| 634 | if (!selinux_mls_enabled) | 632 | if (!policydb.mls_enabled) |
| 635 | return 0; | 633 | return 0; |
| 636 | 634 | ||
| 637 | rc = ebitmap_netlbl_import(&context->range.level[0].cat, | 635 | rc = ebitmap_netlbl_import(&context->range.level[0].cat, |
diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 1276715aaa8b..cd9152632e54 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h | |||
| @@ -39,6 +39,8 @@ int mls_context_to_sid(struct policydb *p, | |||
| 39 | 39 | ||
| 40 | int mls_from_string(char *str, struct context *context, gfp_t gfp_mask); | 40 | int mls_from_string(char *str, struct context *context, gfp_t gfp_mask); |
| 41 | 41 | ||
| 42 | int mls_range_set(struct context *context, struct mls_range *range); | ||
| 43 | |||
| 42 | int mls_convert_context(struct policydb *oldp, | 44 | int mls_convert_context(struct policydb *oldp, |
| 43 | struct policydb *newp, | 45 | struct policydb *newp, |
| 44 | struct context *context); | 46 | struct context *context); |
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index b6e943a21061..03bed52a8052 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #define _SS_MLS_TYPES_H_ | 15 | #define _SS_MLS_TYPES_H_ |
| 16 | 16 | ||
| 17 | #include "security.h" | 17 | #include "security.h" |
| 18 | #include "ebitmap.h" | ||
| 18 | 19 | ||
| 19 | struct mls_level { | 20 | struct mls_level { |
| 20 | u32 sens; /* sensitivity */ | 21 | u32 sens; /* sensitivity */ |
| @@ -27,18 +28,12 @@ struct mls_range { | |||
| 27 | 28 | ||
| 28 | static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) | 29 | static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) |
| 29 | { | 30 | { |
| 30 | if (!selinux_mls_enabled) | ||
| 31 | return 1; | ||
| 32 | |||
| 33 | return ((l1->sens == l2->sens) && | 31 | return ((l1->sens == l2->sens) && |
| 34 | ebitmap_cmp(&l1->cat, &l2->cat)); | 32 | ebitmap_cmp(&l1->cat, &l2->cat)); |
| 35 | } | 33 | } |
| 36 | 34 | ||
| 37 | static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) | 35 | static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) |
| 38 | { | 36 | { |
| 39 | if (!selinux_mls_enabled) | ||
| 40 | return 1; | ||
| 41 | |||
| 42 | return ((l1->sens >= l2->sens) && | 37 | return ((l1->sens >= l2->sens) && |
| 43 | ebitmap_contains(&l1->cat, &l2->cat)); | 38 | ebitmap_contains(&l1->cat, &l2->cat)); |
| 44 | } | 39 | } |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f03667213ea8..23c6e53c102c 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
| @@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = { | |||
| 52 | }; | 52 | }; |
| 53 | #endif | 53 | #endif |
| 54 | 54 | ||
| 55 | int selinux_mls_enabled; | ||
| 56 | |||
| 57 | static unsigned int symtab_sizes[SYM_NUM] = { | 55 | static unsigned int symtab_sizes[SYM_NUM] = { |
| 58 | 2, | 56 | 2, |
| 59 | 32, | 57 | 32, |
| @@ -177,6 +175,21 @@ out_free_role: | |||
| 177 | goto out; | 175 | goto out; |
| 178 | } | 176 | } |
| 179 | 177 | ||
| 178 | static u32 rangetr_hash(struct hashtab *h, const void *k) | ||
| 179 | { | ||
| 180 | const struct range_trans *key = k; | ||
| 181 | return (key->source_type + (key->target_type << 3) + | ||
| 182 | (key->target_class << 5)) & (h->size - 1); | ||
| 183 | } | ||
| 184 | |||
| 185 | static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) | ||
| 186 | { | ||
| 187 | const struct range_trans *key1 = k1, *key2 = k2; | ||
| 188 | return (key1->source_type != key2->source_type || | ||
| 189 | key1->target_type != key2->target_type || | ||
| 190 | key1->target_class != key2->target_class); | ||
| 191 | } | ||
| 192 | |||
| 180 | /* | 193 | /* |
| 181 | * Initialize a policy database structure. | 194 | * Initialize a policy database structure. |
| 182 | */ | 195 | */ |
| @@ -204,6 +217,10 @@ static int policydb_init(struct policydb *p) | |||
| 204 | if (rc) | 217 | if (rc) |
| 205 | goto out_free_symtab; | 218 | goto out_free_symtab; |
| 206 | 219 | ||
| 220 | p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); | ||
| 221 | if (!p->range_tr) | ||
| 222 | goto out_free_symtab; | ||
| 223 | |||
| 207 | ebitmap_init(&p->policycaps); | 224 | ebitmap_init(&p->policycaps); |
| 208 | ebitmap_init(&p->permissive_map); | 225 | ebitmap_init(&p->permissive_map); |
| 209 | 226 | ||
| @@ -408,6 +425,20 @@ static void symtab_hash_eval(struct symtab *s) | |||
| 408 | info.slots_used, h->size, info.max_chain_len); | 425 | info.slots_used, h->size, info.max_chain_len); |
| 409 | } | 426 | } |
| 410 | } | 427 | } |
| 428 | |||
| 429 | static void rangetr_hash_eval(struct hashtab *h) | ||
| 430 | { | ||
| 431 | struct hashtab_info info; | ||
| 432 | |||
| 433 | hashtab_stat(h, &info); | ||
| 434 | printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " | ||
| 435 | "longest chain length %d\n", h->nel, | ||
| 436 | info.slots_used, h->size, info.max_chain_len); | ||
| 437 | } | ||
| 438 | #else | ||
| 439 | static inline void rangetr_hash_eval(struct hashtab *h) | ||
| 440 | { | ||
| 441 | } | ||
| 411 | #endif | 442 | #endif |
| 412 | 443 | ||
| 413 | /* | 444 | /* |
| @@ -422,7 +453,7 @@ static int policydb_index_others(struct policydb *p) | |||
| 422 | 453 | ||
| 423 | printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", | 454 | printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", |
| 424 | p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); | 455 | p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); |
| 425 | if (selinux_mls_enabled) | 456 | if (p->mls_enabled) |
| 426 | printk(", %d sens, %d cats", p->p_levels.nprim, | 457 | printk(", %d sens, %d cats", p->p_levels.nprim, |
| 427 | p->p_cats.nprim); | 458 | p->p_cats.nprim); |
| 428 | printk("\n"); | 459 | printk("\n"); |
| @@ -612,6 +643,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = | |||
| 612 | cat_destroy, | 643 | cat_destroy, |
| 613 | }; | 644 | }; |
| 614 | 645 | ||
| 646 | static int range_tr_destroy(void *key, void *datum, void *p) | ||
| 647 | { | ||
| 648 | struct mls_range *rt = datum; | ||
| 649 | kfree(key); | ||
| 650 | ebitmap_destroy(&rt->level[0].cat); | ||
| 651 | ebitmap_destroy(&rt->level[1].cat); | ||
| 652 | kfree(datum); | ||
| 653 | cond_resched(); | ||
| 654 | return 0; | ||
| 655 | } | ||
| 656 | |||
| 615 | static void ocontext_destroy(struct ocontext *c, int i) | 657 | static void ocontext_destroy(struct ocontext *c, int i) |
| 616 | { | 658 | { |
| 617 | context_destroy(&c->context[0]); | 659 | context_destroy(&c->context[0]); |
| @@ -632,7 +674,6 @@ void policydb_destroy(struct policydb *p) | |||
| 632 | int i; | 674 | int i; |
| 633 | struct role_allow *ra, *lra = NULL; | 675 | struct role_allow *ra, *lra = NULL; |
| 634 | struct role_trans *tr, *ltr = NULL; | 676 | struct role_trans *tr, *ltr = NULL; |
| 635 | struct range_trans *rt, *lrt = NULL; | ||
| 636 | 677 | ||
| 637 | for (i = 0; i < SYM_NUM; i++) { | 678 | for (i = 0; i < SYM_NUM; i++) { |
| 638 | cond_resched(); | 679 | cond_resched(); |
| @@ -693,20 +734,8 @@ void policydb_destroy(struct policydb *p) | |||
| 693 | } | 734 | } |
| 694 | kfree(lra); | 735 | kfree(lra); |
| 695 | 736 | ||
| 696 | for (rt = p->range_tr; rt; rt = rt->next) { | 737 | hashtab_map(p->range_tr, range_tr_destroy, NULL); |
| 697 | cond_resched(); | 738 | hashtab_destroy(p->range_tr); |
| 698 | if (lrt) { | ||
| 699 | ebitmap_destroy(&lrt->target_range.level[0].cat); | ||
| 700 | ebitmap_destroy(&lrt->target_range.level[1].cat); | ||
| 701 | kfree(lrt); | ||
| 702 | } | ||
| 703 | lrt = rt; | ||
| 704 | } | ||
| 705 | if (lrt) { | ||
| 706 | ebitmap_destroy(&lrt->target_range.level[0].cat); | ||
| 707 | ebitmap_destroy(&lrt->target_range.level[1].cat); | ||
| 708 | kfree(lrt); | ||
| 709 | } | ||
| 710 | 739 | ||
| 711 | if (p->type_attr_map) { | 740 | if (p->type_attr_map) { |
| 712 | for (i = 0; i < p->p_types.nprim; i++) | 741 | for (i = 0; i < p->p_types.nprim; i++) |
| @@ -1686,12 +1715,11 @@ int policydb_read(struct policydb *p, void *fp) | |||
| 1686 | int i, j, rc; | 1715 | int i, j, rc; |
| 1687 | __le32 buf[4]; | 1716 | __le32 buf[4]; |
| 1688 | u32 nodebuf[8]; | 1717 | u32 nodebuf[8]; |
| 1689 | u32 len, len2, config, nprim, nel, nel2; | 1718 | u32 len, len2, nprim, nel, nel2; |
| 1690 | char *policydb_str; | 1719 | char *policydb_str; |
| 1691 | struct policydb_compat_info *info; | 1720 | struct policydb_compat_info *info; |
| 1692 | struct range_trans *rt, *lrt; | 1721 | struct range_trans *rt; |
| 1693 | 1722 | struct mls_range *r; | |
| 1694 | config = 0; | ||
| 1695 | 1723 | ||
| 1696 | rc = policydb_init(p); | 1724 | rc = policydb_init(p); |
| 1697 | if (rc) | 1725 | if (rc) |
| @@ -1740,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
| 1740 | kfree(policydb_str); | 1768 | kfree(policydb_str); |
| 1741 | policydb_str = NULL; | 1769 | policydb_str = NULL; |
| 1742 | 1770 | ||
| 1743 | /* Read the version, config, and table sizes. */ | 1771 | /* Read the version and table sizes. */ |
| 1744 | rc = next_entry(buf, fp, sizeof(u32)*4); | 1772 | rc = next_entry(buf, fp, sizeof(u32)*4); |
| 1745 | if (rc < 0) | 1773 | if (rc < 0) |
| 1746 | goto bad; | 1774 | goto bad; |
| @@ -1755,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp) | |||
| 1755 | } | 1783 | } |
| 1756 | 1784 | ||
| 1757 | if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { | 1785 | if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { |
| 1758 | if (ss_initialized && !selinux_mls_enabled) { | 1786 | p->mls_enabled = 1; |
| 1759 | printk(KERN_ERR "SELinux: Cannot switch between non-MLS" | ||
| 1760 | " and MLS policies\n"); | ||
| 1761 | goto bad; | ||
| 1762 | } | ||
| 1763 | selinux_mls_enabled = 1; | ||
| 1764 | config |= POLICYDB_CONFIG_MLS; | ||
| 1765 | 1787 | ||
| 1766 | if (p->policyvers < POLICYDB_VERSION_MLS) { | 1788 | if (p->policyvers < POLICYDB_VERSION_MLS) { |
| 1767 | printk(KERN_ERR "SELinux: security policydb version %d " | 1789 | printk(KERN_ERR "SELinux: security policydb version %d " |
| @@ -1769,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp) | |||
| 1769 | p->policyvers); | 1791 | p->policyvers); |
| 1770 | goto bad; | 1792 | goto bad; |
| 1771 | } | 1793 | } |
| 1772 | } else { | ||
| 1773 | if (ss_initialized && selinux_mls_enabled) { | ||
| 1774 | printk(KERN_ERR "SELinux: Cannot switch between MLS and" | ||
| 1775 | " non-MLS policies\n"); | ||
| 1776 | goto bad; | ||
| 1777 | } | ||
| 1778 | } | 1794 | } |
| 1779 | p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); | 1795 | p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); |
| 1780 | p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); | 1796 | p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); |
| @@ -2122,44 +2138,61 @@ int policydb_read(struct policydb *p, void *fp) | |||
| 2122 | if (rc < 0) | 2138 | if (rc < 0) |
| 2123 | goto bad; | 2139 | goto bad; |
| 2124 | nel = le32_to_cpu(buf[0]); | 2140 | nel = le32_to_cpu(buf[0]); |
| 2125 | lrt = NULL; | ||
| 2126 | for (i = 0; i < nel; i++) { | 2141 | for (i = 0; i < nel; i++) { |
| 2127 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); | 2142 | rt = kzalloc(sizeof(*rt), GFP_KERNEL); |
| 2128 | if (!rt) { | 2143 | if (!rt) { |
| 2129 | rc = -ENOMEM; | 2144 | rc = -ENOMEM; |
| 2130 | goto bad; | 2145 | goto bad; |
| 2131 | } | 2146 | } |
| 2132 | if (lrt) | ||
| 2133 | lrt->next = rt; | ||
| 2134 | else | ||
| 2135 | p->range_tr = rt; | ||
| 2136 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); | 2147 | rc = next_entry(buf, fp, (sizeof(u32) * 2)); |
| 2137 | if (rc < 0) | 2148 | if (rc < 0) { |
| 2149 | kfree(rt); | ||
| 2138 | goto bad; | 2150 | goto bad; |
| 2151 | } | ||
| 2139 | rt->source_type = le32_to_cpu(buf[0]); | 2152 | rt->source_type = le32_to_cpu(buf[0]); |
| 2140 | rt->target_type = le32_to_cpu(buf[1]); | 2153 | rt->target_type = le32_to_cpu(buf[1]); |
| 2141 | if (new_rangetr) { | 2154 | if (new_rangetr) { |
| 2142 | rc = next_entry(buf, fp, sizeof(u32)); | 2155 | rc = next_entry(buf, fp, sizeof(u32)); |
| 2143 | if (rc < 0) | 2156 | if (rc < 0) { |
| 2157 | kfree(rt); | ||
| 2144 | goto bad; | 2158 | goto bad; |
| 2159 | } | ||
| 2145 | rt->target_class = le32_to_cpu(buf[0]); | 2160 | rt->target_class = le32_to_cpu(buf[0]); |
| 2146 | } else | 2161 | } else |
| 2147 | rt->target_class = p->process_class; | 2162 | rt->target_class = p->process_class; |
| 2148 | if (!policydb_type_isvalid(p, rt->source_type) || | 2163 | if (!policydb_type_isvalid(p, rt->source_type) || |
| 2149 | !policydb_type_isvalid(p, rt->target_type) || | 2164 | !policydb_type_isvalid(p, rt->target_type) || |
| 2150 | !policydb_class_isvalid(p, rt->target_class)) { | 2165 | !policydb_class_isvalid(p, rt->target_class)) { |
| 2166 | kfree(rt); | ||
| 2151 | rc = -EINVAL; | 2167 | rc = -EINVAL; |
| 2152 | goto bad; | 2168 | goto bad; |
| 2153 | } | 2169 | } |
| 2154 | rc = mls_read_range_helper(&rt->target_range, fp); | 2170 | r = kzalloc(sizeof(*r), GFP_KERNEL); |
| 2155 | if (rc) | 2171 | if (!r) { |
| 2172 | kfree(rt); | ||
| 2173 | rc = -ENOMEM; | ||
| 2156 | goto bad; | 2174 | goto bad; |
| 2157 | if (!mls_range_isvalid(p, &rt->target_range)) { | 2175 | } |
| 2176 | rc = mls_read_range_helper(r, fp); | ||
| 2177 | if (rc) { | ||
| 2178 | kfree(rt); | ||
| 2179 | kfree(r); | ||
| 2180 | goto bad; | ||
| 2181 | } | ||
| 2182 | if (!mls_range_isvalid(p, r)) { | ||
| 2158 | printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); | 2183 | printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); |
| 2184 | kfree(rt); | ||
| 2185 | kfree(r); | ||
| 2186 | goto bad; | ||
| 2187 | } | ||
| 2188 | rc = hashtab_insert(p->range_tr, rt, r); | ||
| 2189 | if (rc) { | ||
| 2190 | kfree(rt); | ||
| 2191 | kfree(r); | ||
| 2159 | goto bad; | 2192 | goto bad; |
| 2160 | } | 2193 | } |
| 2161 | lrt = rt; | ||
| 2162 | } | 2194 | } |
| 2195 | rangetr_hash_eval(p->range_tr); | ||
| 2163 | } | 2196 | } |
| 2164 | 2197 | ||
| 2165 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); | 2198 | p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); |
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index cdcc5700946f..26d9adf8542b 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
| @@ -27,6 +27,8 @@ | |||
| 27 | #include "symtab.h" | 27 | #include "symtab.h" |
| 28 | #include "avtab.h" | 28 | #include "avtab.h" |
| 29 | #include "sidtab.h" | 29 | #include "sidtab.h" |
| 30 | #include "ebitmap.h" | ||
| 31 | #include "mls_types.h" | ||
| 30 | #include "context.h" | 32 | #include "context.h" |
| 31 | #include "constraint.h" | 33 | #include "constraint.h" |
| 32 | 34 | ||
| @@ -113,8 +115,6 @@ struct range_trans { | |||
| 113 | u32 source_type; | 115 | u32 source_type; |
| 114 | u32 target_type; | 116 | u32 target_type; |
| 115 | u32 target_class; | 117 | u32 target_class; |
| 116 | struct mls_range target_range; | ||
| 117 | struct range_trans *next; | ||
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | /* Boolean data type */ | 120 | /* Boolean data type */ |
| @@ -187,6 +187,8 @@ struct genfs { | |||
| 187 | 187 | ||
| 188 | /* The policy database */ | 188 | /* The policy database */ |
| 189 | struct policydb { | 189 | struct policydb { |
| 190 | int mls_enabled; | ||
| 191 | |||
| 190 | /* symbol tables */ | 192 | /* symbol tables */ |
| 191 | struct symtab symtab[SYM_NUM]; | 193 | struct symtab symtab[SYM_NUM]; |
| 192 | #define p_commons symtab[SYM_COMMONS] | 194 | #define p_commons symtab[SYM_COMMONS] |
| @@ -240,8 +242,8 @@ struct policydb { | |||
| 240 | fixed labeling behavior. */ | 242 | fixed labeling behavior. */ |
| 241 | struct genfs *genfs; | 243 | struct genfs *genfs; |
| 242 | 244 | ||
| 243 | /* range transitions */ | 245 | /* range transitions table (range_trans_key -> mls_range) */ |
| 244 | struct range_trans *range_tr; | 246 | struct hashtab *range_tr; |
| 245 | 247 | ||
| 246 | /* type -> attribute reverse mapping */ | 248 | /* type -> attribute reverse mapping */ |
| 247 | struct ebitmap *type_attr_map; | 249 | struct ebitmap *type_attr_map; |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b3efae204ac7..cf27b3ee1a95 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -26,6 +26,10 @@ | |||
| 26 | * | 26 | * |
| 27 | * Added support for bounds domain and audit messaged on masked permissions | 27 | * Added support for bounds domain and audit messaged on masked permissions |
| 28 | * | 28 | * |
| 29 | * Updated: Guido Trentalancia <guido@trentalancia.com> | ||
| 30 | * | ||
| 31 | * Added support for runtime switching of the policy type | ||
| 32 | * | ||
| 29 | * Copyright (C) 2008, 2009 NEC Corporation | 33 | * Copyright (C) 2008, 2009 NEC Corporation |
| 30 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. | 34 | * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. |
| 31 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. | 35 | * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. |
| @@ -87,11 +91,10 @@ static u32 latest_granting; | |||
| 87 | static int context_struct_to_string(struct context *context, char **scontext, | 91 | static int context_struct_to_string(struct context *context, char **scontext, |
| 88 | u32 *scontext_len); | 92 | u32 *scontext_len); |
| 89 | 93 | ||
| 90 | static int context_struct_compute_av(struct context *scontext, | 94 | static void context_struct_compute_av(struct context *scontext, |
| 91 | struct context *tcontext, | 95 | struct context *tcontext, |
| 92 | u16 tclass, | 96 | u16 tclass, |
| 93 | u32 requested, | 97 | struct av_decision *avd); |
| 94 | struct av_decision *avd); | ||
| 95 | 98 | ||
| 96 | struct selinux_mapping { | 99 | struct selinux_mapping { |
| 97 | u16 value; /* policy value */ | 100 | u16 value; /* policy value */ |
| @@ -196,23 +199,6 @@ static u16 unmap_class(u16 tclass) | |||
| 196 | return tclass; | 199 | return tclass; |
| 197 | } | 200 | } |
| 198 | 201 | ||
| 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, | 202 | static void map_decision(u16 tclass, struct av_decision *avd, |
| 217 | int allow_unknown) | 203 | int allow_unknown) |
| 218 | { | 204 | { |
| @@ -250,6 +236,10 @@ static void map_decision(u16 tclass, struct av_decision *avd, | |||
| 250 | } | 236 | } |
| 251 | } | 237 | } |
| 252 | 238 | ||
| 239 | int security_mls_enabled(void) | ||
| 240 | { | ||
| 241 | return policydb.mls_enabled; | ||
| 242 | } | ||
| 253 | 243 | ||
| 254 | /* | 244 | /* |
| 255 | * Return the boolean value of a constraint expression | 245 | * Return the boolean value of a constraint expression |
| @@ -465,7 +455,8 @@ static void security_dump_masked_av(struct context *scontext, | |||
| 465 | char *scontext_name = NULL; | 455 | char *scontext_name = NULL; |
| 466 | char *tcontext_name = NULL; | 456 | char *tcontext_name = NULL; |
| 467 | char *permission_names[32]; | 457 | char *permission_names[32]; |
| 468 | int index, length; | 458 | int index; |
| 459 | u32 length; | ||
| 469 | bool need_comma = false; | 460 | bool need_comma = false; |
| 470 | 461 | ||
| 471 | if (!permissions) | 462 | if (!permissions) |
| @@ -532,7 +523,6 @@ out: | |||
| 532 | static void type_attribute_bounds_av(struct context *scontext, | 523 | static void type_attribute_bounds_av(struct context *scontext, |
| 533 | struct context *tcontext, | 524 | struct context *tcontext, |
| 534 | u16 tclass, | 525 | u16 tclass, |
| 535 | u32 requested, | ||
| 536 | struct av_decision *avd) | 526 | struct av_decision *avd) |
| 537 | { | 527 | { |
| 538 | struct context lo_scontext; | 528 | struct context lo_scontext; |
| @@ -553,7 +543,6 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 553 | context_struct_compute_av(&lo_scontext, | 543 | context_struct_compute_av(&lo_scontext, |
| 554 | tcontext, | 544 | tcontext, |
| 555 | tclass, | 545 | tclass, |
| 556 | requested, | ||
| 557 | &lo_avd); | 546 | &lo_avd); |
| 558 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 547 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
| 559 | return; /* no masked permission */ | 548 | return; /* no masked permission */ |
| @@ -569,7 +558,6 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 569 | context_struct_compute_av(scontext, | 558 | context_struct_compute_av(scontext, |
| 570 | &lo_tcontext, | 559 | &lo_tcontext, |
| 571 | tclass, | 560 | tclass, |
| 572 | requested, | ||
| 573 | &lo_avd); | 561 | &lo_avd); |
| 574 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 562 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
| 575 | return; /* no masked permission */ | 563 | return; /* no masked permission */ |
| @@ -586,7 +574,6 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 586 | context_struct_compute_av(&lo_scontext, | 574 | context_struct_compute_av(&lo_scontext, |
| 587 | &lo_tcontext, | 575 | &lo_tcontext, |
| 588 | tclass, | 576 | tclass, |
| 589 | requested, | ||
| 590 | &lo_avd); | 577 | &lo_avd); |
| 591 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) | 578 | if ((lo_avd.allowed & avd->allowed) == avd->allowed) |
| 592 | return; /* no masked permission */ | 579 | return; /* no masked permission */ |
| @@ -607,11 +594,10 @@ static void type_attribute_bounds_av(struct context *scontext, | |||
| 607 | * Compute access vectors based on a context structure pair for | 594 | * Compute access vectors based on a context structure pair for |
| 608 | * the permissions in a particular class. | 595 | * the permissions in a particular class. |
| 609 | */ | 596 | */ |
| 610 | static int context_struct_compute_av(struct context *scontext, | 597 | static void context_struct_compute_av(struct context *scontext, |
| 611 | struct context *tcontext, | 598 | struct context *tcontext, |
| 612 | u16 tclass, | 599 | u16 tclass, |
| 613 | u32 requested, | 600 | struct av_decision *avd) |
| 614 | struct av_decision *avd) | ||
| 615 | { | 601 | { |
| 616 | struct constraint_node *constraint; | 602 | struct constraint_node *constraint; |
| 617 | struct role_allow *ra; | 603 | struct role_allow *ra; |
| @@ -622,19 +608,14 @@ static int context_struct_compute_av(struct context *scontext, | |||
| 622 | struct ebitmap_node *snode, *tnode; | 608 | struct ebitmap_node *snode, *tnode; |
| 623 | unsigned int i, j; | 609 | unsigned int i, j; |
| 624 | 610 | ||
| 625 | /* | ||
| 626 | * Initialize the access vectors to the default values. | ||
| 627 | */ | ||
| 628 | avd->allowed = 0; | 611 | avd->allowed = 0; |
| 629 | avd->auditallow = 0; | 612 | avd->auditallow = 0; |
| 630 | avd->auditdeny = 0xffffffff; | 613 | avd->auditdeny = 0xffffffff; |
| 631 | avd->seqno = latest_granting; | ||
| 632 | avd->flags = 0; | ||
| 633 | 614 | ||
| 634 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { | 615 | if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { |
| 635 | if (printk_ratelimit()) | 616 | if (printk_ratelimit()) |
| 636 | printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); | 617 | printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); |
| 637 | return -EINVAL; | 618 | return; |
| 638 | } | 619 | } |
| 639 | 620 | ||
| 640 | tclass_datum = policydb.class_val_to_struct[tclass - 1]; | 621 | tclass_datum = policydb.class_val_to_struct[tclass - 1]; |
| @@ -705,9 +686,7 @@ static int context_struct_compute_av(struct context *scontext, | |||
| 705 | * permission and notice it to userspace via audit. | 686 | * permission and notice it to userspace via audit. |
| 706 | */ | 687 | */ |
| 707 | type_attribute_bounds_av(scontext, tcontext, | 688 | type_attribute_bounds_av(scontext, tcontext, |
| 708 | tclass, requested, avd); | 689 | tclass, avd); |
| 709 | |||
| 710 | return 0; | ||
| 711 | } | 690 | } |
| 712 | 691 | ||
| 713 | static int security_validtrans_handle_fail(struct context *ocontext, | 692 | static int security_validtrans_handle_fail(struct context *ocontext, |
| @@ -864,7 +843,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) | |||
| 864 | if (rc) { | 843 | if (rc) { |
| 865 | char *old_name = NULL; | 844 | char *old_name = NULL; |
| 866 | char *new_name = NULL; | 845 | char *new_name = NULL; |
| 867 | int length; | 846 | u32 length; |
| 868 | 847 | ||
| 869 | if (!context_struct_to_string(old_context, | 848 | if (!context_struct_to_string(old_context, |
| 870 | &old_name, &length) && | 849 | &old_name, &length) && |
| @@ -886,110 +865,116 @@ out: | |||
| 886 | return rc; | 865 | return rc; |
| 887 | } | 866 | } |
| 888 | 867 | ||
| 889 | 868 | static void avd_init(struct av_decision *avd) | |
| 890 | static int security_compute_av_core(u32 ssid, | ||
| 891 | u32 tsid, | ||
| 892 | u16 tclass, | ||
| 893 | u32 requested, | ||
| 894 | struct av_decision *avd) | ||
| 895 | { | 869 | { |
| 896 | struct context *scontext = NULL, *tcontext = NULL; | 870 | avd->allowed = 0; |
| 897 | int rc = 0; | 871 | avd->auditallow = 0; |
| 898 | 872 | avd->auditdeny = 0xffffffff; | |
| 899 | scontext = sidtab_search(&sidtab, ssid); | 873 | avd->seqno = latest_granting; |
| 900 | if (!scontext) { | 874 | avd->flags = 0; |
| 901 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
| 902 | __func__, ssid); | ||
| 903 | return -EINVAL; | ||
| 904 | } | ||
| 905 | tcontext = sidtab_search(&sidtab, tsid); | ||
| 906 | if (!tcontext) { | ||
| 907 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
| 908 | __func__, tsid); | ||
| 909 | return -EINVAL; | ||
| 910 | } | ||
| 911 | |||
| 912 | rc = context_struct_compute_av(scontext, tcontext, tclass, | ||
| 913 | requested, avd); | ||
| 914 | |||
| 915 | /* permissive domain? */ | ||
| 916 | if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) | ||
| 917 | avd->flags |= AVD_FLAGS_PERMISSIVE; | ||
| 918 | |||
| 919 | return rc; | ||
| 920 | } | 875 | } |
| 921 | 876 | ||
| 877 | |||
| 922 | /** | 878 | /** |
| 923 | * security_compute_av - Compute access vector decisions. | 879 | * security_compute_av - Compute access vector decisions. |
| 924 | * @ssid: source security identifier | 880 | * @ssid: source security identifier |
| 925 | * @tsid: target security identifier | 881 | * @tsid: target security identifier |
| 926 | * @tclass: target security class | 882 | * @tclass: target security class |
| 927 | * @requested: requested permissions | ||
| 928 | * @avd: access vector decisions | 883 | * @avd: access vector decisions |
| 929 | * | 884 | * |
| 930 | * Compute a set of access vector decisions based on the | 885 | * Compute a set of access vector decisions based on the |
| 931 | * SID pair (@ssid, @tsid) for the permissions in @tclass. | 886 | * SID pair (@ssid, @tsid) for the permissions in @tclass. |
| 932 | * Return -%EINVAL if any of the parameters are invalid or %0 | ||
| 933 | * if the access vector decisions were computed successfully. | ||
| 934 | */ | 887 | */ |
| 935 | int security_compute_av(u32 ssid, | 888 | void security_compute_av(u32 ssid, |
| 936 | u32 tsid, | 889 | u32 tsid, |
| 937 | u16 orig_tclass, | 890 | u16 orig_tclass, |
| 938 | u32 orig_requested, | 891 | struct av_decision *avd) |
| 939 | struct av_decision *avd) | ||
| 940 | { | 892 | { |
| 941 | u16 tclass; | 893 | u16 tclass; |
| 942 | u32 requested; | 894 | struct context *scontext = NULL, *tcontext = NULL; |
| 943 | int rc; | ||
| 944 | 895 | ||
| 945 | read_lock(&policy_rwlock); | 896 | read_lock(&policy_rwlock); |
| 946 | 897 | avd_init(avd); | |
| 947 | if (!ss_initialized) | 898 | if (!ss_initialized) |
| 948 | goto allow; | 899 | goto allow; |
| 949 | 900 | ||
| 950 | requested = unmap_perm(orig_tclass, orig_requested); | 901 | scontext = sidtab_search(&sidtab, ssid); |
| 902 | if (!scontext) { | ||
| 903 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
| 904 | __func__, ssid); | ||
| 905 | goto out; | ||
| 906 | } | ||
| 907 | |||
| 908 | /* permissive domain? */ | ||
| 909 | if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) | ||
| 910 | avd->flags |= AVD_FLAGS_PERMISSIVE; | ||
| 911 | |||
| 912 | tcontext = sidtab_search(&sidtab, tsid); | ||
| 913 | if (!tcontext) { | ||
| 914 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
| 915 | __func__, tsid); | ||
| 916 | goto out; | ||
| 917 | } | ||
| 918 | |||
| 951 | tclass = unmap_class(orig_tclass); | 919 | tclass = unmap_class(orig_tclass); |
| 952 | if (unlikely(orig_tclass && !tclass)) { | 920 | if (unlikely(orig_tclass && !tclass)) { |
| 953 | if (policydb.allow_unknown) | 921 | if (policydb.allow_unknown) |
| 954 | goto allow; | 922 | goto allow; |
| 955 | rc = -EINVAL; | ||
| 956 | goto out; | 923 | goto out; |
| 957 | } | 924 | } |
| 958 | rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); | 925 | context_struct_compute_av(scontext, tcontext, tclass, avd); |
| 959 | map_decision(orig_tclass, avd, policydb.allow_unknown); | 926 | map_decision(orig_tclass, avd, policydb.allow_unknown); |
| 960 | out: | 927 | out: |
| 961 | read_unlock(&policy_rwlock); | 928 | read_unlock(&policy_rwlock); |
| 962 | return rc; | 929 | return; |
| 963 | allow: | 930 | allow: |
| 964 | avd->allowed = 0xffffffff; | 931 | avd->allowed = 0xffffffff; |
| 965 | avd->auditallow = 0; | ||
| 966 | avd->auditdeny = 0xffffffff; | ||
| 967 | avd->seqno = latest_granting; | ||
| 968 | avd->flags = 0; | ||
| 969 | rc = 0; | ||
| 970 | goto out; | 932 | goto out; |
| 971 | } | 933 | } |
| 972 | 934 | ||
| 973 | int security_compute_av_user(u32 ssid, | 935 | void security_compute_av_user(u32 ssid, |
| 974 | u32 tsid, | 936 | u32 tsid, |
| 975 | u16 tclass, | 937 | u16 tclass, |
| 976 | u32 requested, | 938 | struct av_decision *avd) |
| 977 | struct av_decision *avd) | ||
| 978 | { | 939 | { |
| 979 | int rc; | 940 | struct context *scontext = NULL, *tcontext = NULL; |
| 980 | 941 | ||
| 981 | if (!ss_initialized) { | 942 | read_lock(&policy_rwlock); |
| 982 | avd->allowed = 0xffffffff; | 943 | avd_init(avd); |
| 983 | avd->auditallow = 0; | 944 | if (!ss_initialized) |
| 984 | avd->auditdeny = 0xffffffff; | 945 | goto allow; |
| 985 | avd->seqno = latest_granting; | 946 | |
| 986 | return 0; | 947 | scontext = sidtab_search(&sidtab, ssid); |
| 948 | if (!scontext) { | ||
| 949 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
| 950 | __func__, ssid); | ||
| 951 | goto out; | ||
| 987 | } | 952 | } |
| 988 | 953 | ||
| 989 | read_lock(&policy_rwlock); | 954 | /* permissive domain? */ |
| 990 | rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); | 955 | if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) |
| 956 | avd->flags |= AVD_FLAGS_PERMISSIVE; | ||
| 957 | |||
| 958 | tcontext = sidtab_search(&sidtab, tsid); | ||
| 959 | if (!tcontext) { | ||
| 960 | printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", | ||
| 961 | __func__, tsid); | ||
| 962 | goto out; | ||
| 963 | } | ||
| 964 | |||
| 965 | if (unlikely(!tclass)) { | ||
| 966 | if (policydb.allow_unknown) | ||
| 967 | goto allow; | ||
| 968 | goto out; | ||
| 969 | } | ||
| 970 | |||
| 971 | context_struct_compute_av(scontext, tcontext, tclass, avd); | ||
| 972 | out: | ||
| 991 | read_unlock(&policy_rwlock); | 973 | read_unlock(&policy_rwlock); |
| 992 | return rc; | 974 | return; |
| 975 | allow: | ||
| 976 | avd->allowed = 0xffffffff; | ||
| 977 | goto out; | ||
| 993 | } | 978 | } |
| 994 | 979 | ||
| 995 | /* | 980 | /* |
| @@ -1565,7 +1550,10 @@ static int clone_sid(u32 sid, | |||
| 1565 | { | 1550 | { |
| 1566 | struct sidtab *s = arg; | 1551 | struct sidtab *s = arg; |
| 1567 | 1552 | ||
| 1568 | return sidtab_insert(s, sid, context); | 1553 | if (sid > SECINITSID_NUM) |
| 1554 | return sidtab_insert(s, sid, context); | ||
| 1555 | else | ||
| 1556 | return 0; | ||
| 1569 | } | 1557 | } |
| 1570 | 1558 | ||
| 1571 | static inline int convert_context_handle_invalid_context(struct context *context) | 1559 | static inline int convert_context_handle_invalid_context(struct context *context) |
| @@ -1606,12 +1594,17 @@ static int convert_context(u32 key, | |||
| 1606 | { | 1594 | { |
| 1607 | struct convert_context_args *args; | 1595 | struct convert_context_args *args; |
| 1608 | struct context oldc; | 1596 | struct context oldc; |
| 1597 | struct ocontext *oc; | ||
| 1598 | struct mls_range *range; | ||
| 1609 | struct role_datum *role; | 1599 | struct role_datum *role; |
| 1610 | struct type_datum *typdatum; | 1600 | struct type_datum *typdatum; |
| 1611 | struct user_datum *usrdatum; | 1601 | struct user_datum *usrdatum; |
| 1612 | char *s; | 1602 | char *s; |
| 1613 | u32 len; | 1603 | u32 len; |
| 1614 | int rc; | 1604 | int rc = 0; |
| 1605 | |||
| 1606 | if (key <= SECINITSID_NUM) | ||
| 1607 | goto out; | ||
| 1615 | 1608 | ||
| 1616 | args = p; | 1609 | args = p; |
| 1617 | 1610 | ||
| @@ -1673,9 +1666,39 @@ static int convert_context(u32 key, | |||
| 1673 | goto bad; | 1666 | goto bad; |
| 1674 | c->type = typdatum->value; | 1667 | c->type = typdatum->value; |
| 1675 | 1668 | ||
| 1676 | rc = mls_convert_context(args->oldp, args->newp, c); | 1669 | /* Convert the MLS fields if dealing with MLS policies */ |
| 1677 | if (rc) | 1670 | if (args->oldp->mls_enabled && args->newp->mls_enabled) { |
| 1678 | goto bad; | 1671 | rc = mls_convert_context(args->oldp, args->newp, c); |
| 1672 | if (rc) | ||
| 1673 | goto bad; | ||
| 1674 | } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) { | ||
| 1675 | /* | ||
| 1676 | * Switching between MLS and non-MLS policy: | ||
| 1677 | * free any storage used by the MLS fields in the | ||
| 1678 | * context for all existing entries in the sidtab. | ||
| 1679 | */ | ||
| 1680 | mls_context_destroy(c); | ||
| 1681 | } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { | ||
| 1682 | /* | ||
| 1683 | * Switching between non-MLS and MLS policy: | ||
| 1684 | * ensure that the MLS fields of the context for all | ||
| 1685 | * existing entries in the sidtab are filled in with a | ||
| 1686 | * suitable default value, likely taken from one of the | ||
| 1687 | * initial SIDs. | ||
| 1688 | */ | ||
| 1689 | oc = args->newp->ocontexts[OCON_ISID]; | ||
| 1690 | while (oc && oc->sid[0] != SECINITSID_UNLABELED) | ||
| 1691 | oc = oc->next; | ||
| 1692 | if (!oc) { | ||
| 1693 | printk(KERN_ERR "SELinux: unable to look up" | ||
| 1694 | " the initial SIDs list\n"); | ||
| 1695 | goto bad; | ||
| 1696 | } | ||
| 1697 | range = &oc->context[0].range; | ||
| 1698 | rc = mls_range_set(c, range); | ||
| 1699 | if (rc) | ||
| 1700 | goto bad; | ||
| 1701 | } | ||
| 1679 | 1702 | ||
| 1680 | /* Check the validity of the new context. */ | 1703 | /* Check the validity of the new context. */ |
| 1681 | if (!policydb_context_isvalid(args->newp, c)) { | 1704 | if (!policydb_context_isvalid(args->newp, c)) { |
| @@ -1771,9 +1794,17 @@ int security_load_policy(void *data, size_t len) | |||
| 1771 | if (policydb_read(&newpolicydb, fp)) | 1794 | if (policydb_read(&newpolicydb, fp)) |
| 1772 | return -EINVAL; | 1795 | return -EINVAL; |
| 1773 | 1796 | ||
| 1774 | if (sidtab_init(&newsidtab)) { | 1797 | /* If switching between different policy types, log MLS status */ |
| 1798 | if (policydb.mls_enabled && !newpolicydb.mls_enabled) | ||
| 1799 | printk(KERN_INFO "SELinux: Disabling MLS support...\n"); | ||
| 1800 | else if (!policydb.mls_enabled && newpolicydb.mls_enabled) | ||
| 1801 | printk(KERN_INFO "SELinux: Enabling MLS support...\n"); | ||
| 1802 | |||
| 1803 | rc = policydb_load_isids(&newpolicydb, &newsidtab); | ||
| 1804 | if (rc) { | ||
| 1805 | printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); | ||
| 1775 | policydb_destroy(&newpolicydb); | 1806 | policydb_destroy(&newpolicydb); |
| 1776 | return -ENOMEM; | 1807 | return rc; |
| 1777 | } | 1808 | } |
| 1778 | 1809 | ||
| 1779 | if (selinux_set_mapping(&newpolicydb, secclass_map, | 1810 | if (selinux_set_mapping(&newpolicydb, secclass_map, |
| @@ -1800,8 +1831,12 @@ int security_load_policy(void *data, size_t len) | |||
| 1800 | args.oldp = &policydb; | 1831 | args.oldp = &policydb; |
| 1801 | args.newp = &newpolicydb; | 1832 | args.newp = &newpolicydb; |
| 1802 | rc = sidtab_map(&newsidtab, convert_context, &args); | 1833 | rc = sidtab_map(&newsidtab, convert_context, &args); |
| 1803 | if (rc) | 1834 | if (rc) { |
| 1835 | printk(KERN_ERR "SELinux: unable to convert the internal" | ||
| 1836 | " representation of contexts in the new SID" | ||
| 1837 | " table\n"); | ||
| 1804 | goto err; | 1838 | goto err; |
| 1839 | } | ||
| 1805 | 1840 | ||
| 1806 | /* Save the old policydb and SID table to free later. */ | 1841 | /* Save the old policydb and SID table to free later. */ |
| 1807 | memcpy(&oldpolicydb, &policydb, sizeof policydb); | 1842 | memcpy(&oldpolicydb, &policydb, sizeof policydb); |
| @@ -2397,7 +2432,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) | |||
| 2397 | u32 len; | 2432 | u32 len; |
| 2398 | int rc = 0; | 2433 | int rc = 0; |
| 2399 | 2434 | ||
| 2400 | if (!ss_initialized || !selinux_mls_enabled) { | 2435 | if (!ss_initialized || !policydb.mls_enabled) { |
| 2401 | *new_sid = sid; | 2436 | *new_sid = sid; |
| 2402 | goto out; | 2437 | goto out; |
| 2403 | } | 2438 | } |
| @@ -2498,7 +2533,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, | |||
| 2498 | /* we don't need to check ss_initialized here since the only way both | 2533 | /* we don't need to check ss_initialized here since the only way both |
| 2499 | * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the | 2534 | * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the |
| 2500 | * security server was initialized and ss_initialized was true */ | 2535 | * security server was initialized and ss_initialized was true */ |
| 2501 | if (!selinux_mls_enabled) { | 2536 | if (!policydb.mls_enabled) { |
| 2502 | *peer_sid = SECSID_NULL; | 2537 | *peer_sid = SECSID_NULL; |
| 2503 | return 0; | 2538 | return 0; |
| 2504 | } | 2539 | } |
| @@ -2555,7 +2590,7 @@ int security_get_classes(char ***classes, int *nclasses) | |||
| 2555 | read_lock(&policy_rwlock); | 2590 | read_lock(&policy_rwlock); |
| 2556 | 2591 | ||
| 2557 | *nclasses = policydb.p_classes.nprim; | 2592 | *nclasses = policydb.p_classes.nprim; |
| 2558 | *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC); | 2593 | *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); |
| 2559 | if (!*classes) | 2594 | if (!*classes) |
| 2560 | goto out; | 2595 | goto out; |
| 2561 | 2596 | ||
| @@ -2602,7 +2637,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms) | |||
| 2602 | } | 2637 | } |
| 2603 | 2638 | ||
| 2604 | *nperms = match->permissions.nprim; | 2639 | *nperms = match->permissions.nprim; |
| 2605 | *perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC); | 2640 | *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); |
| 2606 | if (!*perms) | 2641 | if (!*perms) |
| 2607 | goto out; | 2642 | goto out; |
| 2608 | 2643 | ||
