aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
authorPaul Moore <paul.moore@hp.com>2009-03-27 17:10:34 -0400
committerJames Morris <jmorris@namei.org>2009-03-28 00:01:36 -0400
commit389fb800ac8be2832efedd19978a2b8ced37eb61 (patch)
treefa0bc16050dfb491aa05f76b54fa4c167de96376 /security/selinux/hooks.c
parent284904aa79466a4736f4c775fdbe5c7407fa136c (diff)
netlabel: Label incoming TCP connections correctly in SELinux
The current NetLabel/SELinux behavior for incoming TCP connections works but only through a series of happy coincidences that rely on the limited nature of standard CIPSO (only able to convey MLS attributes) and the write equality imposed by the SELinux MLS constraints. The problem is that network sockets created as the result of an incoming TCP connection were not on-the-wire labeled based on the security attributes of the parent socket but rather based on the wire label of the remote peer. The issue had to do with how IP options were managed as part of the network stack and where the LSM hooks were in relation to the code which set the IP options on these newly created child sockets. While NetLabel/SELinux did correctly set the socket's on-the-wire label it was promptly cleared by the network stack and reset based on the IP options of the remote peer. This patch, in conjunction with a prior patch that adjusted the LSM hook locations, works to set the correct on-the-wire label format for new incoming connections through the security_inet_conn_request() hook. Besides the correct behavior there are many advantages to this change, the most significant is that all of the NetLabel socket labeling code in SELinux now lives in hooks which can return error codes to the core stack which allows us to finally get ride of the selinux_netlbl_inode_permission() logic which greatly simplfies the NetLabel/SELinux glue code. In the process of developing this patch I also ran into a small handful of AF_INET6 cleanliness issues that have been fixed which should make the code safer and easier to extend in the future. Signed-off-by: Paul Moore <paul.moore@hp.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c54
1 files changed, 15 insertions, 39 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 7c52ba243c64..ee2e781d11d7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -311,7 +311,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
311 ssec->sid = SECINITSID_UNLABELED; 311 ssec->sid = SECINITSID_UNLABELED;
312 sk->sk_security = ssec; 312 sk->sk_security = ssec;
313 313
314 selinux_netlbl_sk_security_reset(ssec, family); 314 selinux_netlbl_sk_security_reset(ssec);
315 315
316 return 0; 316 return 0;
317} 317}
@@ -2945,7 +2945,6 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid)
2945static int selinux_revalidate_file_permission(struct file *file, int mask) 2945static int selinux_revalidate_file_permission(struct file *file, int mask)
2946{ 2946{
2947 const struct cred *cred = current_cred(); 2947 const struct cred *cred = current_cred();
2948 int rc;
2949 struct inode *inode = file->f_path.dentry->d_inode; 2948 struct inode *inode = file->f_path.dentry->d_inode;
2950 2949
2951 if (!mask) { 2950 if (!mask) {
@@ -2957,29 +2956,15 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
2957 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) 2956 if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
2958 mask |= MAY_APPEND; 2957 mask |= MAY_APPEND;
2959 2958
2960 rc = file_has_perm(cred, file, 2959 return file_has_perm(cred, file,
2961 file_mask_to_av(inode->i_mode, mask)); 2960 file_mask_to_av(inode->i_mode, mask));
2962 if (rc)
2963 return rc;
2964
2965 return selinux_netlbl_inode_permission(inode, mask);
2966} 2961}
2967 2962
2968static int selinux_file_permission(struct file *file, int mask) 2963static int selinux_file_permission(struct file *file, int mask)
2969{ 2964{
2970 struct inode *inode = file->f_path.dentry->d_inode; 2965 if (!mask)
2971 struct file_security_struct *fsec = file->f_security;
2972 struct inode_security_struct *isec = inode->i_security;
2973 u32 sid = current_sid();
2974
2975 if (!mask) {
2976 /* No permission to check. Existence test. */ 2966 /* No permission to check. Existence test. */
2977 return 0; 2967 return 0;
2978 }
2979
2980 if (sid == fsec->sid && fsec->isid == isec->sid
2981 && fsec->pseqno == avc_policy_seqno())
2982 return selinux_netlbl_inode_permission(inode, mask);
2983 2968
2984 return selinux_revalidate_file_permission(file, mask); 2969 return selinux_revalidate_file_permission(file, mask);
2985} 2970}
@@ -3723,7 +3708,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
3723 sksec = sock->sk->sk_security; 3708 sksec = sock->sk->sk_security;
3724 sksec->sid = isec->sid; 3709 sksec->sid = isec->sid;
3725 sksec->sclass = isec->sclass; 3710 sksec->sclass = isec->sclass;
3726 err = selinux_netlbl_socket_post_create(sock); 3711 err = selinux_netlbl_socket_post_create(sock->sk, family);
3727 } 3712 }
3728 3713
3729 return err; 3714 return err;
@@ -3914,13 +3899,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
3914static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, 3899static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
3915 int size) 3900 int size)
3916{ 3901{
3917 int rc; 3902 return socket_has_perm(current, sock, SOCKET__WRITE);
3918
3919 rc = socket_has_perm(current, sock, SOCKET__WRITE);
3920 if (rc)
3921 return rc;
3922
3923 return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
3924} 3903}
3925 3904
3926static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, 3905static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -4304,7 +4283,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
4304 newssec->peer_sid = ssec->peer_sid; 4283 newssec->peer_sid = ssec->peer_sid;
4305 newssec->sclass = ssec->sclass; 4284 newssec->sclass = ssec->sclass;
4306 4285
4307 selinux_netlbl_sk_security_reset(newssec, newsk->sk_family); 4286 selinux_netlbl_sk_security_reset(newssec);
4308} 4287}
4309 4288
4310static void selinux_sk_getsecid(struct sock *sk, u32 *secid) 4289static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
@@ -4348,16 +4327,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4348 if (peersid == SECSID_NULL) { 4327 if (peersid == SECSID_NULL) {
4349 req->secid = sksec->sid; 4328 req->secid = sksec->sid;
4350 req->peer_secid = SECSID_NULL; 4329 req->peer_secid = SECSID_NULL;
4351 return 0; 4330 } else {
4331 err = security_sid_mls_copy(sksec->sid, peersid, &newsid);
4332 if (err)
4333 return err;
4334 req->secid = newsid;
4335 req->peer_secid = peersid;
4352 } 4336 }
4353 4337
4354 err = security_sid_mls_copy(sksec->sid, peersid, &newsid); 4338 return selinux_netlbl_inet_conn_request(req, family);
4355 if (err)
4356 return err;
4357
4358 req->secid = newsid;
4359 req->peer_secid = peersid;
4360 return 0;
4361} 4339}
4362 4340
4363static void selinux_inet_csk_clone(struct sock *newsk, 4341static void selinux_inet_csk_clone(struct sock *newsk,
@@ -4374,7 +4352,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
4374 4352
4375 /* We don't need to take any sort of lock here as we are the only 4353 /* We don't need to take any sort of lock here as we are the only
4376 * thread with access to newsksec */ 4354 * thread with access to newsksec */
4377 selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); 4355 selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
4378} 4356}
4379 4357
4380static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) 4358static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
@@ -4387,8 +4365,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
4387 family = PF_INET; 4365 family = PF_INET;
4388 4366
4389 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); 4367 selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
4390
4391 selinux_netlbl_inet_conn_established(sk, family);
4392} 4368}
4393 4369
4394static void selinux_req_classify_flow(const struct request_sock *req, 4370static void selinux_req_classify_flow(const struct request_sock *req,