diff options
Diffstat (limited to 'security/selinux')
| -rw-r--r-- | security/selinux/avc.c | 31 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 162 | ||||
| -rw-r--r-- | security/selinux/include/initial_sid_to_string.h | 2 | ||||
| -rw-r--r-- | security/selinux/include/netlabel.h | 8 | ||||
| -rw-r--r-- | security/selinux/include/objsec.h | 1 | ||||
| -rw-r--r-- | security/selinux/include/security.h | 13 | ||||
| -rw-r--r-- | security/selinux/netif.c | 1 | ||||
| -rw-r--r-- | security/selinux/netlabel.c | 15 | ||||
| -rw-r--r-- | security/selinux/netlink.c | 2 | ||||
| -rw-r--r-- | security/selinux/netnode.c | 1 | ||||
| -rw-r--r-- | security/selinux/netport.c | 1 | ||||
| -rw-r--r-- | security/selinux/nlmsgtab.c | 1 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 56 | ||||
| -rw-r--r-- | security/selinux/ss/avtab.h | 2 | ||||
| -rw-r--r-- | security/selinux/ss/context.h | 12 | ||||
| -rw-r--r-- | security/selinux/ss/ebitmap.c | 2 | ||||
| -rw-r--r-- | security/selinux/ss/mls.c | 50 | ||||
| -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 | 134 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.h | 10 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 322 | ||||
| -rw-r--r-- | security/selinux/ss/symtab.c | 1 | ||||
| -rw-r--r-- | security/selinux/xfrm.c | 1 |
24 files changed, 422 insertions, 415 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index f2dde268165..7f1a304712a 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -337,7 +337,7 @@ static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass) * Look up an AVC entry that is valid for the * (@ssid, @tsid), interpreting the permissions * based on @tclass. If a valid AVC entry exists, - * then this function return the avc_node. + * then this function returns the avc_node. * Otherwise, this function returns NULL. */ static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass) @@ -489,21 +489,17 @@ void avc_audit(u32 ssid, u32 tsid, struct common_audit_data stack_data; u32 denied, audited; denied = requested & ~avd->allowed; - if (denied) { - audited = denied; - if (!(audited & avd->auditdeny)) - return; - } else if (result) { + if (denied) + audited = denied & avd->auditdeny; + else if (result) audited = denied = requested; - } else { - audited = requested; - if (!(audited & avd->auditallow)) - return; - } + else + audited = requested & avd->auditallow; + if (!audited) + return; if (!a) { a = &stack_data; - memset(a, 0, sizeof(*a)); - a->type = LSM_AUDIT_NO_AUDIT; + COMMON_AUDIT_DATA_INIT(a, NONE); } a->selinux_audit_data.tclass = tclass; a->selinux_audit_data.requested = requested; @@ -526,7 +522,7 @@ void avc_audit(u32 ssid, u32 tsid, * @perms: permissions * * Register a callback function for events in the set @events - * related to the SID pair (@ssid, @tsid) and + * related to the SID pair (@ssid, @tsid) * and the permissions @perms, interpreting * @perms based on @tclass. Returns %0 on success or * -%ENOMEM if insufficient memory exists to add the callback. @@ -571,7 +567,7 @@ static inline int avc_sidcmp(u32 x, u32 y) * * if a valid AVC entry doesn't exist,this function returns -ENOENT. * if kmalloc() called internal returns NULL, this function returns -ENOMEM. - * otherwise, this function update the AVC entry. The original AVC-entry object + * otherwise, this function updates the AVC entry. The original AVC-entry object * will release later by RCU. */ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, @@ -746,9 +742,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, else avd = &avd_entry; - rc = security_compute_av(ssid, tsid, tclass, requested, avd); - if (rc) - goto out; + security_compute_av(ssid, tsid, tclass, avd); rcu_read_lock(); node = avc_insert(ssid, tsid, tclass, avd); } else { @@ -770,7 +764,6 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, } rcu_read_unlock(); -out: return rc; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9a2ee845e9d..5c9f25ba1c9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -76,6 +76,7 @@ #include <linux/selinux.h> #include <linux/mutex.h> #include <linux/posix-timers.h> +#include <linux/syslog.h> #include "avc.h" #include "objsec.h" @@ -125,18 +126,6 @@ __setup("selinux=", selinux_enabled_setup); int selinux_enabled = 1; #endif - -/* - * Minimal support for a secondary security module, - * just to allow the use of the capability module. - */ -static struct security_operations *secondary_ops; - -/* Lists of inode and superblock security structures initialized - before the policy was loaded. */ -static LIST_HEAD(superblock_security_head); -static DEFINE_SPINLOCK(sb_security_lock); - static struct kmem_cache *sel_inode_cache; /** @@ -272,7 +261,6 @@ static int superblock_alloc_security(struct super_block *sb) return -ENOMEM; mutex_init(&sbsec->lock); - INIT_LIST_HEAD(&sbsec->list); INIT_LIST_HEAD(&sbsec->isec_head); spin_lock_init(&sbsec->isec_lock); sbsec->sb = sb; @@ -287,40 +275,34 @@ static int superblock_alloc_security(struct super_block *sb) static void superblock_free_security(struct super_block *sb) { struct superblock_security_struct *sbsec = sb->s_security; - - spin_lock(&sb_security_lock); - if (!list_empty(&sbsec->list)) - list_del_init(&sbsec->list); - spin_unlock(&sb_security_lock); - sb->s_security = NULL; kfree(sbsec); } static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) { - struct sk_security_struct *ssec; + struct sk_security_struct *sksec; - ssec = kzalloc(sizeof(*ssec), priority); - if (!ssec) + sksec = kzalloc(sizeof(*sksec), priority); + if (!sksec) return -ENOMEM; - ssec->peer_sid = SECINITSID_UNLABELED; - ssec->sid = SECINITSID_UNLABELED; - sk->sk_security = ssec; + sksec->peer_sid = SECINITSID_UNLABELED; + sksec->sid = SECINITSID_UNLABELED; + sk->sk_security = sksec; - selinux_netlbl_sk_security_reset(ssec); + selinux_netlbl_sk_security_reset(sksec); return 0; } static void sk_free_security(struct sock *sk) { - struct sk_security_struct *ssec = sk->sk_security; + struct sk_security_struct *sksec = sk->sk_security; sk->sk_security = NULL; - selinux_netlbl_sk_security_free(ssec); - kfree(ssec); + selinux_netlbl_sk_security_free(sksec); + kfree(sksec); } /* The security server must be initialized before @@ -329,7 +311,7 @@ extern int ss_initialized; /* The file system's label must be initialized prior to use. */ -static char *labeling_behaviors[6] = { +static const char *labeling_behaviors[6] = { "uses xattr", "uses transition SIDs", "uses task SIDs", @@ -618,10 +600,6 @@ static int selinux_set_mnt_opts(struct super_block *sb, /* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security server is ready to handle calls. */ - spin_lock(&sb_security_lock); - if (list_empty(&sbsec->list)) - list_add(&sbsec->list, &superblock_security_head); - spin_unlock(&sb_security_lock); goto out; } rc = -EINVAL; @@ -812,16 +790,10 @@ static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, /* * if the parent was able to be mounted it clearly had no special lsm - * mount options. thus we can safely put this sb on the list and deal - * with it later + * mount options. thus we can safely deal with this superblock later */ - if (!ss_initialized) { - spin_lock(&sb_security_lock); - if (list_empty(&newsbsec->list)) - list_add(&newsbsec->list, &superblock_security_head); - spin_unlock(&sb_security_lock); + if (!ss_initialized) return; - } /* how can we clone if the old one wasn't set up?? */ BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); @@ -2049,29 +2021,30 @@ static int selinux_quota_on(struct dentry *dentry) return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); } -static int selinux_syslog(int type) +static int selinux_syslog(int type, bool from_file) { int rc; - rc = cap_syslog(type); + rc = cap_syslog(type, from_file); if (rc) return rc; switch (type) { - case 3: /* Read last kernel messages */ - case 10: /* Return size of the log buffer */ + case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ + case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ rc = task_has_system(current, SYSTEM__SYSLOG_READ); break; - case 6: /* Disable logging to console */ - case 7: /* Enable logging to console */ - case 8: /* Set level of messages printed to console */ + case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ + case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ + /* Set level of messages printed to console */ + case SYSLOG_ACTION_CONSOLE_LEVEL: rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); break; - case 0: /* Close log */ - case 1: /* Open log */ - case 2: /* Read from log */ - case 4: /* Read/clear last kernel messages */ - case 5: /* Clear ring buffer */ + case SYSLOG_ACTION_CLOSE: /* Close log */ + case SYSLOG_ACTION_OPEN: /* Open log */ + case SYSLOG_ACTION_READ: /* Read from log */ + case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */ + case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */ default: rc = task_has_system(current, SYSTEM__SYSLOG_MOD); break; @@ -3004,13 +2977,15 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, return file_has_perm(cred, file, av); } +static int default_noexec; + static int file_map_prot_check(struct file *file, unsigned long prot, int shared) { const struct cred *cred = current_cred(); int rc = 0; -#ifndef CONFIG_PPC32 - if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { + if (default_noexec && + (prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { /* * We are making executable an anonymous mapping or a * private file mapping that will also be writable. @@ -3020,7 +2995,6 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared if (rc) goto error; } -#endif if (file) { /* read access is always possible with a mapping */ @@ -3081,8 +3055,8 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, if (selinux_checkreqprot) prot = reqprot; -#ifndef CONFIG_PPC32 - if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { + if (default_noexec && + (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { int rc = 0; if (vma->vm_start >= vma->vm_mm->start_brk && vma->vm_end <= vma->vm_mm->brk) { @@ -3104,7 +3078,6 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, if (rc) return rc; } -#endif return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); } @@ -3334,7 +3307,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) if (ret == 0) tsec->create_sid = isec->sid; - return 0; + return ret; } static int selinux_kernel_module_request(char *kmod_name) @@ -4007,7 +3980,7 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, struct socket *other, struct sock *newsk) { - struct sk_security_struct *ssec; + struct sk_security_struct *sksec; struct inode_security_struct *isec; struct inode_security_struct *other_isec; struct common_audit_data ad; @@ -4026,13 +3999,13 @@ static int selinux_socket_unix_stream_connect(struct socket *sock, return err; /* connecting socket */ - ssec = sock->sk->sk_security; - ssec->peer_sid = other_isec->sid; + sksec = sock->sk->sk_security; + sksec->peer_sid = other_isec->sid; /* server child socket */ - ssec = newsk->sk_security; - ssec->peer_sid = isec->sid; - err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid); + sksec = newsk->sk_security; + sksec->peer_sid = isec->sid; + err = security_sid_mls_copy(other_isec->sid, sksec->peer_sid, &sksec->sid); return err; } @@ -4195,7 +4168,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op int err = 0; char *scontext; u32 scontext_len; - struct sk_security_struct *ssec; + struct sk_security_struct *sksec; struct inode_security_struct *isec; u32 peer_sid = SECSID_NULL; @@ -4203,8 +4176,8 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET || isec->sclass == SECCLASS_TCP_SOCKET) { - ssec = sock->sk->sk_security; - peer_sid = ssec->peer_sid; + sksec = sock->sk->sk_security; + peer_sid = sksec->peer_sid; } if (peer_sid == SECSID_NULL) { err = -ENOPROTOOPT; @@ -4271,14 +4244,14 @@ static void selinux_sk_free_security(struct sock *sk) static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) { - struct sk_security_struct *ssec = sk->sk_security; - struct sk_security_struct *newssec = newsk->sk_security; + struct sk_security_struct *sksec = sk->sk_security; + struct sk_security_struct *newsksec = newsk->sk_security; - newssec->sid = ssec->sid; - newssec->peer_sid = ssec->peer_sid; - newssec->sclass = ssec->sclass; + newsksec->sid = sksec->sid; + newsksec->peer_sid = sksec->peer_sid; + newsksec->sclass = sksec->sclass; - selinux_netlbl_sk_security_reset(newssec); + selinux_netlbl_sk_security_reset(newsksec); } static void selinux_sk_getsecid(struct sock *sk, u32 *secid) @@ -5667,14 +5640,13 @@ static __init int selinux_init(void) /* Set the security state for the initial task. */ cred_init_security(); + default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC); + sel_inode_cache = kmem_cache_create("selinux_inode_security", sizeof(struct inode_security_struct), 0, SLAB_PANIC, NULL); avc_init(); - secondary_ops = security_ops; - if (!secondary_ops) - panic("SELinux: No initial security operations\n"); if (register_security(&selinux_ops)) panic("SELinux: Unable to register with kernel.\n"); @@ -5686,35 +5658,18 @@ static __init int selinux_init(void) return 0; } +static void delayed_superblock_init(struct super_block *sb, void *unused) +{ + superblock_doinit(sb, NULL); +} + void selinux_complete_init(void) { printk(KERN_DEBUG "SELinux: Completing initialization.\n"); /* Set up any superblocks initialized prior to the policy load. */ printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n"); - spin_lock(&sb_lock); - spin_lock(&sb_security_lock); -next_sb: - if (!list_empty(&superblock_security_head)) { - struct superblock_security_struct *sbsec = - list_entry(superblock_security_head.next, - struct superblock_security_struct, - list); - struct super_block *sb = sbsec->sb; - sb->s_count++; - spin_unlock(&sb_security_lock); - spin_unlock(&sb_lock); - down_read(&sb->s_umount); - if (sb->s_root) - superblock_doinit(sb, NULL); - drop_super(sb); - spin_lock(&sb_lock); - spin_lock(&sb_security_lock); - list_del_init(&sbsec->list); - goto next_sb; - } - spin_unlock(&sb_security_lock); - spin_unlock(&sb_lock); + iterate_supers(delayed_superblock_init, NULL); } /* SELinux requires early initialization in order to label @@ -5835,8 +5790,7 @@ int selinux_disable(void) selinux_disabled = 1; selinux_enabled = 0; - /* Reset security_ops to the secondary module, dummy or capability. */ - security_ops = secondary_ops; + reset_security_ops(); /* Try to destroy the avc node cache */ avc_disable(); diff --git a/security/selinux/include/initial_sid_to_string.h b/security/selinux/include/initial_sid_to_string.h index d4fac82793a..a59b64e3fd0 100644 --- a/security/selinux/include/initial_sid_to_string.h +++ b/security/selinux/include/initial_sid_to_string.h @@ -1,5 +1,5 @@ /* This file is automatically generated. Do not edit. */ -static char *initial_sid_to_string[] = +static const char *initial_sid_to_string[] = { "null", "kernel", diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 8d7384280a7..cf2f628e6e2 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -42,8 +42,8 @@ void selinux_netlbl_cache_invalidate(void); void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway); -void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec); -void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec); +void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec); +void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec); int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u16 family, @@ -79,13 +79,13 @@ static inline void selinux_netlbl_err(struct sk_buff *skb, } static inline void selinux_netlbl_sk_security_free( - struct sk_security_struct *ssec) + struct sk_security_struct *sksec) { return; } static inline void selinux_netlbl_sk_security_reset( - struct sk_security_struct *ssec) + struct sk_security_struct *sksec) { return; } diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index c4e062336ef..26c7eee1c30 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -55,7 +55,6 @@ struct file_security_struct { struct superblock_security_struct { struct super_block *sb; /* back pointer to sb object */ - struct list_head list; /* list of superblock_security_struct */ u32 sid; /* SID of file system superblock */ u32 def_sid; /* default SID for labeling */ u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 2553266ad79..1f7c2491d3d 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -57,7 +57,6 @@ struct netlbl_lsm_secattr; extern int selinux_enabled; -extern int selinux_mls_enabled; /* Policy capabilities */ enum { @@ -80,6 +79,8 @@ extern int selinux_policycap_openperm; /* limitation of boundary depth */ #define POLICYDB_BOUNDS_MAXDEPTH 4 +int security_mls_enabled(void); + int security_load_policy(void *data, size_t len); int security_policycap_supported(unsigned int req_cap); @@ -96,13 +97,11 @@ struct av_decision { /* definitions of av_decision.flags */ #define AVD_FLAGS_PERMISSIVE 0x0001 -int security_compute_av(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct av_decision *avd); +void security_compute_av(u32 ssid, u32 tsid, + u16 tclass, struct av_decision *avd); -int security_compute_av_user(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct av_decision *avd); +void security_compute_av_user(u32 ssid, u32 tsid, + u16 tclass, struct av_decision *avd); int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid); diff --git a/security/selinux/netif.c b/security/selinux/netif.c index b4e14bc0bf3..d6095d63d83 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -16,6 +16,7 @@ */ #include <linux/init.h> #include <linux/types.h> +#include <linux/slab.h> #include <linux/stddef.h> #include <linux/kernel.h> #include <linux/list.h> diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index 2534400317c..1c2fc46544b 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -29,6 +29,7 @@ #include <linux/spinlock.h> #include <linux/rcupdate.h> +#include <linux/gfp.h> #include <linux/ip.h> #include <linux/ipv6.h> #include <net/sock.h> @@ -131,21 +132,21 @@ void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway) /** * selinux_netlbl_sk_security_free - Free the NetLabel fields - * @sssec: the sk_security_struct + * @sksec: the sk_security_struct * * Description: * Free all of the memory in the NetLabel fields of a sk_security_struct. * */ -void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) +void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec) { - if (ssec->nlbl_secattr != NULL) - netlbl_secattr_free(ssec->nlbl_secattr); + if (sksec->nlbl_secattr != NULL) + netlbl_secattr_free(sksec->nlbl_secattr); } /** * selinux_netlbl_sk_security_reset - Reset the NetLabel fields - * @ssec: the sk_security_struct + * @sksec: the sk_security_struct * @family: the socket family * * Description: @@ -153,9 +154,9 @@ void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) * The caller is responsibile for all the NetLabel sk_security_struct locking. * */ -void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec) +void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec) { - ssec->nlbl_state = NLBL_UNSET; + sksec->nlbl_state = NLBL_UNSET; } /** diff --git a/security/selinux/netlink.c b/security/selinux/netlink.c index 1ae556446e6..36ac257cec9 100644 --- a/security/selinux/netlink.c +++ b/security/selinux/netlink.c @@ -11,9 +11,9 @@ */ #include <linux/init.h> #include <linux/types.h> +#include <linux/slab.h> #include <linux/stddef.h> #include <linux/kernel.h> -#include <linux/list.h> #include <linux/skbuff.h> #include <linux/netlink.h> #include <linux/selinux_netlink.h> diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 7100072bb1b..dc92792271f 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c @@ -31,6 +31,7 @@ #include <linux/types.h> #include <linux/rcupdate.h> #include <linux/list.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <linux/in.h> #include <linux/in6.h> diff --git a/security/selinux/netport.c b/security/selinux/netport.c index fe7fba67f19..cfe2d72d3fb 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c @@ -30,6 +30,7 @@ #include <linux/types.h> #include <linux/rcupdate.h> #include <linux/list.h> +#include <linux/slab.h> #include <linux/spinlock.h> #include <linux/in.h> #include <linux/in6.h> diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index dd7cc6de77f..75ec0c6ebac 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c @@ -11,7 +11,6 @@ */ #include <linux/types.h> #include <linux/kernel.h> -#include <linux/skbuff.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #include <linux/if.h> diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index fab36fdf276..0293843f7ed 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, char tmpbuf[TMPBUFLEN]; ssize_t length; - length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled); + length = scnprintf(tmpbuf, TMPBUFLEN, "%d", + security_mls_enabled()); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } @@ -494,7 +495,6 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) char *scon, *tcon; u32 ssid, tsid; u16 tclass; - u32 req; struct av_decision avd; ssize_t length; @@ -503,28 +503,26 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) return length; length = -ENOMEM; - scon = kzalloc(size+1, GFP_KERNEL); + scon = kzalloc(size + 1, GFP_KERNEL); if (!scon) return length; - tcon = kzalloc(size+1, GFP_KERNEL); + tcon = kzalloc(size + 1, GFP_KERNEL); if (!tcon) goto out; length = -EINVAL; - if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4) + if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out2; - length = security_context_to_sid(scon, strlen(scon)+1, &ssid); + length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); if (length < 0) goto out2; - length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); + length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); if (length < 0) goto out2; - length = security_compute_av_user(ssid, tsid, tclass, req, &avd); - if (length < 0) - goto out2; + security_compute_av_user(ssid, tsid, tclass, &avd); length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%x %x %x %x %u %x", @@ -552,11 +550,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) return length; length = -ENOMEM; - scon = kzalloc(size+1, GFP_KERNEL); + scon = kzalloc(size + 1, GFP_KERNEL); if (!scon) return length; - tcon = kzalloc(size+1, GFP_KERNEL); + tcon = kzalloc(size + 1, GFP_KERNEL); if (!tcon) goto out; @@ -564,10 +562,10 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out2; - length = security_context_to_sid(scon, strlen(scon)+1, &ssid); + length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); if (length < 0) goto out2; - length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); + length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); if (length < 0) goto out2; @@ -611,11 +609,11 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) return length; length = -ENOMEM; - scon = kzalloc(size+1, GFP_KERNEL); + scon = kzalloc(size + 1, GFP_KERNEL); if (!scon) return length; - tcon = kzalloc(size+1, GFP_KERNEL); + tcon = kzalloc(size + 1, GFP_KERNEL); if (!tcon) goto out; @@ -623,10 +621,10 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out2; - length = security_context_to_sid(scon, strlen(scon)+1, &ssid); + length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); if (length < 0) goto out2; - length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); + length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); if (length < 0) goto out2; @@ -668,11 +666,11 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) return length; length = -ENOMEM; - con = kzalloc(size+1, GFP_KERNEL); + con = kzalloc(size + 1, GFP_KERNEL); if (!con) return length; - user = kzalloc(size+1, GFP_KERNEL); + user = kzalloc(size + 1, GFP_KERNEL); if (!user) goto out; @@ -680,7 +678,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) if (sscanf(buf, "%s %s", con, user) != 2) goto out2; - length = security_context_to_sid(con, strlen(con)+1, &sid); + length = security_context_to_sid(con, strlen(con) + 1, &sid); if (length < 0) goto out2; @@ -729,11 +727,11 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) return length; length = -ENOMEM; - scon = kzalloc(size+1, GFP_KERNEL); + scon = kzalloc(size + 1, GFP_KERNEL); if (!scon) return length; - tcon = kzalloc(size+1, GFP_KERNEL); + tcon = kzalloc(size + 1, GFP_KERNEL); if (!tcon) goto out; @@ -741,10 +739,10 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out2; - length = security_context_to_sid(scon, strlen(scon)+1, &ssid); + length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); if (length < 0) goto out2; - length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); + length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); if (length < 0) goto out2; @@ -979,6 +977,8 @@ static int sel_make_bools(void) u32 sid; /* remove any existing files */ + for (i = 0; i < bool_num; i++) + kfree(bool_pending_names[i]); kfree(bool_pending_names); kfree(bool_pending_values); bool_pending_names = NULL; @@ -1401,7 +1401,7 @@ static int sel_make_perm_files(char *objclass, int classvalue, } inode->i_fop = &sel_perm_ops; /* i+1 since perm values are 1-indexed */ - inode->i_ino = sel_perm_to_ino(classvalue, i+1); + inode->i_ino = sel_perm_to_ino(classvalue, i + 1); d_add(dentry, inode); } @@ -1489,7 +1489,7 @@ static int sel_make_classes(void) goto out; /* +2 since classes are 1-indexed */ - last_class_ino = sel_class_to_ino(nclasses+2); + last_class_ino = sel_class_to_ino(nclasses + 2); for (i = 0; i < nclasses; i++) { struct dentry *class_name_dir; @@ -1506,7 +1506,7 @@ static int sel_make_classes(void) goto out1; /* i+1 since class values are 1-indexed */ - rc = sel_make_class_dir_entries(classes[i], i+1, + rc = sel_make_class_dir_entries(classes[i], i + 1, class_name_dir); if (rc) goto out1; diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index 8da6a842808..cd4f734e274 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -82,7 +82,7 @@ struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified void avtab_cache_init(void); void avtab_cache_destroy(void); -#define MAX_AVTAB_HASH_BITS 13 +#define MAX_AVTAB_HASH_BITS 11 #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) #define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1) #define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index d9dd7a2f6a8..45e8fb0515f 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) { int rc; - if (!selinux_mls_enabled) - return 0; - dst->range.level[0].sens = src->range.level[0].sens; rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); if (rc) @@ -64,9 +61,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src) { int rc; - if (!selinux_mls_enabled) - return 0; - dst->range.level[0].sens = src->range.level[0].sens; rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); if (rc) @@ -82,9 +76,6 @@ out: static inline int mls_context_cmp(struct context *c1, struct context *c2) { - if (!selinux_mls_enabled) - return 1; - return ((c1->range.level[0].sens == c2->range.level[0].sens) && ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && (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) static inline void mls_context_destroy(struct context *c) { - if (!selinux_mls_enabled) - return; - ebitmap_destroy(&c->range.level[0].cat); ebitmap_destroy(&c->range.level[1].cat); mls_context_init(c); diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 68c7348d1ac..04b6145d767 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -128,7 +128,7 @@ int ebitmap_netlbl_export(struct ebitmap *ebmap, cmap_idx = delta / NETLBL_CATMAP_MAPSIZE; cmap_sft = delta % NETLBL_CATMAP_MAPSIZE; c_iter->bitmap[cmap_idx] - |= e_iter->maps[cmap_idx] << cmap_sft; + |= e_iter->maps[i] << cmap_sft; } e_iter = e_iter->next; } diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 3f2b2706b5b..b4eff7a60c5 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) struct ebitmap *e; struct ebitmap_node *node; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; len = 1; /* for the beginning ":" */ @@ -93,7 +93,7 @@ void mls_sid_to_context(struct context *context, struct ebitmap *e; struct ebitmap_node *node; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return; scontextp = *scontext; @@ -200,7 +200,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c) { struct user_datum *usrdatum; - if (!selinux_mls_enabled) + if (!p->mls_enabled) return 1; if (!mls_range_isvalid(p, &c->range)) @@ -253,9 +253,9 @@ int mls_context_to_sid(struct policydb *pol, struct cat_datum *catdatum, *rngdatum; int l, rc = -EINVAL; - if (!selinux_mls_enabled) { + if (!pol->mls_enabled) { if (def_sid != SECSID_NULL && oldc) - *scontext += strlen(*scontext)+1; + *scontext += strlen(*scontext) + 1; return 0; } @@ -387,7 +387,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) char *tmpstr, *freestr; int rc; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return -EINVAL; /* 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) /* * Copies the MLS range `range' into `context'. */ -static inline int mls_range_set(struct context *context, +int mls_range_set(struct context *context, struct mls_range *range) { int l, rc = 0; @@ -427,7 +427,7 @@ static inline int mls_range_set(struct context *context, int mls_setup_user_range(struct context *fromcon, struct user_datum *user, struct context *usercon) { - if (selinux_mls_enabled) { + if (policydb.mls_enabled) { struct mls_level *fromcon_sen = &(fromcon->range.level[0]); struct mls_level *fromcon_clr = &(fromcon->range.level[1]); struct mls_level *user_low = &(user->range.level[0]); @@ -477,7 +477,7 @@ int mls_convert_context(struct policydb *oldp, struct ebitmap_node *node; int l, i; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; for (l = 0; l < 2; l++) { @@ -513,23 +513,21 @@ int mls_compute_sid(struct context *scontext, u32 specified, struct context *newcontext) { - struct range_trans *rtr; + struct range_trans rtr; + struct mls_range *r; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; switch (specified) { case AVTAB_TRANSITION: /* Look for a range transition rule. */ - for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { - if (rtr->source_type == scontext->type && - rtr->target_type == tcontext->type && - rtr->target_class == tclass) { - /* Set the range from the rule */ - return mls_range_set(newcontext, - &rtr->target_range); - } - } + rtr.source_type = scontext->type; + rtr.target_type = tcontext->type; + rtr.target_class = tclass; + r = hashtab_search(policydb.range_tr, &rtr); + if (r) + return mls_range_set(newcontext, r); /* Fallthrough */ case AVTAB_CHANGE: if (tclass == policydb.process_class) @@ -541,8 +539,8 @@ int mls_compute_sid(struct context *scontext, case AVTAB_MEMBER: /* Use the process effective MLS attributes. */ return mls_context_cpy_low(newcontext, scontext); - default: - return -EINVAL; + + /* fall through */ } return -EINVAL; } @@ -561,7 +559,7 @@ int mls_compute_sid(struct context *scontext, void mls_export_netlbl_lvl(struct context *context, struct netlbl_lsm_secattr *secattr) { - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return; secattr->attr.mls.lvl = context->range.level[0].sens - 1; @@ -581,7 +579,7 @@ void mls_export_netlbl_lvl(struct context *context, void mls_import_netlbl_lvl(struct context *context, struct netlbl_lsm_secattr *secattr) { - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return; context->range.level[0].sens = secattr->attr.mls.lvl + 1; @@ -603,7 +601,7 @@ int mls_export_netlbl_cat(struct context *context, { int rc; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; rc = ebitmap_netlbl_export(&context->range.level[0].cat, @@ -631,7 +629,7 @@ int mls_import_netlbl_cat(struct context *context, { int rc; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; rc = ebitmap_netlbl_import(&context->range.level[0].cat, diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 1276715aaa8..cd9152632e5 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, int mls_from_string(char *str, struct context *context, gfp_t gfp_mask); +int mls_range_set(struct context *context, struct mls_range *range); + int mls_convert_context(struct policydb *oldp, struct policydb *newp, struct context *context); diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index b6e943a2106..03bed52a805 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h @@ -15,6 +15,7 @@ #define _SS_MLS_TYPES_H_ #include "security.h" +#include "ebitmap.h" struct mls_level { u32 sens; /* sensitivity */ @@ -27,18 +28,12 @@ struct mls_range { static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) { - if (!selinux_mls_enabled) - return 1; - return ((l1->sens == l2->sens) && ebitmap_cmp(&l1->cat, &l2->cat)); } static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) { - if (!selinux_mls_enabled) - return 1; - return ((l1->sens >= l2->sens) && ebitmap_contains(&l1->cat, &l2->cat)); } diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f03667213ea..c57802a164d 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -40,7 +40,7 @@ #define _DEBUG_HASHES #ifdef DEBUG_HASHES -static char *symtab_name[SYM_NUM] = { +static const char *symtab_name[SYM_NUM] = { "common prefixes", "classes", "roles", @@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = { }; #endif -int selinux_mls_enabled; - static unsigned int symtab_sizes[SYM_NUM] = { 2, 32, @@ -158,12 +156,11 @@ static int roles_init(struct policydb *p) rc = -EINVAL; goto out_free_role; } - key = kmalloc(strlen(OBJECT_R)+1, GFP_KERNEL); + key = kstrdup(OBJECT_R, GFP_KERNEL); if (!key) { rc = -ENOMEM; goto out_free_role; } - strcpy(key, OBJECT_R); rc = hashtab_insert(p->p_roles.table, key, role); if (rc) goto out_free_key; @@ -177,6 +174,21 @@ out_free_role: goto out; } +static u32 rangetr_hash(struct hashtab *h, const void *k) +{ + const struct range_trans *key = k; + return (key->source_type + (key->target_type << 3) + + (key->target_class << 5)) & (h->size - 1); +} + +static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) +{ + const struct range_trans *key1 = k1, *key2 = k2; + return (key1->source_type != key2->source_type || + key1->target_type != key2->target_type || + key1->target_class != key2->target_class); +} + /* * Initialize a policy database structure. */ @@ -204,6 +216,10 @@ static int policydb_init(struct policydb *p) if (rc) goto out_free_symtab; + p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); + if (!p->range_tr) + goto out_free_symtab; + ebitmap_init(&p->policycaps); ebitmap_init(&p->permissive_map); @@ -408,6 +424,20 @@ static void symtab_hash_eval(struct symtab *s) info.slots_used, h->size, info.max_chain_len); } } + +static void rangetr_hash_eval(struct hashtab *h) +{ + struct hashtab_info info; + + hashtab_stat(h, &info); + printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " + "longest chain length %d\n", h->nel, + info.slots_used, h->size, info.max_chain_len); +} +#else +static inline void rangetr_hash_eval(struct hashtab *h) +{ +} #endif /* @@ -422,7 +452,7 @@ static int policydb_index_others(struct policydb *p) printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); - if (selinux_mls_enabled) + if (p->mls_enabled) printk(", %d sens, %d cats", p->p_levels.nprim, p->p_cats.nprim); printk("\n"); @@ -612,6 +642,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = cat_destroy, }; +static int range_tr_destroy(void *key, void *datum, void *p) +{ + struct mls_range *rt = datum; + kfree(key); + ebitmap_destroy(&rt->level[0].cat); + ebitmap_destroy(&rt->level[1].cat); + kfree(datum); + cond_resched(); + return 0; +} + static void ocontext_destroy(struct ocontext *c, int i) { context_destroy(&c->context[0]); @@ -632,7 +673,6 @@ void policydb_destroy(struct policydb *p) int i; struct role_allow *ra, *lra = NULL; struct role_trans *tr, *ltr = NULL; - struct range_trans *rt, *lrt = NULL; for (i = 0; i < SYM_NUM; i++) { cond_resched(); @@ -693,20 +733,8 @@ void policydb_destroy(struct policydb *p) } kfree(lra); - for (rt = p->range_tr; rt; rt = rt->next) { - cond_resched(); - if (lrt) { - ebitmap_destroy(&lrt->target_range.level[0].cat); - ebitmap_destroy(&lrt->target_range.level[1].cat); - kfree(lrt); - } - lrt = rt; - } - if (lrt) { - ebitmap_destroy(&lrt->target_range.level[0].cat); - ebitmap_destroy(&lrt->target_range.level[1].cat); - kfree(lrt); - } + hashtab_map(p->range_tr, range_tr_destroy, NULL); + hashtab_destroy(p->range_tr); if (p->type_attr_map) { for (i = 0; i < p->p_types.nprim; i++) @@ -1686,12 +1714,11 @@ int policydb_read(struct policydb *p, void *fp) int i, j, rc; __le32 buf[4]; u32 nodebuf[8]; - u32 len, len2, config, nprim, nel, nel2; + u32 len, len2, nprim, nel, nel2; char *policydb_str; struct policydb_compat_info *info; - struct range_trans *rt, *lrt; - - config = 0; + struct range_trans *rt; + struct mls_range *r; rc = policydb_init(p); if (rc) @@ -1740,7 +1767,7 @@ int policydb_read(struct policydb *p, void *fp) kfree(policydb_str); policydb_str = NULL; - /* Read the version, config, and table sizes. */ + /* Read the version and table sizes. */ rc = next_entry(buf, fp, sizeof(u32)*4); if (rc < 0) goto bad; @@ -1755,13 +1782,7 @@ int policydb_read(struct policydb *p, void *fp) } if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { - if (ss_initialized && !selinux_mls_enabled) { - printk(KERN_ERR "SELinux: Cannot switch between non-MLS" - " and MLS policies\n"); - goto bad; - } - selinux_mls_enabled = 1; - config |= POLICYDB_CONFIG_MLS; + p->mls_enabled = 1; if (p->policyvers < POLICYDB_VERSION_MLS) { printk(KERN_ERR "SELinux: security policydb version %d " @@ -1769,12 +1790,6 @@ int policydb_read(struct policydb *p, void *fp) p->policyvers); goto bad; } - } else { - if (ss_initialized && selinux_mls_enabled) { - printk(KERN_ERR "SELinux: Cannot switch between MLS and" - " non-MLS policies\n"); - goto bad; - } } p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); @@ -2122,47 +2137,64 @@ int policydb_read(struct policydb *p, void *fp) if (rc < 0) goto bad; nel = le32_to_cpu(buf[0]); - lrt = NULL; for (i = 0; i < nel; i++) { rt = kzalloc(sizeof(*rt), GFP_KERNEL); if (!rt) { rc = -ENOMEM; goto bad; } - if (lrt) - lrt->next = rt; - else - p->range_tr = rt; rc = next_entry(buf, fp, (sizeof(u32) * 2)); - if (rc < 0) + if (rc < 0) { + kfree(rt); goto bad; + } rt->source_type = le32_to_cpu(buf[0]); rt->target_type = le32_to_cpu(buf[1]); if (new_rangetr) { rc = next_entry(buf, fp, sizeof(u32)); - if (rc < 0) + if (rc < 0) { + kfree(rt); goto bad; + } rt->target_class = le32_to_cpu(buf[0]); } else rt->target_class = p->process_class; if (!policydb_type_isvalid(p, rt->source_type) || !policydb_type_isvalid(p, rt->target_type) || !policydb_class_isvalid(p, rt->target_class)) { + kfree(rt); rc = -EINVAL; goto bad; } - rc = mls_read_range_helper(&rt->target_range, fp); - if (rc) + r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) { + kfree(rt); + rc = -ENOMEM; goto bad; - if (!mls_range_isvalid(p, &rt->target_range)) { + } + rc = mls_read_range_helper(r, fp); + if (rc) { + kfree(rt); + kfree(r); + goto bad; + } + if (!mls_range_isvalid(p, r)) { printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); + kfree(rt); + kfree(r); + goto bad; + } + rc = hashtab_insert(p->range_tr, rt, r); + if (rc) { + kfree(rt); + kfree(r); goto bad; } - lrt = rt; } + rangetr_hash_eval(p->range_tr); } - p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); + p->type_attr_map = kmalloc(p->p_types.nprim * sizeof(struct ebitmap), GFP_KERNEL); if (!p->type_attr_map) goto bad; diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index cdcc5700946..26d9adf8542 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -27,6 +27,8 @@ #include "symtab.h" #include "avtab.h" #include "sidtab.h" +#include "ebitmap.h" +#include "mls_types.h" #include "context.h" #include "constraint.h" @@ -113,8 +115,6 @@ struct range_trans { u32 source_type; u32 target_type; u32 target_class; - struct mls_range target_range; - struct range_trans *next; }; /* Boolean data type */ @@ -187,6 +187,8 @@ struct genfs { /* The policy database */ struct policydb { + int mls_enabled; + /* symbol tables */ struct symtab symtab[SYM_NUM]; #define p_commons symtab[SYM_COMMONS] @@ -240,8 +242,8 @@ struct policydb { fixed labeling behavior. */ struct genfs *genfs; - /* range transitions */ - struct range_trans *range_tr; + /* range transitions table (range_trans_key -> mls_range) */ + struct hashtab *range_tr; /* type -> attribute reverse mapping */ struct ebitmap *type_attr_map; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b3efae204ac..1de60ce90d9 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -26,6 +26,10 @@ * * Added support for bounds domain and audit messaged on masked permissions * + * Updated: Guido Trentalancia <guido@trentalancia.com> + * + * Added support for runtime switching of the policy type + * * Copyright (C) 2008, 2009 NEC Corporation * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. @@ -87,11 +91,10 @@ static u32 latest_granting; static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len); -static int context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - u32 requested, - struct av_decision *avd); +static void context_struct_compute_av(struct context *scontext, + struct context *tcontext, + u16 tclass, + struct av_decision *avd); struct selinux_mapping { u16 value; /* policy value */ @@ -196,23 +199,6 @@ static u16 unmap_class(u16 tclass) return tclass; } -static u32 unmap_perm(u16 tclass, u32 tperm) -{ - if (tclass < current_mapping_size) { - unsigned i; - u32 kperm = 0; - - for (i = 0; i < current_mapping[tclass].num_perms; i++) - if (tperm & (1<<i)) { - kperm |= current_mapping[tclass].perms[i]; - tperm &= ~(1<<i); - } - return kperm; - } - - return tperm; -} - static void map_decision(u16 tclass, struct av_decision *avd, int allow_unknown) { @@ -250,6 +236,10 @@ static void map_decision(u16 tclass, struct av_decision *avd, } } +int security_mls_enabled(void) +{ + return policydb.mls_enabled; +} /* * Return the boolean value of a constraint expression @@ -284,15 +274,15 @@ static int constraint_expr_eval(struct context *scontext, case CEXPR_AND: BUG_ON(sp < 1); sp--; - s[sp] &= s[sp+1]; + s[sp] &= s[sp + 1]; break; case CEXPR_OR: BUG_ON(sp < 1); sp--; - s[sp] |= s[sp+1]; + s[sp] |= s[sp + 1]; break; case CEXPR_ATTR: - if (sp == (CEXPR_MAXDEPTH-1)) + if (sp == (CEXPR_MAXDEPTH - 1)) return 0; switch (e->attr) { case CEXPR_USER: @@ -465,7 +455,8 @@ static void security_dump_masked_av(struct context *scontext, char *scontext_name = NULL; char *tcontext_name = NULL; char *permission_names[32]; - int index, length; + int index; + u32 length; bool need_comma = false; if (!permissions) @@ -532,7 +523,6 @@ out: static void type_attribute_bounds_av(struct context *scontext, struct context *tcontext, u16 tclass, - u32 requested, struct av_decision *avd) { struct context lo_scontext; @@ -553,7 +543,6 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(&lo_scontext, tcontext, tclass, - requested, &lo_avd); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ @@ -569,7 +558,6 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(scontext, &lo_tcontext, tclass, - requested, &lo_avd); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ @@ -586,7 +574,6 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(&lo_scontext, &lo_tcontext, tclass, - requested, &lo_avd); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ @@ -607,11 +594,10 @@ static void type_attribute_bounds_av(struct context *scontext, * Compute access vectors based on a context structure pair for * the permissions in a particular class. */ -static int context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - u32 requested, - struct av_decision *avd) +static void context_struct_compute_av(struct context *scontext, + struct context *tcontext, + u16 tclass, + struct av_decision *avd) { struct constraint_node *constraint; struct role_allow *ra; @@ -622,19 +608,14 @@ static int context_struct_compute_av(struct context *scontext, struct ebitmap_node *snode, *tnode; unsigned int i, j; - /* - * Initialize the access vectors to the default values. - */ avd->allowed = 0; avd->auditallow = 0; avd->auditdeny = 0xffffffff; - avd->seqno = latest_granting; - avd->flags = 0; if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { if (printk_ratelimit()) printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); - return -EINVAL; + return; } tclass_datum = policydb.class_val_to_struct[tclass - 1]; @@ -705,9 +686,7 @@ static int context_struct_compute_av(struct context *scontext, * permission and notice it to userspace via audit. */ type_attribute_bounds_av(scontext, tcontext, - tclass, requested, avd); - - return 0; + tclass, avd); } static int security_validtrans_handle_fail(struct context *ocontext, @@ -864,7 +843,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) if (rc) { char *old_name = NULL; char *new_name = NULL; - int length; + u32 length; if (!context_struct_to_string(old_context, &old_name, &length) && @@ -886,110 +865,116 @@ out: return rc; } - -static int security_compute_av_core(u32 ssid, - u32 tsid, - u16 tclass, - u32 requested, - struct av_decision *avd) +static void avd_init(struct av_decision *avd) { - struct context *scontext = NULL, *tcontext = NULL; - int rc = 0; - - scontext = sidtab_search(&sidtab, ssid); - if (!scontext) { - printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", - __func__, ssid); - return -EINVAL; - } - tcontext = sidtab_search(&sidtab, tsid); - if (!tcontext) { - printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", - __func__, tsid); - return -EINVAL; - } - - rc = context_struct_compute_av(scontext, tcontext, tclass, - requested, avd); - - /* permissive domain? */ - if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) - avd->flags |= AVD_FLAGS_PERMISSIVE; - - return rc; + avd->allowed = 0; + avd->auditallow = 0; + avd->auditdeny = 0xffffffff; + avd->seqno = latest_granting; + avd->flags = 0; } + /** * security_compute_av - Compute access vector decisions. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class - * @requested: requested permissions * @avd: access vector decisions * * Compute a set of access vector decisions based on the * SID pair (@ssid, @tsid) for the permissions in @tclass. - * Return -%EINVAL if any of the parameters are invalid or %0 - * if the access vector decisions were computed successfully. */ -int security_compute_av(u32 ssid, - u32 tsid, - u16 orig_tclass, - u32 orig_requested, - struct av_decision *avd) +void security_compute_av(u32 ssid, + u32 tsid, + u16 orig_tclass, + struct av_decision *avd) { u16 tclass; - u32 requested; - int rc; + struct context *scontext = NULL, *tcontext = NULL; read_lock(&policy_rwlock); - + avd_init(avd); if (!ss_initialized) goto allow; - requested = unmap_perm(orig_tclass, orig_requested); + scontext = sidtab_search(&sidtab, ssid); + if (!scontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); + goto out; + } + + /* permissive domain? */ + if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) + avd->flags |= AVD_FLAGS_PERMISSIVE; + + tcontext = sidtab_search(&sidtab, tsid); + if (!tcontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); + goto out; + } + tclass = unmap_class(orig_tclass); if (unlikely(orig_tclass && !tclass)) { if (policydb.allow_unknown) goto allow; - rc = -EINVAL; goto out; } - rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); + context_struct_compute_av(scontext, tcontext, tclass, avd); map_decision(orig_tclass, avd, policydb.allow_unknown); out: read_unlock(&policy_rwlock); - return rc; + return; allow: avd->allowed = 0xffffffff; - avd->auditallow = 0; - avd->auditdeny = 0xffffffff; - avd->seqno = latest_granting; - avd->flags = 0; - rc = 0; goto out; } -int security_compute_av_user(u32 ssid, - u32 tsid, - u16 tclass, - u32 requested, - struct av_decision *avd) +void security_compute_av_user(u32 ssid, + u32 tsid, + u16 tclass, + struct av_decision *avd) { - int rc; + struct context *scontext = NULL, *tcontext = NULL; - if (!ss_initialized) { - avd->allowed = 0xffffffff; - avd->auditallow = 0; - avd->auditdeny = 0xffffffff; - avd->seqno = latest_granting; - return 0; + read_lock(&policy_rwlock); + avd_init(avd); + if (!ss_initialized) + goto allow; + + scontext = sidtab_search(&sidtab, ssid); + if (!scontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); + goto out; } - read_lock(&policy_rwlock); - rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); + /* permissive domain? */ + if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) + avd->flags |= AVD_FLAGS_PERMISSIVE; + + tcontext = sidtab_search(&sidtab, tsid); + if (!tcontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); + goto out; + } + + if (unlikely(!tclass)) { + if (policydb.allow_unknown) + goto allow; + goto out; + } + + context_struct_compute_av(scontext, tcontext, tclass, avd); + out: read_unlock(&policy_rwlock); - return rc; + return; +allow: + avd->allowed = 0xffffffff; + goto out; } /* @@ -1231,7 +1216,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, *sid = SECSID_NULL; /* Copy the string so that we can modify the copy as we parse it. */ - scontext2 = kmalloc(scontext_len+1, gfp_flags); + scontext2 = kmalloc(scontext_len + 1, gfp_flags); if (!scontext2) return -ENOMEM; memcpy(scontext2, scontext, scontext_len); @@ -1565,7 +1550,10 @@ static int clone_sid(u32 sid, { struct sidtab *s = arg; - return sidtab_insert(s, sid, context); + if (sid > SECINITSID_NUM) + return sidtab_insert(s, sid, context); + else + return 0; } static inline int convert_context_handle_invalid_context(struct context *context) @@ -1606,12 +1594,17 @@ static int convert_context(u32 key, { struct convert_context_args *args; struct context oldc; + struct ocontext *oc; + struct mls_range *range; struct role_datum *role; struct type_datum *typdatum; struct user_datum *usrdatum; char *s; u32 len; - int rc; + int rc = 0; + + if (key <= SECINITSID_NUM) + goto out; args = p; @@ -1673,9 +1666,39 @@ static int convert_context(u32 key, goto bad; c->type = typdatum->value; - rc = mls_convert_context(args->oldp, args->newp, c); - if (rc) - goto bad; + /* Convert the MLS fields if dealing with MLS policies */ + if (args->oldp->mls_enabled && args->newp->mls_enabled) { + rc = mls_convert_context(args->oldp, args->newp, c); + if (rc) + goto bad; + } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) { + /* + * Switching between MLS and non-MLS policy: + * free any storage used by the MLS fields in the + * context for all existing entries in the sidtab. + */ + mls_context_destroy(c); + } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { + /* + * Switching between non-MLS and MLS policy: + * ensure that the MLS fields of the context for all + * existing entries in the sidtab are filled in with a + * suitable default value, likely taken from one of the + * initial SIDs. + */ + oc = args->newp->ocontexts[OCON_ISID]; + while (oc && oc->sid[0] != SECINITSID_UNLABELED) + oc = oc->next; + if (!oc) { + printk(KERN_ERR "SELinux: unable to look up" + " the initial SIDs list\n"); + goto bad; + } + range = &oc->context[0].range; + rc = mls_range_set(c, range); + if (rc) + goto bad; + } /* Check the validity of the new context. */ if (!policydb_context_isvalid(args->newp, c)) { @@ -1737,22 +1760,28 @@ int security_load_policy(void *data, size_t len) if (!ss_initialized) { avtab_cache_init(); - if (policydb_read(&policydb, fp)) { + rc = policydb_read(&policydb, fp); + if (rc) { avtab_cache_destroy(); - return -EINVAL; + return rc; } - if (selinux_set_mapping(&policydb, secclass_map, - ¤t_mapping, - ¤t_mapping_size)) { + + rc = selinux_set_mapping(&policydb, secclass_map, + ¤t_mapping, + ¤t_mapping_size); + if (rc) { policydb_destroy(&policydb); avtab_cache_destroy(); - return -EINVAL; + return rc; } - if (policydb_load_isids(&policydb, &sidtab)) { + + rc = policydb_load_isids(&policydb, &sidtab); + if (rc) { policydb_destroy(&policydb); avtab_cache_destroy(); - return -EINVAL; + return rc; } + security_load_policycaps(); ss_initialized = 1; seqno = ++latest_granting; @@ -1768,16 +1797,25 @@ int security_load_policy(void *data, size_t len) sidtab_hash_eval(&sidtab, "sids"); #endif - if (policydb_read(&newpolicydb, fp)) - return -EINVAL; + rc = policydb_read(&newpolicydb, fp); + if (rc) + return rc; + + /* If switching between different policy types, log MLS status */ + if (policydb.mls_enabled && !newpolicydb.mls_enabled) + printk(KERN_INFO "SELinux: Disabling MLS support...\n"); + else if (!policydb.mls_enabled && newpolicydb.mls_enabled) + printk(KERN_INFO "SELinux: Enabling MLS support...\n"); - if (sidtab_init(&newsidtab)) { + rc = policydb_load_isids(&newpolicydb, &newsidtab); + if (rc) { + printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); policydb_destroy(&newpolicydb); - return -ENOMEM; + return rc; } - if (selinux_set_mapping(&newpolicydb, secclass_map, - &map, &map_size)) + rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size); + if (rc) goto err; rc = security_preserve_bools(&newpolicydb); @@ -1788,10 +1826,10 @@ int security_load_policy(void *data, size_t len) /* Clone the SID table. */ sidtab_shutdown(&sidtab); - if (sidtab_map(&sidtab, clone_sid, &newsidtab)) { - rc = -ENOMEM; + + rc = sidtab_map(&sidtab, clone_sid, &newsidtab); + if (rc) goto err; - } /* * Convert the internal representations of contexts @@ -1800,8 +1838,12 @@ int security_load_policy(void *data, size_t len) args.oldp = &policydb; args.newp = &newpolicydb; rc = sidtab_map(&newsidtab, convert_context, &args); - if (rc) + if (rc) { + printk(KERN_ERR "SELinux: unable to convert the internal" + " representation of contexts in the new SID" + " table\n"); goto err; + } /* Save the old policydb and SID table to free later. */ memcpy(&oldpolicydb, &policydb, sizeof policydb); @@ -2066,9 +2108,9 @@ int security_get_user_sids(u32 fromsid, ebitmap_for_each_positive_bit(&user->roles, rnode, i) { role = policydb.role_val_to_struct[i]; - usercon.role = i+1; + usercon.role = i + 1; ebitmap_for_each_positive_bit(&role->types, tnode, j) { - usercon.type = j+1; + usercon.type = j + 1; if (mls_setup_user_range(fromcon, user, &usercon)) continue; @@ -2397,7 +2439,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) u32 len; int rc = 0; - if (!ss_initialized || !selinux_mls_enabled) { + if (!ss_initialized || !policydb.mls_enabled) { *new_sid = sid; goto out; } @@ -2498,7 +2540,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, /* we don't need to check ss_initialized here since the only way both * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the * security server was initialized and ss_initialized was true */ - if (!selinux_mls_enabled) { + if (!policydb.mls_enabled) { *peer_sid = SECSID_NULL; return 0; } @@ -2555,7 +2597,7 @@ int security_get_classes(char ***classes, int *nclasses) read_lock(&policy_rwlock); *nclasses = policydb.p_classes.nprim; - *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC); + *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); if (!*classes) goto out; @@ -2602,7 +2644,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms) } *nperms = match->permissions.nprim; - *perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC); + *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); if (!*perms) goto out; diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c index 837658a98a5..bcf9f620426 100644 --- a/security/selinux/ss/symtab.c +++ b/security/selinux/ss/symtab.c @@ -4,7 +4,6 @@ * Author : Stephen Smalley, <sds@epoch.ncsc.mil> */ #include <linux/kernel.h> -#include <linux/slab.h> #include <linux/string.h> #include <linux/errno.h> #include "symtab.h" diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index f3cb9ed731a..fff78d3b51a 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -38,6 +38,7 @@ #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv6.h> +#include <linux/slab.h> #include <linux/ip.h> #include <linux/tcp.h> #include <linux/skbuff.h> |
