From b4e0d5f0791bd6dd12a1c1edea0340969c7c1f90 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 24 Nov 2010 17:12:10 -0800 Subject: Smack: UDS revision This patch addresses a number of long standing issues with the way Smack treats UNIX domain sockets. All access control was being done based on the label of the file system object. This is inconsistant with the internet domain, in which access is done based on the IPIN and IPOUT attributes of the socket. As a result of the inode label policy it was not possible to use a UDS socket for label cognizant services, including dbus and the X11 server. Support for SCM_PEERSEC on UDS sockets is also provided. Signed-off-by: Casey Schaufler Signed-off-by: James Morris --- security/smack/smack_lsm.c | 106 +++++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 43 deletions(-) (limited to 'security') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 489a85afa477..04a98c361a65 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1667,10 +1667,13 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ssp->smk_in = sp; else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { ssp->smk_out = sp; - rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); - if (rc != 0) - printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", - __func__, -rc); + if (sock->sk->sk_family != PF_UNIX) { + rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); + if (rc != 0) + printk(KERN_WARNING + "Smack: \"%s\" netlbl error %d.\n", + __func__, -rc); + } } else return -EOPNOTSUPP; @@ -2267,9 +2270,10 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) break; case SOCKFS_MAGIC: /* - * Casey says sockets get the smack of the task. + * Socket access is controlled by the socket + * structures associated with the task involved. */ - final = csp; + final = smack_known_star.smk_known; break; case PROC_SUPER_MAGIC: /* @@ -2296,7 +2300,16 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) /* * This isn't an understood special case. * Get the value from the xattr. - * + */ + + /* + * UNIX domain sockets use lower level socket data. + */ + if (S_ISSOCK(inode->i_mode)) { + final = smack_known_star.smk_known; + break; + } + /* * No xattr support means, alas, no SMACK label. * Use the aforeapplied default. * It would be curious if the label of the task @@ -2418,14 +2431,18 @@ static int smack_setprocattr(struct task_struct *p, char *name, static int smack_unix_stream_connect(struct socket *sock, struct socket *other, struct sock *newsk) { - struct inode *sp = SOCK_INODE(sock); - struct inode *op = SOCK_INODE(other); + struct socket_smack *ssp = sock->sk->sk_security; + struct socket_smack *osp = other->sk->sk_security; struct smk_audit_info ad; + int rc = 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); smk_ad_setfield_u_net_sk(&ad, other->sk); - return smk_access(smk_of_inode(sp), smk_of_inode(op), - MAY_READWRITE, &ad); + + if (!capable(CAP_MAC_OVERRIDE)) + rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); + + return rc; } /** @@ -2438,13 +2455,18 @@ static int smack_unix_stream_connect(struct socket *sock, */ static int smack_unix_may_send(struct socket *sock, struct socket *other) { - struct inode *sp = SOCK_INODE(sock); - struct inode *op = SOCK_INODE(other); + struct socket_smack *ssp = sock->sk->sk_security; + struct socket_smack *osp = other->sk->sk_security; struct smk_audit_info ad; + int rc = 0; smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); smk_ad_setfield_u_net_sk(&ad, other->sk); - return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE, &ad); + + if (!capable(CAP_MAC_OVERRIDE)) + rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); + + return rc; } /** @@ -2629,7 +2651,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock, /** * smack_socket_getpeersec_dgram - pull in packet label - * @sock: the socket + * @sock: the peer socket * @skb: packet data * @secid: pointer to where to put the secid of the packet * @@ -2640,41 +2662,39 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, { struct netlbl_lsm_secattr secattr; - struct sock *sk; + struct socket_smack *sp; char smack[SMK_LABELLEN]; - int family = PF_INET; - u32 s; + int family = PF_UNSPEC; + u32 s = 0; /* 0 is the invalid secid */ int rc; - /* - * Only works for families with packets. - */ - if (sock != NULL) { - sk = sock->sk; - if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) - return 0; - family = sk->sk_family; + if (skb != NULL) { + if (skb->protocol == htons(ETH_P_IP)) + family = PF_INET; + else if (skb->protocol == htons(ETH_P_IPV6)) + family = PF_INET6; } - /* - * Translate what netlabel gave us. - */ - netlbl_secattr_init(&secattr); - rc = netlbl_skbuff_getattr(skb, family, &secattr); - if (rc == 0) - smack_from_secattr(&secattr, smack); - netlbl_secattr_destroy(&secattr); - - /* - * Give up if we couldn't get anything - */ - if (rc != 0) - return rc; + if (family == PF_UNSPEC && sock != NULL) + family = sock->sk->sk_family; - s = smack_to_secid(smack); + if (family == PF_UNIX) { + sp = sock->sk->sk_security; + s = smack_to_secid(sp->smk_out); + } else if (family == PF_INET || family == PF_INET6) { + /* + * Translate what netlabel gave us. + */ + netlbl_secattr_init(&secattr); + rc = netlbl_skbuff_getattr(skb, family, &secattr); + if (rc == 0) { + smack_from_secattr(&secattr, smack); + s = smack_to_secid(smack); + } + netlbl_secattr_destroy(&secattr); + } + *secid = s; if (s == 0) return -EINVAL; - - *secid = s; return 0; } -- cgit v1.2.2