diff options
Diffstat (limited to 'security/selinux')
| -rw-r--r-- | security/selinux/hooks.c | 60 | ||||
| -rw-r--r-- | security/selinux/include/xfrm.h | 12 | ||||
| -rw-r--r-- | security/selinux/nlmsgtab.c | 7 | ||||
| -rw-r--r-- | security/selinux/selinuxfs.c | 112 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 9 | ||||
| -rw-r--r-- | security/selinux/xfrm.c | 68 |
6 files changed, 190 insertions, 78 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b65c201e9ff5..ccaf988f3729 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -117,6 +117,8 @@ static struct security_operations *secondary_ops = NULL; | |||
| 117 | static LIST_HEAD(superblock_security_head); | 117 | static LIST_HEAD(superblock_security_head); |
| 118 | static DEFINE_SPINLOCK(sb_security_lock); | 118 | static DEFINE_SPINLOCK(sb_security_lock); |
| 119 | 119 | ||
| 120 | static kmem_cache_t *sel_inode_cache; | ||
| 121 | |||
| 120 | /* Allocate and free functions for each kind of security blob. */ | 122 | /* Allocate and free functions for each kind of security blob. */ |
| 121 | 123 | ||
| 122 | static int task_alloc_security(struct task_struct *task) | 124 | static int task_alloc_security(struct task_struct *task) |
| @@ -146,10 +148,11 @@ static int inode_alloc_security(struct inode *inode) | |||
| 146 | struct task_security_struct *tsec = current->security; | 148 | struct task_security_struct *tsec = current->security; |
| 147 | struct inode_security_struct *isec; | 149 | struct inode_security_struct *isec; |
| 148 | 150 | ||
| 149 | isec = kzalloc(sizeof(struct inode_security_struct), GFP_KERNEL); | 151 | isec = kmem_cache_alloc(sel_inode_cache, SLAB_KERNEL); |
| 150 | if (!isec) | 152 | if (!isec) |
| 151 | return -ENOMEM; | 153 | return -ENOMEM; |
| 152 | 154 | ||
| 155 | memset(isec, 0, sizeof(*isec)); | ||
| 153 | init_MUTEX(&isec->sem); | 156 | init_MUTEX(&isec->sem); |
| 154 | INIT_LIST_HEAD(&isec->list); | 157 | INIT_LIST_HEAD(&isec->list); |
| 155 | isec->inode = inode; | 158 | isec->inode = inode; |
| @@ -172,7 +175,7 @@ static void inode_free_security(struct inode *inode) | |||
| 172 | spin_unlock(&sbsec->isec_lock); | 175 | spin_unlock(&sbsec->isec_lock); |
| 173 | 176 | ||
| 174 | inode->i_security = NULL; | 177 | inode->i_security = NULL; |
| 175 | kfree(isec); | 178 | kmem_cache_free(sel_inode_cache, isec); |
| 176 | } | 179 | } |
| 177 | 180 | ||
| 178 | static int file_alloc_security(struct file *file) | 181 | static int file_alloc_security(struct file *file) |
| @@ -1929,7 +1932,6 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
| 1929 | struct task_security_struct *tsec; | 1932 | struct task_security_struct *tsec; |
| 1930 | struct inode_security_struct *dsec; | 1933 | struct inode_security_struct *dsec; |
| 1931 | struct superblock_security_struct *sbsec; | 1934 | struct superblock_security_struct *sbsec; |
| 1932 | struct inode_security_struct *isec; | ||
| 1933 | u32 newsid, clen; | 1935 | u32 newsid, clen; |
| 1934 | int rc; | 1936 | int rc; |
| 1935 | char *namep = NULL, *context; | 1937 | char *namep = NULL, *context; |
| @@ -1937,7 +1939,6 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
| 1937 | tsec = current->security; | 1939 | tsec = current->security; |
| 1938 | dsec = dir->i_security; | 1940 | dsec = dir->i_security; |
| 1939 | sbsec = dir->i_sb->s_security; | 1941 | sbsec = dir->i_sb->s_security; |
| 1940 | isec = inode->i_security; | ||
| 1941 | 1942 | ||
| 1942 | if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { | 1943 | if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { |
| 1943 | newsid = tsec->create_sid; | 1944 | newsid = tsec->create_sid; |
| @@ -1957,7 +1958,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
| 1957 | 1958 | ||
| 1958 | inode_security_set_sid(inode, newsid); | 1959 | inode_security_set_sid(inode, newsid); |
| 1959 | 1960 | ||
| 1960 | if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) | 1961 | if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) |
| 1961 | return -EOPNOTSUPP; | 1962 | return -EOPNOTSUPP; |
| 1962 | 1963 | ||
| 1963 | if (name) { | 1964 | if (name) { |
| @@ -3318,24 +3319,38 @@ out: | |||
| 3318 | return err; | 3319 | return err; |
| 3319 | } | 3320 | } |
| 3320 | 3321 | ||
| 3321 | static int selinux_socket_getpeersec(struct socket *sock, char __user *optval, | 3322 | static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, |
| 3322 | int __user *optlen, unsigned len) | 3323 | int __user *optlen, unsigned len) |
| 3323 | { | 3324 | { |
| 3324 | int err = 0; | 3325 | int err = 0; |
| 3325 | char *scontext; | 3326 | char *scontext; |
| 3326 | u32 scontext_len; | 3327 | u32 scontext_len; |
| 3327 | struct sk_security_struct *ssec; | 3328 | struct sk_security_struct *ssec; |
| 3328 | struct inode_security_struct *isec; | 3329 | struct inode_security_struct *isec; |
| 3330 | u32 peer_sid = 0; | ||
| 3329 | 3331 | ||
| 3330 | isec = SOCK_INODE(sock)->i_security; | 3332 | isec = SOCK_INODE(sock)->i_security; |
| 3331 | if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) { | 3333 | |
| 3334 | /* if UNIX_STREAM check peer_sid, if TCP check dst for labelled sa */ | ||
| 3335 | if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET) { | ||
| 3336 | ssec = sock->sk->sk_security; | ||
| 3337 | peer_sid = ssec->peer_sid; | ||
| 3338 | } | ||
| 3339 | else if (isec->sclass == SECCLASS_TCP_SOCKET) { | ||
| 3340 | peer_sid = selinux_socket_getpeer_stream(sock->sk); | ||
| 3341 | |||
| 3342 | if (peer_sid == SECSID_NULL) { | ||
| 3343 | err = -ENOPROTOOPT; | ||
| 3344 | goto out; | ||
| 3345 | } | ||
| 3346 | } | ||
| 3347 | else { | ||
| 3332 | err = -ENOPROTOOPT; | 3348 | err = -ENOPROTOOPT; |
| 3333 | goto out; | 3349 | goto out; |
| 3334 | } | 3350 | } |
| 3335 | 3351 | ||
| 3336 | ssec = sock->sk->sk_security; | 3352 | err = security_sid_to_context(peer_sid, &scontext, &scontext_len); |
| 3337 | 3353 | ||
| 3338 | err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len); | ||
| 3339 | if (err) | 3354 | if (err) |
| 3340 | goto out; | 3355 | goto out; |
| 3341 | 3356 | ||
| @@ -3356,6 +3371,23 @@ out: | |||
| 3356 | return err; | 3371 | return err; |
| 3357 | } | 3372 | } |
| 3358 | 3373 | ||
| 3374 | static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen) | ||
| 3375 | { | ||
| 3376 | int err = 0; | ||
| 3377 | u32 peer_sid = selinux_socket_getpeer_dgram(skb); | ||
| 3378 | |||
| 3379 | if (peer_sid == SECSID_NULL) | ||
| 3380 | return -EINVAL; | ||
| 3381 | |||
| 3382 | err = security_sid_to_context(peer_sid, secdata, seclen); | ||
| 3383 | if (err) | ||
| 3384 | return err; | ||
| 3385 | |||
| 3386 | return 0; | ||
| 3387 | } | ||
| 3388 | |||
| 3389 | |||
| 3390 | |||
| 3359 | static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) | 3391 | static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) |
| 3360 | { | 3392 | { |
| 3361 | return sk_alloc_security(sk, family, priority); | 3393 | return sk_alloc_security(sk, family, priority); |
| @@ -4344,7 +4376,8 @@ static struct security_operations selinux_ops = { | |||
| 4344 | .socket_setsockopt = selinux_socket_setsockopt, | 4376 | .socket_setsockopt = selinux_socket_setsockopt, |
| 4345 | .socket_shutdown = selinux_socket_shutdown, | 4377 | .socket_shutdown = selinux_socket_shutdown, |
| 4346 | .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb, | 4378 | .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb, |
| 4347 | .socket_getpeersec = selinux_socket_getpeersec, | 4379 | .socket_getpeersec_stream = selinux_socket_getpeersec_stream, |
| 4380 | .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram, | ||
| 4348 | .sk_alloc_security = selinux_sk_alloc_security, | 4381 | .sk_alloc_security = selinux_sk_alloc_security, |
| 4349 | .sk_free_security = selinux_sk_free_security, | 4382 | .sk_free_security = selinux_sk_free_security, |
| 4350 | .sk_getsid = selinux_sk_getsid_security, | 4383 | .sk_getsid = selinux_sk_getsid_security, |
| @@ -4376,6 +4409,9 @@ static __init int selinux_init(void) | |||
| 4376 | tsec = current->security; | 4409 | tsec = current->security; |
| 4377 | tsec->osid = tsec->sid = SECINITSID_KERNEL; | 4410 | tsec->osid = tsec->sid = SECINITSID_KERNEL; |
| 4378 | 4411 | ||
| 4412 | sel_inode_cache = kmem_cache_create("selinux_inode_security", | ||
| 4413 | sizeof(struct inode_security_struct), | ||
| 4414 | 0, SLAB_PANIC, NULL, NULL); | ||
| 4379 | avc_init(); | 4415 | avc_init(); |
| 4380 | 4416 | ||
| 4381 | original_ops = secondary_ops = security_ops; | 4417 | original_ops = secondary_ops = security_ops; |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 8e87996c6dd5..c10f1fc41502 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
| @@ -39,6 +39,8 @@ static inline u32 selinux_no_sk_sid(struct flowi *fl) | |||
| 39 | #ifdef CONFIG_SECURITY_NETWORK_XFRM | 39 | #ifdef CONFIG_SECURITY_NETWORK_XFRM |
| 40 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb); | 40 | int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb); |
| 41 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb); | 41 | int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb); |
| 42 | u32 selinux_socket_getpeer_stream(struct sock *sk); | ||
| 43 | u32 selinux_socket_getpeer_dgram(struct sk_buff *skb); | ||
| 42 | #else | 44 | #else |
| 43 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) | 45 | static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) |
| 44 | { | 46 | { |
| @@ -49,6 +51,16 @@ static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb) | |||
| 49 | { | 51 | { |
| 50 | return NF_ACCEPT; | 52 | return NF_ACCEPT; |
| 51 | } | 53 | } |
| 54 | |||
| 55 | static inline int selinux_socket_getpeer_stream(struct sock *sk) | ||
| 56 | { | ||
| 57 | return SECSID_NULL; | ||
| 58 | } | ||
| 59 | |||
| 60 | static inline int selinux_socket_getpeer_dgram(struct sk_buff *skb) | ||
| 61 | { | ||
| 62 | return SECSID_NULL; | ||
| 63 | } | ||
| 52 | #endif | 64 | #endif |
| 53 | 65 | ||
| 54 | #endif /* _SELINUX_XFRM_H_ */ | 66 | #endif /* _SELINUX_XFRM_H_ */ |
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c index 69b9329b2054..85e399259832 100644 --- a/security/selinux/nlmsgtab.c +++ b/security/selinux/nlmsgtab.c | |||
| @@ -88,8 +88,15 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] = | |||
| 88 | { XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | 88 | { XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, |
| 89 | { XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ }, | 89 | { XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ }, |
| 90 | { XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | 90 | { XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, |
| 91 | { XFRM_MSG_ACQUIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | ||
| 92 | { XFRM_MSG_EXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | ||
| 91 | { XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | 93 | { XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, |
| 92 | { XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | 94 | { XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, |
| 95 | { XFRM_MSG_POLEXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | ||
| 96 | { XFRM_MSG_FLUSHSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | ||
| 97 | { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | ||
| 98 | { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE }, | ||
| 99 | { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ }, | ||
| 93 | }; | 100 | }; |
| 94 | 101 | ||
| 95 | static struct nlmsg_perm nlmsg_audit_perms[] = | 102 | static struct nlmsg_perm nlmsg_audit_perms[] = |
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index b5fa02d17b1e..f5d78365488f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
| 17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
| 18 | #include <linux/mutex.h> | ||
| 18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
| 19 | #include <linux/string.h> | 20 | #include <linux/string.h> |
| 20 | #include <linux/security.h> | 21 | #include <linux/security.h> |
| @@ -44,7 +45,7 @@ static int __init checkreqprot_setup(char *str) | |||
| 44 | __setup("checkreqprot=", checkreqprot_setup); | 45 | __setup("checkreqprot=", checkreqprot_setup); |
| 45 | 46 | ||
| 46 | 47 | ||
| 47 | static DECLARE_MUTEX(sel_sem); | 48 | static DEFINE_MUTEX(sel_mutex); |
| 48 | 49 | ||
| 49 | /* global data for booleans */ | 50 | /* global data for booleans */ |
| 50 | static struct dentry *bool_dir = NULL; | 51 | static struct dentry *bool_dir = NULL; |
| @@ -230,7 +231,7 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf, | |||
| 230 | ssize_t length; | 231 | ssize_t length; |
| 231 | void *data = NULL; | 232 | void *data = NULL; |
| 232 | 233 | ||
| 233 | down(&sel_sem); | 234 | mutex_lock(&sel_mutex); |
| 234 | 235 | ||
| 235 | length = task_has_security(current, SECURITY__LOAD_POLICY); | 236 | length = task_has_security(current, SECURITY__LOAD_POLICY); |
| 236 | if (length) | 237 | if (length) |
| @@ -262,7 +263,7 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf, | |||
| 262 | else | 263 | else |
| 263 | length = count; | 264 | length = count; |
| 264 | out: | 265 | out: |
| 265 | up(&sel_sem); | 266 | mutex_unlock(&sel_mutex); |
| 266 | vfree(data); | 267 | vfree(data); |
| 267 | return length; | 268 | return length; |
| 268 | } | 269 | } |
| @@ -709,12 +710,11 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
| 709 | { | 710 | { |
| 710 | char *page = NULL; | 711 | char *page = NULL; |
| 711 | ssize_t length; | 712 | ssize_t length; |
| 712 | ssize_t end; | ||
| 713 | ssize_t ret; | 713 | ssize_t ret; |
| 714 | int cur_enforcing; | 714 | int cur_enforcing; |
| 715 | struct inode *inode; | 715 | struct inode *inode; |
| 716 | 716 | ||
| 717 | down(&sel_sem); | 717 | mutex_lock(&sel_mutex); |
| 718 | 718 | ||
| 719 | ret = -EFAULT; | 719 | ret = -EFAULT; |
| 720 | 720 | ||
| @@ -740,26 +740,9 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
| 740 | 740 | ||
| 741 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, | 741 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, |
| 742 | bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]); | 742 | bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]); |
| 743 | if (length < 0) { | 743 | ret = simple_read_from_buffer(buf, count, ppos, page, length); |
| 744 | ret = length; | ||
| 745 | goto out; | ||
| 746 | } | ||
| 747 | |||
| 748 | if (*ppos >= length) { | ||
| 749 | ret = 0; | ||
| 750 | goto out; | ||
| 751 | } | ||
| 752 | if (count + *ppos > length) | ||
| 753 | count = length - *ppos; | ||
| 754 | end = count + *ppos; | ||
| 755 | if (copy_to_user(buf, (char *) page + *ppos, count)) { | ||
| 756 | ret = -EFAULT; | ||
| 757 | goto out; | ||
| 758 | } | ||
| 759 | *ppos = end; | ||
| 760 | ret = count; | ||
| 761 | out: | 744 | out: |
| 762 | up(&sel_sem); | 745 | mutex_unlock(&sel_mutex); |
| 763 | if (page) | 746 | if (page) |
| 764 | free_page((unsigned long)page); | 747 | free_page((unsigned long)page); |
| 765 | return ret; | 748 | return ret; |
| @@ -773,7 +756,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
| 773 | int new_value; | 756 | int new_value; |
| 774 | struct inode *inode; | 757 | struct inode *inode; |
| 775 | 758 | ||
| 776 | down(&sel_sem); | 759 | mutex_lock(&sel_mutex); |
| 777 | 760 | ||
| 778 | length = task_has_security(current, SECURITY__SETBOOL); | 761 | length = task_has_security(current, SECURITY__SETBOOL); |
| 779 | if (length) | 762 | if (length) |
| @@ -812,7 +795,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
| 812 | length = count; | 795 | length = count; |
| 813 | 796 | ||
| 814 | out: | 797 | out: |
| 815 | up(&sel_sem); | 798 | mutex_unlock(&sel_mutex); |
| 816 | if (page) | 799 | if (page) |
| 817 | free_page((unsigned long) page); | 800 | free_page((unsigned long) page); |
| 818 | return length; | 801 | return length; |
| @@ -831,7 +814,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
| 831 | ssize_t length = -EFAULT; | 814 | ssize_t length = -EFAULT; |
| 832 | int new_value; | 815 | int new_value; |
| 833 | 816 | ||
| 834 | down(&sel_sem); | 817 | mutex_lock(&sel_mutex); |
| 835 | 818 | ||
| 836 | length = task_has_security(current, SECURITY__SETBOOL); | 819 | length = task_has_security(current, SECURITY__SETBOOL); |
| 837 | if (length) | 820 | if (length) |
| @@ -869,7 +852,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
| 869 | length = count; | 852 | length = count; |
| 870 | 853 | ||
| 871 | out: | 854 | out: |
| 872 | up(&sel_sem); | 855 | mutex_unlock(&sel_mutex); |
| 873 | if (page) | 856 | if (page) |
| 874 | free_page((unsigned long) page); | 857 | free_page((unsigned long) page); |
| 875 | return length; | 858 | return length; |
| @@ -987,7 +970,7 @@ out: | |||
| 987 | return ret; | 970 | return ret; |
| 988 | err: | 971 | err: |
| 989 | kfree(values); | 972 | kfree(values); |
| 990 | d_genocide(dir); | 973 | sel_remove_bools(dir); |
| 991 | ret = -ENOMEM; | 974 | ret = -ENOMEM; |
| 992 | goto out; | 975 | goto out; |
| 993 | } | 976 | } |
| @@ -1168,37 +1151,38 @@ static int sel_make_avc_files(struct dentry *dir) | |||
| 1168 | dentry = d_alloc_name(dir, files[i].name); | 1151 | dentry = d_alloc_name(dir, files[i].name); |
| 1169 | if (!dentry) { | 1152 | if (!dentry) { |
| 1170 | ret = -ENOMEM; | 1153 | ret = -ENOMEM; |
| 1171 | goto err; | 1154 | goto out; |
| 1172 | } | 1155 | } |
| 1173 | 1156 | ||
| 1174 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); | 1157 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); |
| 1175 | if (!inode) { | 1158 | if (!inode) { |
| 1176 | ret = -ENOMEM; | 1159 | ret = -ENOMEM; |
| 1177 | goto err; | 1160 | goto out; |
| 1178 | } | 1161 | } |
| 1179 | inode->i_fop = files[i].ops; | 1162 | inode->i_fop = files[i].ops; |
| 1180 | d_add(dentry, inode); | 1163 | d_add(dentry, inode); |
| 1181 | } | 1164 | } |
| 1182 | out: | 1165 | out: |
| 1183 | return ret; | 1166 | return ret; |
| 1184 | err: | ||
| 1185 | d_genocide(dir); | ||
| 1186 | goto out; | ||
| 1187 | } | 1167 | } |
| 1188 | 1168 | ||
| 1189 | static int sel_make_dir(struct super_block *sb, struct dentry *dentry) | 1169 | static int sel_make_dir(struct inode *dir, struct dentry *dentry) |
| 1190 | { | 1170 | { |
| 1191 | int ret = 0; | 1171 | int ret = 0; |
| 1192 | struct inode *inode; | 1172 | struct inode *inode; |
| 1193 | 1173 | ||
| 1194 | inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); | 1174 | inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); |
| 1195 | if (!inode) { | 1175 | if (!inode) { |
| 1196 | ret = -ENOMEM; | 1176 | ret = -ENOMEM; |
| 1197 | goto out; | 1177 | goto out; |
| 1198 | } | 1178 | } |
| 1199 | inode->i_op = &simple_dir_inode_operations; | 1179 | inode->i_op = &simple_dir_inode_operations; |
| 1200 | inode->i_fop = &simple_dir_operations; | 1180 | inode->i_fop = &simple_dir_operations; |
| 1181 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
| 1182 | inode->i_nlink++; | ||
| 1201 | d_add(dentry, inode); | 1183 | d_add(dentry, inode); |
| 1184 | /* bump link count on parent directory, too */ | ||
| 1185 | dir->i_nlink++; | ||
| 1202 | out: | 1186 | out: |
| 1203 | return ret; | 1187 | return ret; |
| 1204 | } | 1188 | } |
| @@ -1207,7 +1191,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
| 1207 | { | 1191 | { |
| 1208 | int ret; | 1192 | int ret; |
| 1209 | struct dentry *dentry; | 1193 | struct dentry *dentry; |
| 1210 | struct inode *inode; | 1194 | struct inode *inode, *root_inode; |
| 1211 | struct inode_security_struct *isec; | 1195 | struct inode_security_struct *isec; |
| 1212 | 1196 | ||
| 1213 | static struct tree_descr selinux_files[] = { | 1197 | static struct tree_descr selinux_files[] = { |
| @@ -1228,30 +1212,33 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
| 1228 | }; | 1212 | }; |
| 1229 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1213 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); |
| 1230 | if (ret) | 1214 | if (ret) |
| 1231 | return ret; | 1215 | goto err; |
| 1216 | |||
| 1217 | root_inode = sb->s_root->d_inode; | ||
| 1232 | 1218 | ||
| 1233 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); | 1219 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); |
| 1234 | if (!dentry) | 1220 | if (!dentry) { |
| 1235 | return -ENOMEM; | 1221 | ret = -ENOMEM; |
| 1222 | goto err; | ||
| 1223 | } | ||
| 1236 | 1224 | ||
| 1237 | inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); | 1225 | ret = sel_make_dir(root_inode, dentry); |
| 1238 | if (!inode) | ||
| 1239 | goto out; | ||
| 1240 | inode->i_op = &simple_dir_inode_operations; | ||
| 1241 | inode->i_fop = &simple_dir_operations; | ||
| 1242 | d_add(dentry, inode); | ||
| 1243 | bool_dir = dentry; | ||
| 1244 | ret = sel_make_bools(); | ||
| 1245 | if (ret) | 1226 | if (ret) |
| 1246 | goto out; | 1227 | goto err; |
| 1228 | |||
| 1229 | bool_dir = dentry; | ||
| 1247 | 1230 | ||
| 1248 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); | 1231 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); |
| 1249 | if (!dentry) | 1232 | if (!dentry) { |
| 1250 | return -ENOMEM; | 1233 | ret = -ENOMEM; |
| 1234 | goto err; | ||
| 1235 | } | ||
| 1251 | 1236 | ||
| 1252 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); | 1237 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); |
| 1253 | if (!inode) | 1238 | if (!inode) { |
| 1254 | goto out; | 1239 | ret = -ENOMEM; |
| 1240 | goto err; | ||
| 1241 | } | ||
| 1255 | isec = (struct inode_security_struct*)inode->i_security; | 1242 | isec = (struct inode_security_struct*)inode->i_security; |
| 1256 | isec->sid = SECINITSID_DEVNULL; | 1243 | isec->sid = SECINITSID_DEVNULL; |
| 1257 | isec->sclass = SECCLASS_CHR_FILE; | 1244 | isec->sclass = SECCLASS_CHR_FILE; |
| @@ -1262,22 +1249,23 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
| 1262 | selinux_null = dentry; | 1249 | selinux_null = dentry; |
| 1263 | 1250 | ||
| 1264 | dentry = d_alloc_name(sb->s_root, "avc"); | 1251 | dentry = d_alloc_name(sb->s_root, "avc"); |
| 1265 | if (!dentry) | 1252 | if (!dentry) { |
| 1266 | return -ENOMEM; | 1253 | ret = -ENOMEM; |
| 1254 | goto err; | ||
| 1255 | } | ||
| 1267 | 1256 | ||
| 1268 | ret = sel_make_dir(sb, dentry); | 1257 | ret = sel_make_dir(root_inode, dentry); |
| 1269 | if (ret) | 1258 | if (ret) |
| 1270 | goto out; | 1259 | goto err; |
| 1271 | 1260 | ||
| 1272 | ret = sel_make_avc_files(dentry); | 1261 | ret = sel_make_avc_files(dentry); |
| 1273 | if (ret) | 1262 | if (ret) |
| 1274 | goto out; | 1263 | goto err; |
| 1275 | |||
| 1276 | return 0; | ||
| 1277 | out: | 1264 | out: |
| 1278 | dput(dentry); | 1265 | return ret; |
| 1266 | err: | ||
| 1279 | printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); | 1267 | printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); |
| 1280 | return -ENOMEM; | 1268 | goto out; |
| 1281 | } | 1269 | } |
| 1282 | 1270 | ||
| 1283 | static struct super_block *sel_get_sb(struct file_system_type *fs_type, | 1271 | static struct super_block *sel_get_sb(struct file_system_type *fs_type, |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 8a764928ff4b..63e0b7f29cb5 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
| @@ -27,7 +27,8 @@ | |||
| 27 | #include <linux/in.h> | 27 | #include <linux/in.h> |
| 28 | #include <linux/sched.h> | 28 | #include <linux/sched.h> |
| 29 | #include <linux/audit.h> | 29 | #include <linux/audit.h> |
| 30 | #include <asm/semaphore.h> | 30 | #include <linux/mutex.h> |
| 31 | |||
| 31 | #include "flask.h" | 32 | #include "flask.h" |
| 32 | #include "avc.h" | 33 | #include "avc.h" |
| 33 | #include "avc_ss.h" | 34 | #include "avc_ss.h" |
| @@ -48,9 +49,9 @@ static DEFINE_RWLOCK(policy_rwlock); | |||
| 48 | #define POLICY_RDUNLOCK read_unlock(&policy_rwlock) | 49 | #define POLICY_RDUNLOCK read_unlock(&policy_rwlock) |
| 49 | #define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock) | 50 | #define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock) |
| 50 | 51 | ||
| 51 | static DECLARE_MUTEX(load_sem); | 52 | static DEFINE_MUTEX(load_mutex); |
| 52 | #define LOAD_LOCK down(&load_sem) | 53 | #define LOAD_LOCK mutex_lock(&load_mutex) |
| 53 | #define LOAD_UNLOCK up(&load_sem) | 54 | #define LOAD_UNLOCK mutex_unlock(&load_mutex) |
| 54 | 55 | ||
| 55 | static struct sidtab sidtab; | 56 | static struct sidtab sidtab; |
| 56 | struct policydb policydb; | 57 | struct policydb policydb; |
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index b2af7ca496c1..dfab6c886698 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
| @@ -225,6 +225,74 @@ void selinux_xfrm_state_free(struct xfrm_state *x) | |||
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | /* | 227 | /* |
| 228 | * SELinux internal function to retrieve the context of a connected | ||
| 229 | * (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security | ||
| 230 | * association used to connect to the remote socket. | ||
| 231 | * | ||
| 232 | * Retrieve via getsockopt SO_PEERSEC. | ||
| 233 | */ | ||
| 234 | u32 selinux_socket_getpeer_stream(struct sock *sk) | ||
| 235 | { | ||
| 236 | struct dst_entry *dst, *dst_test; | ||
| 237 | u32 peer_sid = SECSID_NULL; | ||
| 238 | |||
| 239 | if (sk->sk_state != TCP_ESTABLISHED) | ||
| 240 | goto out; | ||
| 241 | |||
| 242 | dst = sk_dst_get(sk); | ||
| 243 | if (!dst) | ||
| 244 | goto out; | ||
| 245 | |||
| 246 | for (dst_test = dst; dst_test != 0; | ||
| 247 | dst_test = dst_test->child) { | ||
| 248 | struct xfrm_state *x = dst_test->xfrm; | ||
| 249 | |||
| 250 | if (x && selinux_authorizable_xfrm(x)) { | ||
| 251 | struct xfrm_sec_ctx *ctx = x->security; | ||
| 252 | peer_sid = ctx->ctx_sid; | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | dst_release(dst); | ||
| 257 | |||
| 258 | out: | ||
| 259 | return peer_sid; | ||
| 260 | } | ||
| 261 | |||
| 262 | /* | ||
| 263 | * SELinux internal function to retrieve the context of a UDP packet | ||
| 264 | * based on its security association used to connect to the remote socket. | ||
| 265 | * | ||
| 266 | * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message | ||
| 267 | * type SCM_SECURITY. | ||
| 268 | */ | ||
| 269 | u32 selinux_socket_getpeer_dgram(struct sk_buff *skb) | ||
| 270 | { | ||
| 271 | struct sec_path *sp; | ||
| 272 | |||
| 273 | if (skb == NULL) | ||
| 274 | return SECSID_NULL; | ||
| 275 | |||
| 276 | if (skb->sk->sk_protocol != IPPROTO_UDP) | ||
| 277 | return SECSID_NULL; | ||
| 278 | |||
| 279 | sp = skb->sp; | ||
| 280 | if (sp) { | ||
| 281 | int i; | ||
| 282 | |||
| 283 | for (i = sp->len-1; i >= 0; i--) { | ||
| 284 | struct xfrm_state *x = sp->x[i].xvec; | ||
| 285 | if (selinux_authorizable_xfrm(x)) { | ||
| 286 | struct xfrm_sec_ctx *ctx = x->security; | ||
| 287 | return ctx->ctx_sid; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | return SECSID_NULL; | ||
| 293 | } | ||
| 294 | |||
| 295 | /* | ||
| 228 | * LSM hook that controls access to unlabelled packets. If | 296 | * LSM hook that controls access to unlabelled packets. If |
| 229 | * a xfrm_state is authorizable (defined by macro) then it was | 297 | * a xfrm_state is authorizable (defined by macro) then it was |
| 230 | * already authorized by the IPSec process. If not, then | 298 | * already authorized by the IPSec process. If not, then |
