aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/dummy.c10
-rw-r--r--security/selinux/hooks.c46
-rw-r--r--security/selinux/include/xfrm.h2
-rw-r--r--security/selinux/xfrm.c68
4 files changed, 117 insertions, 9 deletions
diff --git a/security/dummy.c b/security/dummy.c
index f1a5bd98bf10..a326d6e0b6d7 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -763,8 +763,14 @@ static int dummy_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
763 return 0; 763 return 0;
764} 764}
765 765
766static int dummy_socket_getpeersec(struct socket *sock, char __user *optval, 766static int dummy_socket_getpeersec_stream(struct socket *sock, char __user *optval,
767 int __user *optlen, unsigned len) 767 int __user *optlen, unsigned len)
768{
769 return -ENOPROTOOPT;
770}
771
772static int dummy_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
773 u32 *seclen)
768{ 774{
769 return -ENOPROTOOPT; 775 return -ENOPROTOOPT;
770} 776}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b65c201e9ff5..5b16196f2823 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3318,24 +3318,38 @@ out:
3318 return err; 3318 return err;
3319} 3319}
3320 3320
3321static int selinux_socket_getpeersec(struct socket *sock, char __user *optval, 3321static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
3322 int __user *optlen, unsigned len) 3322 int __user *optlen, unsigned len)
3323{ 3323{
3324 int err = 0; 3324 int err = 0;
3325 char *scontext; 3325 char *scontext;
3326 u32 scontext_len; 3326 u32 scontext_len;
3327 struct sk_security_struct *ssec; 3327 struct sk_security_struct *ssec;
3328 struct inode_security_struct *isec; 3328 struct inode_security_struct *isec;
3329 u32 peer_sid = 0;
3329 3330
3330 isec = SOCK_INODE(sock)->i_security; 3331 isec = SOCK_INODE(sock)->i_security;
3331 if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) { 3332
3333 /* if UNIX_STREAM check peer_sid, if TCP check dst for labelled sa */
3334 if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET) {
3335 ssec = sock->sk->sk_security;
3336 peer_sid = ssec->peer_sid;
3337 }
3338 else if (isec->sclass == SECCLASS_TCP_SOCKET) {
3339 peer_sid = selinux_socket_getpeer_stream(sock->sk);
3340
3341 if (peer_sid == SECSID_NULL) {
3342 err = -ENOPROTOOPT;
3343 goto out;
3344 }
3345 }
3346 else {
3332 err = -ENOPROTOOPT; 3347 err = -ENOPROTOOPT;
3333 goto out; 3348 goto out;
3334 } 3349 }
3335 3350
3336 ssec = sock->sk->sk_security; 3351 err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
3337 3352
3338 err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
3339 if (err) 3353 if (err)
3340 goto out; 3354 goto out;
3341 3355
@@ -3356,6 +3370,23 @@ out:
3356 return err; 3370 return err;
3357} 3371}
3358 3372
3373static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen)
3374{
3375 int err = 0;
3376 u32 peer_sid = selinux_socket_getpeer_dgram(skb);
3377
3378 if (peer_sid == SECSID_NULL)
3379 return -EINVAL;
3380
3381 err = security_sid_to_context(peer_sid, secdata, seclen);
3382 if (err)
3383 return err;
3384
3385 return 0;
3386}
3387
3388
3389
3359static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) 3390static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
3360{ 3391{
3361 return sk_alloc_security(sk, family, priority); 3392 return sk_alloc_security(sk, family, priority);
@@ -4344,7 +4375,8 @@ static struct security_operations selinux_ops = {
4344 .socket_setsockopt = selinux_socket_setsockopt, 4375 .socket_setsockopt = selinux_socket_setsockopt,
4345 .socket_shutdown = selinux_socket_shutdown, 4376 .socket_shutdown = selinux_socket_shutdown,
4346 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb, 4377 .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
4347 .socket_getpeersec = selinux_socket_getpeersec, 4378 .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
4379 .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
4348 .sk_alloc_security = selinux_sk_alloc_security, 4380 .sk_alloc_security = selinux_sk_alloc_security,
4349 .sk_free_security = selinux_sk_free_security, 4381 .sk_free_security = selinux_sk_free_security,
4350 .sk_getsid = selinux_sk_getsid_security, 4382 .sk_getsid = selinux_sk_getsid_security,
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 8e87996c6dd5..a7f388bff3f2 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -39,6 +39,8 @@ static inline u32 selinux_no_sk_sid(struct flowi *fl)
39#ifdef CONFIG_SECURITY_NETWORK_XFRM 39#ifdef CONFIG_SECURITY_NETWORK_XFRM
40int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb); 40int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb);
41int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb); 41int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb);
42u32 selinux_socket_getpeer_stream(struct sock *sk);
43u32 selinux_socket_getpeer_dgram(struct sk_buff *skb);
42#else 44#else
43static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb) 45static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
44{ 46{
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index b2af7ca496c1..dfab6c886698 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -225,6 +225,74 @@ void selinux_xfrm_state_free(struct xfrm_state *x)
225} 225}
226 226
227/* 227/*
228 * SELinux internal function to retrieve the context of a connected
229 * (sk->sk_state == TCP_ESTABLISHED) TCP socket based on its security
230 * association used to connect to the remote socket.
231 *
232 * Retrieve via getsockopt SO_PEERSEC.
233 */
234u32 selinux_socket_getpeer_stream(struct sock *sk)
235{
236 struct dst_entry *dst, *dst_test;
237 u32 peer_sid = SECSID_NULL;
238
239 if (sk->sk_state != TCP_ESTABLISHED)
240 goto out;
241
242 dst = sk_dst_get(sk);
243 if (!dst)
244 goto out;
245
246 for (dst_test = dst; dst_test != 0;
247 dst_test = dst_test->child) {
248 struct xfrm_state *x = dst_test->xfrm;
249
250 if (x && selinux_authorizable_xfrm(x)) {
251 struct xfrm_sec_ctx *ctx = x->security;
252 peer_sid = ctx->ctx_sid;
253 break;
254 }
255 }
256 dst_release(dst);
257
258out:
259 return peer_sid;
260}
261
262/*
263 * SELinux internal function to retrieve the context of a UDP packet
264 * based on its security association used to connect to the remote socket.
265 *
266 * Retrieve via setsockopt IP_PASSSEC and recvmsg with control message
267 * type SCM_SECURITY.
268 */
269u32 selinux_socket_getpeer_dgram(struct sk_buff *skb)
270{
271 struct sec_path *sp;
272
273 if (skb == NULL)
274 return SECSID_NULL;
275
276 if (skb->sk->sk_protocol != IPPROTO_UDP)
277 return SECSID_NULL;
278
279 sp = skb->sp;
280 if (sp) {
281 int i;
282
283 for (i = sp->len-1; i >= 0; i--) {
284 struct xfrm_state *x = sp->x[i].xvec;
285 if (selinux_authorizable_xfrm(x)) {
286 struct xfrm_sec_ctx *ctx = x->security;
287 return ctx->ctx_sid;
288 }
289 }
290 }
291
292 return SECSID_NULL;
293}
294
295/*
228 * LSM hook that controls access to unlabelled packets. If 296 * LSM hook that controls access to unlabelled packets. If
229 * a xfrm_state is authorizable (defined by macro) then it was 297 * a xfrm_state is authorizable (defined by macro) then it was
230 * already authorized by the IPSec process. If not, then 298 * already authorized by the IPSec process. If not, then