diff options
Diffstat (limited to 'security/selinux/hooks.c')
| -rw-r--r-- | security/selinux/hooks.c | 209 |
1 files changed, 23 insertions, 186 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7c52ba243c64..2fcad7c33eaf 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -93,7 +93,6 @@ | |||
| 93 | 93 | ||
| 94 | extern unsigned int policydb_loaded_version; | 94 | extern unsigned int policydb_loaded_version; |
| 95 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); | 95 | extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); |
| 96 | extern int selinux_compat_net; | ||
| 97 | extern struct security_operations *security_ops; | 96 | extern struct security_operations *security_ops; |
| 98 | 97 | ||
| 99 | /* SECMARK reference count */ | 98 | /* SECMARK reference count */ |
| @@ -311,7 +310,7 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) | |||
| 311 | ssec->sid = SECINITSID_UNLABELED; | 310 | ssec->sid = SECINITSID_UNLABELED; |
| 312 | sk->sk_security = ssec; | 311 | sk->sk_security = ssec; |
| 313 | 312 | ||
| 314 | selinux_netlbl_sk_security_reset(ssec, family); | 313 | selinux_netlbl_sk_security_reset(ssec); |
| 315 | 314 | ||
| 316 | return 0; | 315 | return 0; |
| 317 | } | 316 | } |
| @@ -2945,7 +2944,6 @@ static void selinux_inode_getsecid(const struct inode *inode, u32 *secid) | |||
| 2945 | static int selinux_revalidate_file_permission(struct file *file, int mask) | 2944 | static int selinux_revalidate_file_permission(struct file *file, int mask) |
| 2946 | { | 2945 | { |
| 2947 | const struct cred *cred = current_cred(); | 2946 | const struct cred *cred = current_cred(); |
| 2948 | int rc; | ||
| 2949 | struct inode *inode = file->f_path.dentry->d_inode; | 2947 | struct inode *inode = file->f_path.dentry->d_inode; |
| 2950 | 2948 | ||
| 2951 | if (!mask) { | 2949 | if (!mask) { |
| @@ -2957,29 +2955,15 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) | |||
| 2957 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) | 2955 | if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) |
| 2958 | mask |= MAY_APPEND; | 2956 | mask |= MAY_APPEND; |
| 2959 | 2957 | ||
| 2960 | rc = file_has_perm(cred, file, | 2958 | return file_has_perm(cred, file, |
| 2961 | file_mask_to_av(inode->i_mode, mask)); | 2959 | file_mask_to_av(inode->i_mode, mask)); |
| 2962 | if (rc) | ||
| 2963 | return rc; | ||
| 2964 | |||
| 2965 | return selinux_netlbl_inode_permission(inode, mask); | ||
| 2966 | } | 2960 | } |
| 2967 | 2961 | ||
| 2968 | static int selinux_file_permission(struct file *file, int mask) | 2962 | static int selinux_file_permission(struct file *file, int mask) |
| 2969 | { | 2963 | { |
| 2970 | struct inode *inode = file->f_path.dentry->d_inode; | 2964 | 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. */ | 2965 | /* No permission to check. Existence test. */ |
| 2977 | return 0; | 2966 | 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 | 2967 | ||
| 2984 | return selinux_revalidate_file_permission(file, mask); | 2968 | return selinux_revalidate_file_permission(file, mask); |
| 2985 | } | 2969 | } |
| @@ -3169,7 +3153,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk, | |||
| 3169 | struct fown_struct *fown, int signum) | 3153 | struct fown_struct *fown, int signum) |
| 3170 | { | 3154 | { |
| 3171 | struct file *file; | 3155 | struct file *file; |
| 3172 | u32 sid = current_sid(); | 3156 | u32 sid = task_sid(tsk); |
| 3173 | u32 perm; | 3157 | u32 perm; |
| 3174 | struct file_security_struct *fsec; | 3158 | struct file_security_struct *fsec; |
| 3175 | 3159 | ||
| @@ -3723,7 +3707,7 @@ static int selinux_socket_post_create(struct socket *sock, int family, | |||
| 3723 | sksec = sock->sk->sk_security; | 3707 | sksec = sock->sk->sk_security; |
| 3724 | sksec->sid = isec->sid; | 3708 | sksec->sid = isec->sid; |
| 3725 | sksec->sclass = isec->sclass; | 3709 | sksec->sclass = isec->sclass; |
| 3726 | err = selinux_netlbl_socket_post_create(sock); | 3710 | err = selinux_netlbl_socket_post_create(sock->sk, family); |
| 3727 | } | 3711 | } |
| 3728 | 3712 | ||
| 3729 | return err; | 3713 | return err; |
| @@ -3914,13 +3898,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock) | |||
| 3914 | static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, | 3898 | static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, |
| 3915 | int size) | 3899 | int size) |
| 3916 | { | 3900 | { |
| 3917 | int rc; | 3901 | 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 | } | 3902 | } |
| 3925 | 3903 | ||
| 3926 | static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, | 3904 | static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, |
| @@ -4040,72 +4018,6 @@ static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, | |||
| 4040 | SECCLASS_NODE, NODE__RECVFROM, ad); | 4018 | SECCLASS_NODE, NODE__RECVFROM, ad); |
| 4041 | } | 4019 | } |
| 4042 | 4020 | ||
| 4043 | static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | ||
| 4044 | struct sk_buff *skb, | ||
| 4045 | struct avc_audit_data *ad, | ||
| 4046 | u16 family, | ||
| 4047 | char *addrp) | ||
| 4048 | { | ||
| 4049 | int err; | ||
| 4050 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4051 | u16 sk_class; | ||
| 4052 | u32 netif_perm, node_perm, recv_perm; | ||
| 4053 | u32 port_sid, node_sid, if_sid, sk_sid; | ||
| 4054 | |||
| 4055 | sk_sid = sksec->sid; | ||
| 4056 | sk_class = sksec->sclass; | ||
| 4057 | |||
| 4058 | switch (sk_class) { | ||
| 4059 | case SECCLASS_UDP_SOCKET: | ||
| 4060 | netif_perm = NETIF__UDP_RECV; | ||
| 4061 | node_perm = NODE__UDP_RECV; | ||
| 4062 | recv_perm = UDP_SOCKET__RECV_MSG; | ||
| 4063 | break; | ||
| 4064 | case SECCLASS_TCP_SOCKET: | ||
| 4065 | netif_perm = NETIF__TCP_RECV; | ||
| 4066 | node_perm = NODE__TCP_RECV; | ||
| 4067 | recv_perm = TCP_SOCKET__RECV_MSG; | ||
| 4068 | break; | ||
| 4069 | case SECCLASS_DCCP_SOCKET: | ||
| 4070 | netif_perm = NETIF__DCCP_RECV; | ||
| 4071 | node_perm = NODE__DCCP_RECV; | ||
| 4072 | recv_perm = DCCP_SOCKET__RECV_MSG; | ||
| 4073 | break; | ||
| 4074 | default: | ||
| 4075 | netif_perm = NETIF__RAWIP_RECV; | ||
| 4076 | node_perm = NODE__RAWIP_RECV; | ||
| 4077 | recv_perm = 0; | ||
| 4078 | break; | ||
| 4079 | } | ||
| 4080 | |||
| 4081 | err = sel_netif_sid(skb->iif, &if_sid); | ||
| 4082 | if (err) | ||
| 4083 | return err; | ||
| 4084 | err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | ||
| 4085 | if (err) | ||
| 4086 | return err; | ||
| 4087 | |||
| 4088 | err = sel_netnode_sid(addrp, family, &node_sid); | ||
| 4089 | if (err) | ||
| 4090 | return err; | ||
| 4091 | err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); | ||
| 4092 | if (err) | ||
| 4093 | return err; | ||
| 4094 | |||
| 4095 | if (!recv_perm) | ||
| 4096 | return 0; | ||
| 4097 | err = sel_netport_sid(sk->sk_protocol, | ||
| 4098 | ntohs(ad->u.net.sport), &port_sid); | ||
| 4099 | if (unlikely(err)) { | ||
| 4100 | printk(KERN_WARNING | ||
| 4101 | "SELinux: failure in" | ||
| 4102 | " selinux_sock_rcv_skb_iptables_compat()," | ||
| 4103 | " network port label not found\n"); | ||
| 4104 | return err; | ||
| 4105 | } | ||
| 4106 | return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad); | ||
| 4107 | } | ||
| 4108 | |||
| 4109 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 4021 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
| 4110 | u16 family) | 4022 | u16 family) |
| 4111 | { | 4023 | { |
| @@ -4123,14 +4035,12 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
| 4123 | if (err) | 4035 | if (err) |
| 4124 | return err; | 4036 | return err; |
| 4125 | 4037 | ||
| 4126 | if (selinux_compat_net) | 4038 | if (selinux_secmark_enabled()) { |
| 4127 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, | ||
| 4128 | family, addrp); | ||
| 4129 | else if (selinux_secmark_enabled()) | ||
| 4130 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4039 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
| 4131 | PACKET__RECV, &ad); | 4040 | PACKET__RECV, &ad); |
| 4132 | if (err) | 4041 | if (err) |
| 4133 | return err; | 4042 | return err; |
| 4043 | } | ||
| 4134 | 4044 | ||
| 4135 | if (selinux_policycap_netpeer) { | 4045 | if (selinux_policycap_netpeer) { |
| 4136 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4046 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
| @@ -4172,7 +4082,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
| 4172 | * to the selinux_sock_rcv_skb_compat() function to deal with the | 4082 | * to the selinux_sock_rcv_skb_compat() function to deal with the |
| 4173 | * special handling. We do this in an attempt to keep this function | 4083 | * special handling. We do this in an attempt to keep this function |
| 4174 | * as fast and as clean as possible. */ | 4084 | * as fast and as clean as possible. */ |
| 4175 | if (selinux_compat_net || !selinux_policycap_netpeer) | 4085 | if (!selinux_policycap_netpeer) |
| 4176 | return selinux_sock_rcv_skb_compat(sk, skb, family); | 4086 | return selinux_sock_rcv_skb_compat(sk, skb, family); |
| 4177 | 4087 | ||
| 4178 | secmark_active = selinux_secmark_enabled(); | 4088 | secmark_active = selinux_secmark_enabled(); |
| @@ -4304,7 +4214,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) | |||
| 4304 | newssec->peer_sid = ssec->peer_sid; | 4214 | newssec->peer_sid = ssec->peer_sid; |
| 4305 | newssec->sclass = ssec->sclass; | 4215 | newssec->sclass = ssec->sclass; |
| 4306 | 4216 | ||
| 4307 | selinux_netlbl_sk_security_reset(newssec, newsk->sk_family); | 4217 | selinux_netlbl_sk_security_reset(newssec); |
| 4308 | } | 4218 | } |
| 4309 | 4219 | ||
| 4310 | static void selinux_sk_getsecid(struct sock *sk, u32 *secid) | 4220 | static void selinux_sk_getsecid(struct sock *sk, u32 *secid) |
| @@ -4348,16 +4258,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
| 4348 | if (peersid == SECSID_NULL) { | 4258 | if (peersid == SECSID_NULL) { |
| 4349 | req->secid = sksec->sid; | 4259 | req->secid = sksec->sid; |
| 4350 | req->peer_secid = SECSID_NULL; | 4260 | req->peer_secid = SECSID_NULL; |
| 4351 | return 0; | 4261 | } else { |
| 4262 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | ||
| 4263 | if (err) | ||
| 4264 | return err; | ||
| 4265 | req->secid = newsid; | ||
| 4266 | req->peer_secid = peersid; | ||
| 4352 | } | 4267 | } |
| 4353 | 4268 | ||
| 4354 | err = security_sid_mls_copy(sksec->sid, peersid, &newsid); | 4269 | 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 | } | 4270 | } |
| 4362 | 4271 | ||
| 4363 | static void selinux_inet_csk_clone(struct sock *newsk, | 4272 | static void selinux_inet_csk_clone(struct sock *newsk, |
| @@ -4374,7 +4283,7 @@ static void selinux_inet_csk_clone(struct sock *newsk, | |||
| 4374 | 4283 | ||
| 4375 | /* We don't need to take any sort of lock here as we are the only | 4284 | /* We don't need to take any sort of lock here as we are the only |
| 4376 | * thread with access to newsksec */ | 4285 | * thread with access to newsksec */ |
| 4377 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); | 4286 | selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family); |
| 4378 | } | 4287 | } |
| 4379 | 4288 | ||
| 4380 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) | 4289 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) |
| @@ -4387,8 +4296,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) | |||
| 4387 | family = PF_INET; | 4296 | family = PF_INET; |
| 4388 | 4297 | ||
| 4389 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | 4298 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); |
| 4390 | |||
| 4391 | selinux_netlbl_inet_conn_established(sk, family); | ||
| 4392 | } | 4299 | } |
| 4393 | 4300 | ||
| 4394 | static void selinux_req_classify_flow(const struct request_sock *req, | 4301 | static void selinux_req_classify_flow(const struct request_sock *req, |
| @@ -4540,71 +4447,6 @@ static unsigned int selinux_ipv4_output(unsigned int hooknum, | |||
| 4540 | return selinux_ip_output(skb, PF_INET); | 4447 | return selinux_ip_output(skb, PF_INET); |
| 4541 | } | 4448 | } |
| 4542 | 4449 | ||
| 4543 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | ||
| 4544 | int ifindex, | ||
| 4545 | struct avc_audit_data *ad, | ||
| 4546 | u16 family, char *addrp) | ||
| 4547 | { | ||
| 4548 | int err; | ||
| 4549 | struct sk_security_struct *sksec = sk->sk_security; | ||
| 4550 | u16 sk_class; | ||
| 4551 | u32 netif_perm, node_perm, send_perm; | ||
| 4552 | u32 port_sid, node_sid, if_sid, sk_sid; | ||
| 4553 | |||
| 4554 | sk_sid = sksec->sid; | ||
| 4555 | sk_class = sksec->sclass; | ||
| 4556 | |||
| 4557 | switch (sk_class) { | ||
| 4558 | case SECCLASS_UDP_SOCKET: | ||
| 4559 | netif_perm = NETIF__UDP_SEND; | ||
| 4560 | node_perm = NODE__UDP_SEND; | ||
| 4561 | send_perm = UDP_SOCKET__SEND_MSG; | ||
| 4562 | break; | ||
| 4563 | case SECCLASS_TCP_SOCKET: | ||
| 4564 | netif_perm = NETIF__TCP_SEND; | ||
| 4565 | node_perm = NODE__TCP_SEND; | ||
| 4566 | send_perm = TCP_SOCKET__SEND_MSG; | ||
| 4567 | break; | ||
| 4568 | case SECCLASS_DCCP_SOCKET: | ||
| 4569 | netif_perm = NETIF__DCCP_SEND; | ||
| 4570 | node_perm = NODE__DCCP_SEND; | ||
| 4571 | send_perm = DCCP_SOCKET__SEND_MSG; | ||
| 4572 | break; | ||
| 4573 | default: | ||
| 4574 | netif_perm = NETIF__RAWIP_SEND; | ||
| 4575 | node_perm = NODE__RAWIP_SEND; | ||
| 4576 | send_perm = 0; | ||
| 4577 | break; | ||
| 4578 | } | ||
| 4579 | |||
| 4580 | err = sel_netif_sid(ifindex, &if_sid); | ||
| 4581 | if (err) | ||
| 4582 | return err; | ||
| 4583 | err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); | ||
| 4584 | return err; | ||
| 4585 | |||
| 4586 | err = sel_netnode_sid(addrp, family, &node_sid); | ||
| 4587 | if (err) | ||
| 4588 | return err; | ||
| 4589 | err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); | ||
| 4590 | if (err) | ||
| 4591 | return err; | ||
| 4592 | |||
| 4593 | if (send_perm != 0) | ||
| 4594 | return 0; | ||
| 4595 | |||
| 4596 | err = sel_netport_sid(sk->sk_protocol, | ||
| 4597 | ntohs(ad->u.net.dport), &port_sid); | ||
| 4598 | if (unlikely(err)) { | ||
| 4599 | printk(KERN_WARNING | ||
| 4600 | "SELinux: failure in" | ||
| 4601 | " selinux_ip_postroute_iptables_compat()," | ||
| 4602 | " network port label not found\n"); | ||
| 4603 | return err; | ||
| 4604 | } | ||
| 4605 | return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad); | ||
| 4606 | } | ||
| 4607 | |||
| 4608 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | 4450 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, |
| 4609 | int ifindex, | 4451 | int ifindex, |
| 4610 | u16 family) | 4452 | u16 family) |
| @@ -4625,15 +4467,10 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
| 4625 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | 4467 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) |
| 4626 | return NF_DROP; | 4468 | return NF_DROP; |
| 4627 | 4469 | ||
| 4628 | if (selinux_compat_net) { | 4470 | if (selinux_secmark_enabled()) |
| 4629 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, | ||
| 4630 | &ad, family, addrp)) | ||
| 4631 | return NF_DROP; | ||
| 4632 | } else if (selinux_secmark_enabled()) { | ||
| 4633 | if (avc_has_perm(sksec->sid, skb->secmark, | 4471 | if (avc_has_perm(sksec->sid, skb->secmark, |
| 4634 | SECCLASS_PACKET, PACKET__SEND, &ad)) | 4472 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
| 4635 | return NF_DROP; | 4473 | return NF_DROP; |
| 4636 | } | ||
| 4637 | 4474 | ||
| 4638 | if (selinux_policycap_netpeer) | 4475 | if (selinux_policycap_netpeer) |
| 4639 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) | 4476 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) |
| @@ -4657,7 +4494,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
| 4657 | * to the selinux_ip_postroute_compat() function to deal with the | 4494 | * to the selinux_ip_postroute_compat() function to deal with the |
| 4658 | * special handling. We do this in an attempt to keep this function | 4495 | * special handling. We do this in an attempt to keep this function |
| 4659 | * as fast and as clean as possible. */ | 4496 | * as fast and as clean as possible. */ |
| 4660 | if (selinux_compat_net || !selinux_policycap_netpeer) | 4497 | if (!selinux_policycap_netpeer) |
| 4661 | return selinux_ip_postroute_compat(skb, ifindex, family); | 4498 | return selinux_ip_postroute_compat(skb, ifindex, family); |
| 4662 | #ifdef CONFIG_XFRM | 4499 | #ifdef CONFIG_XFRM |
| 4663 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | 4500 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
