diff options
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r-- | security/selinux/hooks.c | 296 |
1 files changed, 210 insertions, 86 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 03fc6a81ae32..576e51199079 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -291,6 +291,7 @@ static void sk_free_security(struct sock *sk) | |||
291 | struct sk_security_struct *ssec = sk->sk_security; | 291 | struct sk_security_struct *ssec = sk->sk_security; |
292 | 292 | ||
293 | sk->sk_security = NULL; | 293 | sk->sk_security = NULL; |
294 | selinux_netlbl_sk_security_free(ssec); | ||
294 | kfree(ssec); | 295 | kfree(ssec); |
295 | } | 296 | } |
296 | 297 | ||
@@ -324,7 +325,7 @@ enum { | |||
324 | Opt_rootcontext = 4, | 325 | Opt_rootcontext = 4, |
325 | }; | 326 | }; |
326 | 327 | ||
327 | static match_table_t tokens = { | 328 | static const match_table_t tokens = { |
328 | {Opt_context, CONTEXT_STR "%s"}, | 329 | {Opt_context, CONTEXT_STR "%s"}, |
329 | {Opt_fscontext, FSCONTEXT_STR "%s"}, | 330 | {Opt_fscontext, FSCONTEXT_STR "%s"}, |
330 | {Opt_defcontext, DEFCONTEXT_STR "%s"}, | 331 | {Opt_defcontext, DEFCONTEXT_STR "%s"}, |
@@ -957,7 +958,8 @@ out_err: | |||
957 | return rc; | 958 | return rc; |
958 | } | 959 | } |
959 | 960 | ||
960 | void selinux_write_opts(struct seq_file *m, struct security_mnt_opts *opts) | 961 | static void selinux_write_opts(struct seq_file *m, |
962 | struct security_mnt_opts *opts) | ||
961 | { | 963 | { |
962 | int i; | 964 | int i; |
963 | char *prefix; | 965 | char *prefix; |
@@ -1290,7 +1292,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent | |||
1290 | /* Default to the fs superblock SID. */ | 1292 | /* Default to the fs superblock SID. */ |
1291 | isec->sid = sbsec->sid; | 1293 | isec->sid = sbsec->sid; |
1292 | 1294 | ||
1293 | if (sbsec->proc) { | 1295 | if (sbsec->proc && !S_ISLNK(inode->i_mode)) { |
1294 | struct proc_inode *proci = PROC_I(inode); | 1296 | struct proc_inode *proci = PROC_I(inode); |
1295 | if (proci->pde) { | 1297 | if (proci->pde) { |
1296 | isec->sclass = inode_mode_to_security_class(inode->i_mode); | 1298 | isec->sclass = inode_mode_to_security_class(inode->i_mode); |
@@ -2120,7 +2122,6 @@ static inline void flush_unauthorized_files(struct files_struct *files) | |||
2120 | long j = -1; | 2122 | long j = -1; |
2121 | int drop_tty = 0; | 2123 | int drop_tty = 0; |
2122 | 2124 | ||
2123 | mutex_lock(&tty_mutex); | ||
2124 | tty = get_current_tty(); | 2125 | tty = get_current_tty(); |
2125 | if (tty) { | 2126 | if (tty) { |
2126 | file_list_lock(); | 2127 | file_list_lock(); |
@@ -2138,8 +2139,8 @@ static inline void flush_unauthorized_files(struct files_struct *files) | |||
2138 | } | 2139 | } |
2139 | } | 2140 | } |
2140 | file_list_unlock(); | 2141 | file_list_unlock(); |
2142 | tty_kref_put(tty); | ||
2141 | } | 2143 | } |
2142 | mutex_unlock(&tty_mutex); | ||
2143 | /* Reset controlling tty. */ | 2144 | /* Reset controlling tty. */ |
2144 | if (drop_tty) | 2145 | if (drop_tty) |
2145 | no_tty(); | 2146 | no_tty(); |
@@ -3548,38 +3549,44 @@ out: | |||
3548 | #endif /* IPV6 */ | 3549 | #endif /* IPV6 */ |
3549 | 3550 | ||
3550 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, | 3551 | static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, |
3551 | char **addrp, int src, u8 *proto) | 3552 | char **_addrp, int src, u8 *proto) |
3552 | { | 3553 | { |
3553 | int ret = 0; | 3554 | char *addrp; |
3555 | int ret; | ||
3554 | 3556 | ||
3555 | switch (ad->u.net.family) { | 3557 | switch (ad->u.net.family) { |
3556 | case PF_INET: | 3558 | case PF_INET: |
3557 | ret = selinux_parse_skb_ipv4(skb, ad, proto); | 3559 | ret = selinux_parse_skb_ipv4(skb, ad, proto); |
3558 | if (ret || !addrp) | 3560 | if (ret) |
3559 | break; | 3561 | goto parse_error; |
3560 | *addrp = (char *)(src ? &ad->u.net.v4info.saddr : | 3562 | addrp = (char *)(src ? &ad->u.net.v4info.saddr : |
3561 | &ad->u.net.v4info.daddr); | 3563 | &ad->u.net.v4info.daddr); |
3562 | break; | 3564 | goto okay; |
3563 | 3565 | ||
3564 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 3566 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
3565 | case PF_INET6: | 3567 | case PF_INET6: |
3566 | ret = selinux_parse_skb_ipv6(skb, ad, proto); | 3568 | ret = selinux_parse_skb_ipv6(skb, ad, proto); |
3567 | if (ret || !addrp) | 3569 | if (ret) |
3568 | break; | 3570 | goto parse_error; |
3569 | *addrp = (char *)(src ? &ad->u.net.v6info.saddr : | 3571 | addrp = (char *)(src ? &ad->u.net.v6info.saddr : |
3570 | &ad->u.net.v6info.daddr); | 3572 | &ad->u.net.v6info.daddr); |
3571 | break; | 3573 | goto okay; |
3572 | #endif /* IPV6 */ | 3574 | #endif /* IPV6 */ |
3573 | default: | 3575 | default: |
3574 | break; | 3576 | addrp = NULL; |
3577 | goto okay; | ||
3575 | } | 3578 | } |
3576 | 3579 | ||
3577 | if (unlikely(ret)) | 3580 | parse_error: |
3578 | printk(KERN_WARNING | 3581 | printk(KERN_WARNING |
3579 | "SELinux: failure in selinux_parse_skb()," | 3582 | "SELinux: failure in selinux_parse_skb()," |
3580 | " unable to parse packet\n"); | 3583 | " unable to parse packet\n"); |
3581 | |||
3582 | return ret; | 3584 | return ret; |
3585 | |||
3586 | okay: | ||
3587 | if (_addrp) | ||
3588 | *_addrp = addrp; | ||
3589 | return 0; | ||
3583 | } | 3590 | } |
3584 | 3591 | ||
3585 | /** | 3592 | /** |
@@ -3794,6 +3801,7 @@ out: | |||
3794 | 3801 | ||
3795 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) | 3802 | static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) |
3796 | { | 3803 | { |
3804 | struct sock *sk = sock->sk; | ||
3797 | struct inode_security_struct *isec; | 3805 | struct inode_security_struct *isec; |
3798 | int err; | 3806 | int err; |
3799 | 3807 | ||
@@ -3807,7 +3815,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3807 | isec = SOCK_INODE(sock)->i_security; | 3815 | isec = SOCK_INODE(sock)->i_security; |
3808 | if (isec->sclass == SECCLASS_TCP_SOCKET || | 3816 | if (isec->sclass == SECCLASS_TCP_SOCKET || |
3809 | isec->sclass == SECCLASS_DCCP_SOCKET) { | 3817 | isec->sclass == SECCLASS_DCCP_SOCKET) { |
3810 | struct sock *sk = sock->sk; | ||
3811 | struct avc_audit_data ad; | 3818 | struct avc_audit_data ad; |
3812 | struct sockaddr_in *addr4 = NULL; | 3819 | struct sockaddr_in *addr4 = NULL; |
3813 | struct sockaddr_in6 *addr6 = NULL; | 3820 | struct sockaddr_in6 *addr6 = NULL; |
@@ -3841,6 +3848,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3841 | goto out; | 3848 | goto out; |
3842 | } | 3849 | } |
3843 | 3850 | ||
3851 | err = selinux_netlbl_socket_connect(sk, address); | ||
3852 | |||
3844 | out: | 3853 | out: |
3845 | return err; | 3854 | return err; |
3846 | } | 3855 | } |
@@ -4070,20 +4079,28 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, | |||
4070 | } | 4079 | } |
4071 | 4080 | ||
4072 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | 4081 | static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, |
4073 | struct avc_audit_data *ad, | 4082 | u16 family) |
4074 | u16 family, char *addrp) | ||
4075 | { | 4083 | { |
4076 | int err; | 4084 | int err; |
4077 | struct sk_security_struct *sksec = sk->sk_security; | 4085 | struct sk_security_struct *sksec = sk->sk_security; |
4078 | u32 peer_sid; | 4086 | u32 peer_sid; |
4079 | u32 sk_sid = sksec->sid; | 4087 | u32 sk_sid = sksec->sid; |
4088 | struct avc_audit_data ad; | ||
4089 | char *addrp; | ||
4090 | |||
4091 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4092 | ad.u.net.netif = skb->iif; | ||
4093 | ad.u.net.family = family; | ||
4094 | err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); | ||
4095 | if (err) | ||
4096 | return err; | ||
4080 | 4097 | ||
4081 | if (selinux_compat_net) | 4098 | if (selinux_compat_net) |
4082 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad, | 4099 | err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, |
4083 | family, addrp); | 4100 | family, addrp); |
4084 | else | 4101 | else |
4085 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4102 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
4086 | PACKET__RECV, ad); | 4103 | PACKET__RECV, &ad); |
4087 | if (err) | 4104 | if (err) |
4088 | return err; | 4105 | return err; |
4089 | 4106 | ||
@@ -4092,12 +4109,14 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4092 | if (err) | 4109 | if (err) |
4093 | return err; | 4110 | return err; |
4094 | err = avc_has_perm(sk_sid, peer_sid, | 4111 | err = avc_has_perm(sk_sid, peer_sid, |
4095 | SECCLASS_PEER, PEER__RECV, ad); | 4112 | SECCLASS_PEER, PEER__RECV, &ad); |
4113 | if (err) | ||
4114 | selinux_netlbl_err(skb, err, 0); | ||
4096 | } else { | 4115 | } else { |
4097 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad); | 4116 | err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); |
4098 | if (err) | 4117 | if (err) |
4099 | return err; | 4118 | return err; |
4100 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad); | 4119 | err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); |
4101 | } | 4120 | } |
4102 | 4121 | ||
4103 | return err; | 4122 | return err; |
@@ -4111,6 +4130,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4111 | u32 sk_sid = sksec->sid; | 4130 | u32 sk_sid = sksec->sid; |
4112 | struct avc_audit_data ad; | 4131 | struct avc_audit_data ad; |
4113 | char *addrp; | 4132 | char *addrp; |
4133 | u8 secmark_active; | ||
4134 | u8 peerlbl_active; | ||
4114 | 4135 | ||
4115 | if (family != PF_INET && family != PF_INET6) | 4136 | if (family != PF_INET && family != PF_INET6) |
4116 | return 0; | 4137 | return 0; |
@@ -4119,6 +4140,18 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4119 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | 4140 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) |
4120 | family = PF_INET; | 4141 | family = PF_INET; |
4121 | 4142 | ||
4143 | /* If any sort of compatibility mode is enabled then handoff processing | ||
4144 | * to the selinux_sock_rcv_skb_compat() function to deal with the | ||
4145 | * special handling. We do this in an attempt to keep this function | ||
4146 | * as fast and as clean as possible. */ | ||
4147 | if (selinux_compat_net || !selinux_policycap_netpeer) | ||
4148 | return selinux_sock_rcv_skb_compat(sk, skb, family); | ||
4149 | |||
4150 | secmark_active = selinux_secmark_enabled(); | ||
4151 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | ||
4152 | if (!secmark_active && !peerlbl_active) | ||
4153 | return 0; | ||
4154 | |||
4122 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4155 | AVC_AUDIT_DATA_INIT(&ad, NET); |
4123 | ad.u.net.netif = skb->iif; | 4156 | ad.u.net.netif = skb->iif; |
4124 | ad.u.net.family = family; | 4157 | ad.u.net.family = family; |
@@ -4126,15 +4159,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4126 | if (err) | 4159 | if (err) |
4127 | return err; | 4160 | return err; |
4128 | 4161 | ||
4129 | /* If any sort of compatibility mode is enabled then handoff processing | 4162 | if (peerlbl_active) { |
4130 | * to the selinux_sock_rcv_skb_compat() function to deal with the | ||
4131 | * special handling. We do this in an attempt to keep this function | ||
4132 | * as fast and as clean as possible. */ | ||
4133 | if (selinux_compat_net || !selinux_policycap_netpeer) | ||
4134 | return selinux_sock_rcv_skb_compat(sk, skb, &ad, | ||
4135 | family, addrp); | ||
4136 | |||
4137 | if (netlbl_enabled() || selinux_xfrm_enabled()) { | ||
4138 | u32 peer_sid; | 4163 | u32 peer_sid; |
4139 | 4164 | ||
4140 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); | 4165 | err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); |
@@ -4142,13 +4167,17 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4142 | return err; | 4167 | return err; |
4143 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, | 4168 | err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, |
4144 | peer_sid, &ad); | 4169 | peer_sid, &ad); |
4145 | if (err) | 4170 | if (err) { |
4171 | selinux_netlbl_err(skb, err, 0); | ||
4146 | return err; | 4172 | return err; |
4173 | } | ||
4147 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, | 4174 | err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, |
4148 | PEER__RECV, &ad); | 4175 | PEER__RECV, &ad); |
4176 | if (err) | ||
4177 | selinux_netlbl_err(skb, err, 0); | ||
4149 | } | 4178 | } |
4150 | 4179 | ||
4151 | if (selinux_secmark_enabled()) { | 4180 | if (secmark_active) { |
4152 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, | 4181 | err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, |
4153 | PACKET__RECV, &ad); | 4182 | PACKET__RECV, &ad); |
4154 | if (err) | 4183 | if (err) |
@@ -4207,10 +4236,12 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff * | |||
4207 | u32 peer_secid = SECSID_NULL; | 4236 | u32 peer_secid = SECSID_NULL; |
4208 | u16 family; | 4237 | u16 family; |
4209 | 4238 | ||
4210 | if (sock) | 4239 | if (skb && skb->protocol == htons(ETH_P_IP)) |
4240 | family = PF_INET; | ||
4241 | else if (skb && skb->protocol == htons(ETH_P_IPV6)) | ||
4242 | family = PF_INET6; | ||
4243 | else if (sock) | ||
4211 | family = sock->sk->sk_family; | 4244 | family = sock->sk->sk_family; |
4212 | else if (skb && skb->sk) | ||
4213 | family = skb->sk->sk_family; | ||
4214 | else | 4245 | else |
4215 | goto out; | 4246 | goto out; |
4216 | 4247 | ||
@@ -4268,8 +4299,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) | |||
4268 | sk->sk_family == PF_UNIX) | 4299 | sk->sk_family == PF_UNIX) |
4269 | isec->sid = sksec->sid; | 4300 | isec->sid = sksec->sid; |
4270 | sksec->sclass = isec->sclass; | 4301 | sksec->sclass = isec->sclass; |
4271 | |||
4272 | selinux_netlbl_sock_graft(sk, parent); | ||
4273 | } | 4302 | } |
4274 | 4303 | ||
4275 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | 4304 | static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, |
@@ -4277,10 +4306,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
4277 | { | 4306 | { |
4278 | struct sk_security_struct *sksec = sk->sk_security; | 4307 | struct sk_security_struct *sksec = sk->sk_security; |
4279 | int err; | 4308 | int err; |
4309 | u16 family = sk->sk_family; | ||
4280 | u32 newsid; | 4310 | u32 newsid; |
4281 | u32 peersid; | 4311 | u32 peersid; |
4282 | 4312 | ||
4283 | err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid); | 4313 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
4314 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
4315 | family = PF_INET; | ||
4316 | |||
4317 | err = selinux_skb_peerlbl_sid(skb, family, &peersid); | ||
4284 | if (err) | 4318 | if (err) |
4285 | return err; | 4319 | return err; |
4286 | if (peersid == SECSID_NULL) { | 4320 | if (peersid == SECSID_NULL) { |
@@ -4315,12 +4349,18 @@ static void selinux_inet_csk_clone(struct sock *newsk, | |||
4315 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); | 4349 | selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); |
4316 | } | 4350 | } |
4317 | 4351 | ||
4318 | static void selinux_inet_conn_established(struct sock *sk, | 4352 | static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) |
4319 | struct sk_buff *skb) | ||
4320 | { | 4353 | { |
4354 | u16 family = sk->sk_family; | ||
4321 | struct sk_security_struct *sksec = sk->sk_security; | 4355 | struct sk_security_struct *sksec = sk->sk_security; |
4322 | 4356 | ||
4323 | selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid); | 4357 | /* handle mapped IPv4 packets arriving via IPv6 sockets */ |
4358 | if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) | ||
4359 | family = PF_INET; | ||
4360 | |||
4361 | selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); | ||
4362 | |||
4363 | selinux_netlbl_inet_conn_established(sk, family); | ||
4324 | } | 4364 | } |
4325 | 4365 | ||
4326 | static void selinux_req_classify_flow(const struct request_sock *req, | 4366 | static void selinux_req_classify_flow(const struct request_sock *req, |
@@ -4370,39 +4410,54 @@ out: | |||
4370 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | 4410 | static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, |
4371 | u16 family) | 4411 | u16 family) |
4372 | { | 4412 | { |
4413 | int err; | ||
4373 | char *addrp; | 4414 | char *addrp; |
4374 | u32 peer_sid; | 4415 | u32 peer_sid; |
4375 | struct avc_audit_data ad; | 4416 | struct avc_audit_data ad; |
4376 | u8 secmark_active; | 4417 | u8 secmark_active; |
4418 | u8 netlbl_active; | ||
4377 | u8 peerlbl_active; | 4419 | u8 peerlbl_active; |
4378 | 4420 | ||
4379 | if (!selinux_policycap_netpeer) | 4421 | if (!selinux_policycap_netpeer) |
4380 | return NF_ACCEPT; | 4422 | return NF_ACCEPT; |
4381 | 4423 | ||
4382 | secmark_active = selinux_secmark_enabled(); | 4424 | secmark_active = selinux_secmark_enabled(); |
4383 | peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); | 4425 | netlbl_active = netlbl_enabled(); |
4426 | peerlbl_active = netlbl_active || selinux_xfrm_enabled(); | ||
4384 | if (!secmark_active && !peerlbl_active) | 4427 | if (!secmark_active && !peerlbl_active) |
4385 | return NF_ACCEPT; | 4428 | return NF_ACCEPT; |
4386 | 4429 | ||
4430 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | ||
4431 | return NF_DROP; | ||
4432 | |||
4387 | AVC_AUDIT_DATA_INIT(&ad, NET); | 4433 | AVC_AUDIT_DATA_INIT(&ad, NET); |
4388 | ad.u.net.netif = ifindex; | 4434 | ad.u.net.netif = ifindex; |
4389 | ad.u.net.family = family; | 4435 | ad.u.net.family = family; |
4390 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) | 4436 | if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) |
4391 | return NF_DROP; | 4437 | return NF_DROP; |
4392 | 4438 | ||
4393 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | 4439 | if (peerlbl_active) { |
4394 | return NF_DROP; | 4440 | err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, |
4395 | 4441 | peer_sid, &ad); | |
4396 | if (peerlbl_active) | 4442 | if (err) { |
4397 | if (selinux_inet_sys_rcv_skb(ifindex, addrp, family, | 4443 | selinux_netlbl_err(skb, err, 1); |
4398 | peer_sid, &ad) != 0) | ||
4399 | return NF_DROP; | 4444 | return NF_DROP; |
4445 | } | ||
4446 | } | ||
4400 | 4447 | ||
4401 | if (secmark_active) | 4448 | if (secmark_active) |
4402 | if (avc_has_perm(peer_sid, skb->secmark, | 4449 | if (avc_has_perm(peer_sid, skb->secmark, |
4403 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) | 4450 | SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) |
4404 | return NF_DROP; | 4451 | return NF_DROP; |
4405 | 4452 | ||
4453 | if (netlbl_active) | ||
4454 | /* we do this in the FORWARD path and not the POST_ROUTING | ||
4455 | * path because we want to make sure we apply the necessary | ||
4456 | * labeling before IPsec is applied so we can leverage AH | ||
4457 | * protection */ | ||
4458 | if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) | ||
4459 | return NF_DROP; | ||
4460 | |||
4406 | return NF_ACCEPT; | 4461 | return NF_ACCEPT; |
4407 | } | 4462 | } |
4408 | 4463 | ||
@@ -4426,6 +4481,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum, | |||
4426 | } | 4481 | } |
4427 | #endif /* IPV6 */ | 4482 | #endif /* IPV6 */ |
4428 | 4483 | ||
4484 | static unsigned int selinux_ip_output(struct sk_buff *skb, | ||
4485 | u16 family) | ||
4486 | { | ||
4487 | u32 sid; | ||
4488 | |||
4489 | if (!netlbl_enabled()) | ||
4490 | return NF_ACCEPT; | ||
4491 | |||
4492 | /* we do this in the LOCAL_OUT path and not the POST_ROUTING path | ||
4493 | * because we want to make sure we apply the necessary labeling | ||
4494 | * before IPsec is applied so we can leverage AH protection */ | ||
4495 | if (skb->sk) { | ||
4496 | struct sk_security_struct *sksec = skb->sk->sk_security; | ||
4497 | sid = sksec->sid; | ||
4498 | } else | ||
4499 | sid = SECINITSID_KERNEL; | ||
4500 | if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) | ||
4501 | return NF_DROP; | ||
4502 | |||
4503 | return NF_ACCEPT; | ||
4504 | } | ||
4505 | |||
4506 | static unsigned int selinux_ipv4_output(unsigned int hooknum, | ||
4507 | struct sk_buff *skb, | ||
4508 | const struct net_device *in, | ||
4509 | const struct net_device *out, | ||
4510 | int (*okfn)(struct sk_buff *)) | ||
4511 | { | ||
4512 | return selinux_ip_output(skb, PF_INET); | ||
4513 | } | ||
4514 | |||
4429 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, | 4515 | static int selinux_ip_postroute_iptables_compat(struct sock *sk, |
4430 | int ifindex, | 4516 | int ifindex, |
4431 | struct avc_audit_data *ad, | 4517 | struct avc_audit_data *ad, |
@@ -4493,30 +4579,36 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk, | |||
4493 | 4579 | ||
4494 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | 4580 | static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, |
4495 | int ifindex, | 4581 | int ifindex, |
4496 | struct avc_audit_data *ad, | 4582 | u16 family) |
4497 | u16 family, | ||
4498 | char *addrp, | ||
4499 | u8 proto) | ||
4500 | { | 4583 | { |
4501 | struct sock *sk = skb->sk; | 4584 | struct sock *sk = skb->sk; |
4502 | struct sk_security_struct *sksec; | 4585 | struct sk_security_struct *sksec; |
4586 | struct avc_audit_data ad; | ||
4587 | char *addrp; | ||
4588 | u8 proto; | ||
4503 | 4589 | ||
4504 | if (sk == NULL) | 4590 | if (sk == NULL) |
4505 | return NF_ACCEPT; | 4591 | return NF_ACCEPT; |
4506 | sksec = sk->sk_security; | 4592 | sksec = sk->sk_security; |
4507 | 4593 | ||
4594 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4595 | ad.u.net.netif = ifindex; | ||
4596 | ad.u.net.family = family; | ||
4597 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
4598 | return NF_DROP; | ||
4599 | |||
4508 | if (selinux_compat_net) { | 4600 | if (selinux_compat_net) { |
4509 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, | 4601 | if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, |
4510 | ad, family, addrp)) | 4602 | &ad, family, addrp)) |
4511 | return NF_DROP; | 4603 | return NF_DROP; |
4512 | } else { | 4604 | } else { |
4513 | if (avc_has_perm(sksec->sid, skb->secmark, | 4605 | if (avc_has_perm(sksec->sid, skb->secmark, |
4514 | SECCLASS_PACKET, PACKET__SEND, ad)) | 4606 | SECCLASS_PACKET, PACKET__SEND, &ad)) |
4515 | return NF_DROP; | 4607 | return NF_DROP; |
4516 | } | 4608 | } |
4517 | 4609 | ||
4518 | if (selinux_policycap_netpeer) | 4610 | if (selinux_policycap_netpeer) |
4519 | if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto)) | 4611 | if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) |
4520 | return NF_DROP; | 4612 | return NF_DROP; |
4521 | 4613 | ||
4522 | return NF_ACCEPT; | 4614 | return NF_ACCEPT; |
@@ -4530,23 +4622,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4530 | struct sock *sk; | 4622 | struct sock *sk; |
4531 | struct avc_audit_data ad; | 4623 | struct avc_audit_data ad; |
4532 | char *addrp; | 4624 | char *addrp; |
4533 | u8 proto; | ||
4534 | u8 secmark_active; | 4625 | u8 secmark_active; |
4535 | u8 peerlbl_active; | 4626 | u8 peerlbl_active; |
4536 | 4627 | ||
4537 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4538 | ad.u.net.netif = ifindex; | ||
4539 | ad.u.net.family = family; | ||
4540 | if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) | ||
4541 | return NF_DROP; | ||
4542 | |||
4543 | /* If any sort of compatibility mode is enabled then handoff processing | 4628 | /* If any sort of compatibility mode is enabled then handoff processing |
4544 | * to the selinux_ip_postroute_compat() function to deal with the | 4629 | * to the selinux_ip_postroute_compat() function to deal with the |
4545 | * special handling. We do this in an attempt to keep this function | 4630 | * special handling. We do this in an attempt to keep this function |
4546 | * as fast and as clean as possible. */ | 4631 | * as fast and as clean as possible. */ |
4547 | if (selinux_compat_net || !selinux_policycap_netpeer) | 4632 | if (selinux_compat_net || !selinux_policycap_netpeer) |
4548 | return selinux_ip_postroute_compat(skb, ifindex, &ad, | 4633 | return selinux_ip_postroute_compat(skb, ifindex, family); |
4549 | family, addrp, proto); | ||
4550 | 4634 | ||
4551 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec | 4635 | /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec |
4552 | * packet transformation so allow the packet to pass without any checks | 4636 | * packet transformation so allow the packet to pass without any checks |
@@ -4562,21 +4646,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4562 | if (!secmark_active && !peerlbl_active) | 4646 | if (!secmark_active && !peerlbl_active) |
4563 | return NF_ACCEPT; | 4647 | return NF_ACCEPT; |
4564 | 4648 | ||
4565 | /* if the packet is locally generated (skb->sk != NULL) then use the | 4649 | /* if the packet is being forwarded then get the peer label from the |
4566 | * socket's label as the peer label, otherwise the packet is being | 4650 | * packet itself; otherwise check to see if it is from a local |
4567 | * forwarded through this system and we need to fetch the peer label | 4651 | * application or the kernel, if from an application get the peer label |
4568 | * directly from the packet */ | 4652 | * from the sending socket, otherwise use the kernel's sid */ |
4569 | sk = skb->sk; | 4653 | sk = skb->sk; |
4570 | if (sk) { | 4654 | if (sk == NULL) { |
4655 | switch (family) { | ||
4656 | case PF_INET: | ||
4657 | if (IPCB(skb)->flags & IPSKB_FORWARDED) | ||
4658 | secmark_perm = PACKET__FORWARD_OUT; | ||
4659 | else | ||
4660 | secmark_perm = PACKET__SEND; | ||
4661 | break; | ||
4662 | case PF_INET6: | ||
4663 | if (IP6CB(skb)->flags & IP6SKB_FORWARDED) | ||
4664 | secmark_perm = PACKET__FORWARD_OUT; | ||
4665 | else | ||
4666 | secmark_perm = PACKET__SEND; | ||
4667 | break; | ||
4668 | default: | ||
4669 | return NF_DROP; | ||
4670 | } | ||
4671 | if (secmark_perm == PACKET__FORWARD_OUT) { | ||
4672 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
4673 | return NF_DROP; | ||
4674 | } else | ||
4675 | peer_sid = SECINITSID_KERNEL; | ||
4676 | } else { | ||
4571 | struct sk_security_struct *sksec = sk->sk_security; | 4677 | struct sk_security_struct *sksec = sk->sk_security; |
4572 | peer_sid = sksec->sid; | 4678 | peer_sid = sksec->sid; |
4573 | secmark_perm = PACKET__SEND; | 4679 | secmark_perm = PACKET__SEND; |
4574 | } else { | ||
4575 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) | ||
4576 | return NF_DROP; | ||
4577 | secmark_perm = PACKET__FORWARD_OUT; | ||
4578 | } | 4680 | } |
4579 | 4681 | ||
4682 | AVC_AUDIT_DATA_INIT(&ad, NET); | ||
4683 | ad.u.net.netif = ifindex; | ||
4684 | ad.u.net.family = family; | ||
4685 | if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) | ||
4686 | return NF_DROP; | ||
4687 | |||
4580 | if (secmark_active) | 4688 | if (secmark_active) |
4581 | if (avc_has_perm(peer_sid, skb->secmark, | 4689 | if (avc_has_perm(peer_sid, skb->secmark, |
4582 | SECCLASS_PACKET, secmark_perm, &ad)) | 4690 | SECCLASS_PACKET, secmark_perm, &ad)) |
@@ -5219,8 +5327,12 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5219 | 5327 | ||
5220 | if (sid == 0) | 5328 | if (sid == 0) |
5221 | return -EINVAL; | 5329 | return -EINVAL; |
5222 | 5330 | /* | |
5223 | /* Only allow single threaded processes to change context */ | 5331 | * SELinux allows to change context in the following case only. |
5332 | * - Single threaded processes. | ||
5333 | * - Multi threaded processes intend to change its context into | ||
5334 | * more restricted domain (defined by TYPEBOUNDS statement). | ||
5335 | */ | ||
5224 | if (atomic_read(&p->mm->mm_users) != 1) { | 5336 | if (atomic_read(&p->mm->mm_users) != 1) { |
5225 | struct task_struct *g, *t; | 5337 | struct task_struct *g, *t; |
5226 | struct mm_struct *mm = p->mm; | 5338 | struct mm_struct *mm = p->mm; |
@@ -5228,11 +5340,16 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5228 | do_each_thread(g, t) { | 5340 | do_each_thread(g, t) { |
5229 | if (t->mm == mm && t != p) { | 5341 | if (t->mm == mm && t != p) { |
5230 | read_unlock(&tasklist_lock); | 5342 | read_unlock(&tasklist_lock); |
5231 | return -EPERM; | 5343 | error = security_bounded_transition(tsec->sid, sid); |
5344 | if (!error) | ||
5345 | goto boundary_ok; | ||
5346 | |||
5347 | return error; | ||
5232 | } | 5348 | } |
5233 | } while_each_thread(g, t); | 5349 | } while_each_thread(g, t); |
5234 | read_unlock(&tasklist_lock); | 5350 | read_unlock(&tasklist_lock); |
5235 | } | 5351 | } |
5352 | boundary_ok: | ||
5236 | 5353 | ||
5237 | /* Check permissions for the transition. */ | 5354 | /* Check permissions for the transition. */ |
5238 | error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, | 5355 | error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, |
@@ -5641,6 +5758,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = { | |||
5641 | .pf = PF_INET, | 5758 | .pf = PF_INET, |
5642 | .hooknum = NF_INET_FORWARD, | 5759 | .hooknum = NF_INET_FORWARD, |
5643 | .priority = NF_IP_PRI_SELINUX_FIRST, | 5760 | .priority = NF_IP_PRI_SELINUX_FIRST, |
5761 | }, | ||
5762 | { | ||
5763 | .hook = selinux_ipv4_output, | ||
5764 | .owner = THIS_MODULE, | ||
5765 | .pf = PF_INET, | ||
5766 | .hooknum = NF_INET_LOCAL_OUT, | ||
5767 | .priority = NF_IP_PRI_SELINUX_FIRST, | ||
5644 | } | 5768 | } |
5645 | }; | 5769 | }; |
5646 | 5770 | ||