X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=security%2Fselinux%2Fhooks.c;h=b61b9554bc27c1d9eec70e3bce7e6a4f020d2345;hb=1b9a3917366028cc451a98dd22e3bcd537d4e5c1;hp=4ae834d89bce9e81a98c8be4a0056341603ffded;hpb=cf41f8ac386e8d62122e7e394b4c6b3e3ab30ede;p=powerpc.git diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4ae834d89b..b61b9554bc 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -117,6 +117,34 @@ static struct security_operations *secondary_ops = NULL; static LIST_HEAD(superblock_security_head); static DEFINE_SPINLOCK(sb_security_lock); +static kmem_cache_t *sel_inode_cache; + +/* Return security context for a given sid or just the context + length if the buffer is null or length is 0 */ +static int selinux_getsecurity(u32 sid, void *buffer, size_t size) +{ + char *context; + unsigned len; + int rc; + + rc = security_sid_to_context(sid, &context, &len); + if (rc) + return rc; + + if (!buffer || !size) + goto getsecurity_exit; + + if (size < len) { + len = -ERANGE; + goto getsecurity_exit; + } + memcpy(buffer, context, len); + +getsecurity_exit: + kfree(context); + return len; +} + /* Allocate and free functions for each kind of security blob. */ static int task_alloc_security(struct task_struct *task) @@ -146,10 +174,11 @@ static int inode_alloc_security(struct inode *inode) struct task_security_struct *tsec = current->security; struct inode_security_struct *isec; - isec = kzalloc(sizeof(struct inode_security_struct), GFP_KERNEL); + isec = kmem_cache_alloc(sel_inode_cache, SLAB_KERNEL); if (!isec) return -ENOMEM; + memset(isec, 0, sizeof(*isec)); init_MUTEX(&isec->sem); INIT_LIST_HEAD(&isec->list); isec->inode = inode; @@ -172,7 +201,7 @@ static void inode_free_security(struct inode *inode) spin_unlock(&sbsec->isec_lock); inode->i_security = NULL; - kfree(isec); + kmem_cache_free(sel_inode_cache, isec); } static int file_alloc_security(struct file *file) @@ -232,7 +261,6 @@ static void superblock_free_security(struct super_block *sb) kfree(sbsec); } -#ifdef CONFIG_SECURITY_NETWORK static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) { struct sk_security_struct *ssec; @@ -261,7 +289,6 @@ static void sk_free_security(struct sock *sk) sk->sk_security = NULL; kfree(ssec); } -#endif /* CONFIG_SECURITY_NETWORK */ /* The security server must be initialized before any labeling or access decisions can be provided. */ @@ -1264,7 +1291,7 @@ static int selinux_ptrace(struct task_struct *parent, struct task_struct *child) rc = task_has_perm(parent, child, PROCESS__PTRACE); /* Save the SID of the tracing process for later use in apply_creds. */ - if (!rc) + if (!(child->ptrace & PT_PTRACED) && !rc) csec->ptrace_sid = psec->sid; return rc; } @@ -1931,7 +1958,6 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, struct task_security_struct *tsec; struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; - struct inode_security_struct *isec; u32 newsid, clen; int rc; char *namep = NULL, *context; @@ -1939,7 +1965,6 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, tsec = current->security; dsec = dir->i_security; sbsec = dir->i_sb->s_security; - isec = inode->i_security; if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { newsid = tsec->create_sid; @@ -1959,7 +1984,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, inode_security_set_sid(inode, newsid); - if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) + if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) return -EOPNOTSUPP; if (name) { @@ -2211,6 +2236,11 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name) return -EACCES; } +static const char *selinux_inode_xattr_getsuffix(void) +{ + return XATTR_SELINUX_SUFFIX; +} + /* * Copy the in-core inode security context value to the user. If the * getxattr() prior to this succeeded, check to see if we need to @@ -2218,47 +2248,14 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name) * * Permission check is handled by selinux_inode_getxattr hook. */ -static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err) +static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err) { struct inode_security_struct *isec = inode->i_security; - char *context; - unsigned len; - int rc; - - if (strcmp(name, XATTR_SELINUX_SUFFIX)) { - rc = -EOPNOTSUPP; - goto out; - } - - rc = security_sid_to_context(isec->sid, &context, &len); - if (rc) - goto out; - /* Probe for required buffer size */ - if (!buffer || !size) { - rc = len; - goto out_free; - } - - if (size < len) { - rc = -ERANGE; - goto out_free; - } + if (strcmp(name, XATTR_SELINUX_SUFFIX)) + return -EOPNOTSUPP; - if (err > 0) { - if ((len == err) && !(memcmp(context, buffer, len))) { - /* Don't need to canonicalize value */ - rc = err; - goto out_free; - } - memset(buffer, 0, size); - } - memcpy(buffer, context, len); - rc = len; -out_free: - kfree(context); -out: - return rc; + return selinux_getsecurity(isec->sid, buffer, size); } static int selinux_inode_setsecurity(struct inode *inode, const char *name, @@ -2736,8 +2733,6 @@ static void selinux_task_to_inode(struct task_struct *p, return; } -#ifdef CONFIG_SECURITY_NETWORK - /* Returns error only if unable to parse addresses */ static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad) { @@ -3322,24 +3317,38 @@ out: return err; } -static int selinux_socket_getpeersec(struct socket *sock, char __user *optval, - int __user *optlen, unsigned len) +static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, + int __user *optlen, unsigned len) { int err = 0; char *scontext; u32 scontext_len; struct sk_security_struct *ssec; struct inode_security_struct *isec; + u32 peer_sid = 0; isec = SOCK_INODE(sock)->i_security; - if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) { + + /* if UNIX_STREAM check peer_sid, if TCP check dst for labelled sa */ + if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET) { + ssec = sock->sk->sk_security; + peer_sid = ssec->peer_sid; + } + else if (isec->sclass == SECCLASS_TCP_SOCKET) { + peer_sid = selinux_socket_getpeer_stream(sock->sk); + + if (peer_sid == SECSID_NULL) { + err = -ENOPROTOOPT; + goto out; + } + } + else { err = -ENOPROTOOPT; goto out; } - ssec = sock->sk->sk_security; - - err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len); + err = security_sid_to_context(peer_sid, &scontext, &scontext_len); + if (err) goto out; @@ -3360,6 +3369,23 @@ out: return err; } +static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen) +{ + int err = 0; + u32 peer_sid = selinux_socket_getpeer_dgram(skb); + + if (peer_sid == SECSID_NULL) + return -EINVAL; + + err = security_sid_to_context(peer_sid, secdata, seclen); + if (err) + return err; + + return 0; +} + + + static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) { return sk_alloc_security(sk, family, priority); @@ -3556,15 +3582,6 @@ static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum, #endif /* CONFIG_NETFILTER */ -#else - -static inline int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) -{ - return 0; -} - -#endif /* CONFIG_SECURITY_NETWORK */ - static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) { struct task_security_struct *tsec; @@ -4035,6 +4052,13 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) return ipc_has_perm(ipcp, av); } +static int selinux_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size) +{ + struct ipc_security_struct *isec = ipcp->security; + + return selinux_getsecurity(isec->sid, buffer, size); +} + /* module stacking operations */ static int selinux_register_security (const char *name, struct security_operations *ops) { @@ -4076,8 +4100,7 @@ static int selinux_getprocattr(struct task_struct *p, char *name, void *value, size_t size) { struct task_security_struct *tsec; - u32 sid, len; - char *context; + u32 sid; int error; if (current != p) { @@ -4086,9 +4109,6 @@ static int selinux_getprocattr(struct task_struct *p, return error; } - if (!size) - return -ERANGE; - tsec = p->security; if (!strcmp(name, "current")) @@ -4105,16 +4125,7 @@ static int selinux_getprocattr(struct task_struct *p, if (!sid) return 0; - error = security_sid_to_context(sid, &context, &len); - if (error) - return error; - if (len > size) { - kfree(context); - return -ERANGE; - } - memcpy(value, context, len); - kfree(context); - return len; + return selinux_getsecurity(sid, value, size); } static int selinux_setprocattr(struct task_struct *p, @@ -4272,6 +4283,7 @@ static struct security_operations selinux_ops = { .inode_getxattr = selinux_inode_getxattr, .inode_listxattr = selinux_inode_listxattr, .inode_removexattr = selinux_inode_removexattr, + .inode_xattr_getsuffix = selinux_inode_xattr_getsuffix, .inode_getsecurity = selinux_inode_getsecurity, .inode_setsecurity = selinux_inode_setsecurity, .inode_listsecurity = selinux_inode_listsecurity, @@ -4309,6 +4321,7 @@ static struct security_operations selinux_ops = { .task_to_inode = selinux_task_to_inode, .ipc_permission = selinux_ipc_permission, + .ipc_getsecurity = selinux_ipc_getsecurity, .msg_msg_alloc_security = selinux_msg_msg_alloc_security, .msg_msg_free_security = selinux_msg_msg_free_security, @@ -4340,7 +4353,6 @@ static struct security_operations selinux_ops = { .getprocattr = selinux_getprocattr, .setprocattr = selinux_setprocattr, -#ifdef CONFIG_SECURITY_NETWORK .unix_stream_connect = selinux_socket_unix_stream_connect, .unix_may_send = selinux_socket_unix_may_send, @@ -4358,11 +4370,11 @@ static struct security_operations selinux_ops = { .socket_setsockopt = selinux_socket_setsockopt, .socket_shutdown = selinux_socket_shutdown, .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb, - .socket_getpeersec = selinux_socket_getpeersec, + .socket_getpeersec_stream = selinux_socket_getpeersec_stream, + .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram, .sk_alloc_security = selinux_sk_alloc_security, .sk_free_security = selinux_sk_free_security, .sk_getsid = selinux_sk_getsid_security, -#endif #ifdef CONFIG_SECURITY_NETWORK_XFRM .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, @@ -4391,6 +4403,9 @@ static __init int selinux_init(void) tsec = current->security; tsec->osid = tsec->sid = SECINITSID_KERNEL; + sel_inode_cache = kmem_cache_create("selinux_inode_security", + sizeof(struct inode_security_struct), + 0, SLAB_PANIC, NULL, NULL); avc_init(); original_ops = secondary_ops = security_ops; @@ -4440,7 +4455,7 @@ next_sb: all processes and objects when they are created. */ security_initcall(selinux_init); -#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_NETFILTER) +#if defined(CONFIG_NETFILTER) static struct nf_hook_ops selinux_ipv4_op = { .hook = selinux_ipv4_postroute_last, @@ -4501,13 +4516,13 @@ static void selinux_nf_ip_exit(void) } #endif -#else /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */ +#else /* CONFIG_NETFILTER */ #ifdef CONFIG_SECURITY_SELINUX_DISABLE #define selinux_nf_ip_exit() #endif -#endif /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */ +#endif /* CONFIG_NETFILTER */ #ifdef CONFIG_SECURITY_SELINUX_DISABLE int selinux_disable(void)