1d28d1e08STrent Jaeger /* 2d28d1e08STrent Jaeger * NSA Security-Enhanced Linux (SELinux) security module 3d28d1e08STrent Jaeger * 4d28d1e08STrent Jaeger * This file contains the SELinux XFRM hook function implementations. 5d28d1e08STrent Jaeger * 6d28d1e08STrent Jaeger * Authors: Serge Hallyn <sergeh@us.ibm.com> 7d28d1e08STrent Jaeger * Trent Jaeger <jaegert@us.ibm.com> 8d28d1e08STrent Jaeger * 9e0d1caa7SVenkat Yekkirala * Updated: Venkat Yekkirala <vyekkirala@TrustedCS.com> 10e0d1caa7SVenkat Yekkirala * 11e0d1caa7SVenkat Yekkirala * Granular IPSec Associations for use in MLS environments. 12e0d1caa7SVenkat Yekkirala * 13d28d1e08STrent Jaeger * Copyright (C) 2005 International Business Machines Corporation 14e0d1caa7SVenkat Yekkirala * Copyright (C) 2006 Trusted Computer Solutions, Inc. 15d28d1e08STrent Jaeger * 16d28d1e08STrent Jaeger * This program is free software; you can redistribute it and/or modify 17d28d1e08STrent Jaeger * it under the terms of the GNU General Public License version 2, 18d28d1e08STrent Jaeger * as published by the Free Software Foundation. 19d28d1e08STrent Jaeger */ 20d28d1e08STrent Jaeger 21d28d1e08STrent Jaeger /* 22d28d1e08STrent Jaeger * USAGE: 23d28d1e08STrent Jaeger * NOTES: 24d28d1e08STrent Jaeger * 1. Make sure to enable the following options in your kernel config: 25d28d1e08STrent Jaeger * CONFIG_SECURITY=y 26d28d1e08STrent Jaeger * CONFIG_SECURITY_NETWORK=y 27d28d1e08STrent Jaeger * CONFIG_SECURITY_NETWORK_XFRM=y 28d28d1e08STrent Jaeger * CONFIG_SECURITY_SELINUX=m/y 29d28d1e08STrent Jaeger * ISSUES: 30d28d1e08STrent Jaeger * 1. Caching packets, so they are not dropped during negotiation 31d28d1e08STrent Jaeger * 2. Emulating a reasonable SO_PEERSEC across machines 32d28d1e08STrent Jaeger * 3. Testing addition of sk_policy's with security context via setsockopt 33d28d1e08STrent Jaeger */ 34d28d1e08STrent Jaeger #include <linux/kernel.h> 35d28d1e08STrent Jaeger #include <linux/init.h> 36d28d1e08STrent Jaeger #include <linux/security.h> 37d28d1e08STrent Jaeger #include <linux/types.h> 385a0e3ad6STejun Heo #include <linux/slab.h> 39d28d1e08STrent Jaeger #include <linux/ip.h> 40d28d1e08STrent Jaeger #include <linux/tcp.h> 41d28d1e08STrent Jaeger #include <linux/skbuff.h> 42d28d1e08STrent Jaeger #include <linux/xfrm.h> 43d28d1e08STrent Jaeger #include <net/xfrm.h> 44d28d1e08STrent Jaeger #include <net/checksum.h> 45d28d1e08STrent Jaeger #include <net/udp.h> 4660063497SArun Sharma #include <linux/atomic.h> 47d28d1e08STrent Jaeger 48d28d1e08STrent Jaeger #include "avc.h" 49d28d1e08STrent Jaeger #include "objsec.h" 50d28d1e08STrent Jaeger #include "xfrm.h" 51d28d1e08STrent Jaeger 52d621d35eSPaul Moore /* Labeled XFRM instance counter */ 53d621d35eSPaul Moore atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0); 54d28d1e08STrent Jaeger 55d28d1e08STrent Jaeger /* 564baabeecSPaul Moore * Returns true if the context is an LSM/SELinux context. 57d28d1e08STrent Jaeger */ 58d28d1e08STrent Jaeger static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx) 59d28d1e08STrent Jaeger { 60d28d1e08STrent Jaeger return (ctx && 61d28d1e08STrent Jaeger (ctx->ctx_doi == XFRM_SC_DOI_LSM) && 62d28d1e08STrent Jaeger (ctx->ctx_alg == XFRM_SC_ALG_SELINUX)); 63d28d1e08STrent Jaeger } 64d28d1e08STrent Jaeger 65d28d1e08STrent Jaeger /* 664baabeecSPaul Moore * Returns true if the xfrm contains a security blob for SELinux. 67d28d1e08STrent Jaeger */ 68d28d1e08STrent Jaeger static inline int selinux_authorizable_xfrm(struct xfrm_state *x) 69d28d1e08STrent Jaeger { 70d28d1e08STrent Jaeger return selinux_authorizable_ctx(x->security); 71d28d1e08STrent Jaeger } 72d28d1e08STrent Jaeger 73d28d1e08STrent Jaeger /* 742e5aa866SPaul Moore * Allocates a xfrm_sec_state and populates it using the supplied security 752e5aa866SPaul Moore * xfrm_user_sec_ctx context. 762e5aa866SPaul Moore */ 772e5aa866SPaul Moore static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, 7852a4c640SNikolay Aleksandrov struct xfrm_user_sec_ctx *uctx, 7952a4c640SNikolay Aleksandrov gfp_t gfp) 802e5aa866SPaul Moore { 812e5aa866SPaul Moore int rc; 822e5aa866SPaul Moore const struct task_security_struct *tsec = current_security(); 832e5aa866SPaul Moore struct xfrm_sec_ctx *ctx = NULL; 842e5aa866SPaul Moore u32 str_len; 852e5aa866SPaul Moore 862e5aa866SPaul Moore if (ctxp == NULL || uctx == NULL || 872e5aa866SPaul Moore uctx->ctx_doi != XFRM_SC_DOI_LSM || 882e5aa866SPaul Moore uctx->ctx_alg != XFRM_SC_ALG_SELINUX) 892e5aa866SPaul Moore return -EINVAL; 902e5aa866SPaul Moore 912e5aa866SPaul Moore str_len = uctx->ctx_len; 922e5aa866SPaul Moore if (str_len >= PAGE_SIZE) 932e5aa866SPaul Moore return -ENOMEM; 942e5aa866SPaul Moore 9552a4c640SNikolay Aleksandrov ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp); 962e5aa866SPaul Moore if (!ctx) 972e5aa866SPaul Moore return -ENOMEM; 982e5aa866SPaul Moore 992e5aa866SPaul Moore ctx->ctx_doi = XFRM_SC_DOI_LSM; 1002e5aa866SPaul Moore ctx->ctx_alg = XFRM_SC_ALG_SELINUX; 1012e5aa866SPaul Moore ctx->ctx_len = str_len; 1022e5aa866SPaul Moore memcpy(ctx->ctx_str, &uctx[1], str_len); 1032e5aa866SPaul Moore ctx->ctx_str[str_len] = '\0'; 104aa8e712cSStephen Smalley rc = security_context_to_sid(&selinux_state, ctx->ctx_str, str_len, 105aa8e712cSStephen Smalley &ctx->ctx_sid, gfp); 1062e5aa866SPaul Moore if (rc) 1072e5aa866SPaul Moore goto err; 1082e5aa866SPaul Moore 1096b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 1106b6bc620SStephen Smalley tsec->sid, ctx->ctx_sid, 1112e5aa866SPaul Moore SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL); 1122e5aa866SPaul Moore if (rc) 1132e5aa866SPaul Moore goto err; 1142e5aa866SPaul Moore 1152e5aa866SPaul Moore *ctxp = ctx; 1162e5aa866SPaul Moore atomic_inc(&selinux_xfrm_refcount); 1172e5aa866SPaul Moore return 0; 1182e5aa866SPaul Moore 1192e5aa866SPaul Moore err: 1202e5aa866SPaul Moore kfree(ctx); 1212e5aa866SPaul Moore return rc; 1222e5aa866SPaul Moore } 1232e5aa866SPaul Moore 1242e5aa866SPaul Moore /* 125ccf17cc4SPaul Moore * Free the xfrm_sec_ctx structure. 126ccf17cc4SPaul Moore */ 127ccf17cc4SPaul Moore static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx) 128ccf17cc4SPaul Moore { 129ccf17cc4SPaul Moore if (!ctx) 130ccf17cc4SPaul Moore return; 131ccf17cc4SPaul Moore 132ccf17cc4SPaul Moore atomic_dec(&selinux_xfrm_refcount); 133ccf17cc4SPaul Moore kfree(ctx); 134ccf17cc4SPaul Moore } 135ccf17cc4SPaul Moore 136ccf17cc4SPaul Moore /* 137ccf17cc4SPaul Moore * Authorize the deletion of a labeled SA or policy rule. 138ccf17cc4SPaul Moore */ 139ccf17cc4SPaul Moore static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx) 140ccf17cc4SPaul Moore { 141ccf17cc4SPaul Moore const struct task_security_struct *tsec = current_security(); 142ccf17cc4SPaul Moore 143ccf17cc4SPaul Moore if (!ctx) 144ccf17cc4SPaul Moore return 0; 145ccf17cc4SPaul Moore 1466b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 1476b6bc620SStephen Smalley tsec->sid, ctx->ctx_sid, 148ccf17cc4SPaul Moore SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, 149ccf17cc4SPaul Moore NULL); 150ccf17cc4SPaul Moore } 151ccf17cc4SPaul Moore 152ccf17cc4SPaul Moore /* 1534baabeecSPaul Moore * LSM hook implementation that authorizes that a flow can use a xfrm policy 1544baabeecSPaul Moore * rule. 155d28d1e08STrent Jaeger */ 15603e1ad7bSPaul Moore int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) 157d28d1e08STrent Jaeger { 1585b368e61SVenkat Yekkirala int rc; 15996484348SPaul Moore 16096484348SPaul Moore /* All flows should be treated as polmatch'ing an otherwise applicable 16196484348SPaul Moore * "non-labeled" policy. This would prevent inadvertent "leaks". */ 16296484348SPaul Moore if (!ctx) 16396484348SPaul Moore return 0; 164d28d1e08STrent Jaeger 165d28d1e08STrent Jaeger /* Context sid is either set to label or ANY_ASSOC */ 166d28d1e08STrent Jaeger if (!selinux_authorizable_ctx(ctx)) 167d28d1e08STrent Jaeger return -EINVAL; 168d28d1e08STrent Jaeger 1696b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 1706b6bc620SStephen Smalley fl_secid, ctx->ctx_sid, 17196484348SPaul Moore SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL); 17296484348SPaul Moore return (rc == -EACCES ? -ESRCH : rc); 173d28d1e08STrent Jaeger } 174d28d1e08STrent Jaeger 175d28d1e08STrent Jaeger /* 176e0d1caa7SVenkat Yekkirala * LSM hook implementation that authorizes that a state matches 177e0d1caa7SVenkat Yekkirala * the given policy, flow combo. 178e0d1caa7SVenkat Yekkirala */ 17996484348SPaul Moore int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, 18096484348SPaul Moore struct xfrm_policy *xp, 181e33f7704SDavid S. Miller const struct flowi *fl) 182e0d1caa7SVenkat Yekkirala { 183e0d1caa7SVenkat Yekkirala u32 state_sid; 184e0d1caa7SVenkat Yekkirala 18567f83cbfSVenkat Yekkirala if (!xp->security) 1865b368e61SVenkat Yekkirala if (x->security) 1875b368e61SVenkat Yekkirala /* unlabeled policy and labeled SA can't match */ 1885b368e61SVenkat Yekkirala return 0; 189e0d1caa7SVenkat Yekkirala else 1905b368e61SVenkat Yekkirala /* unlabeled policy and unlabeled SA match all flows */ 1915b368e61SVenkat Yekkirala return 1; 19267f83cbfSVenkat Yekkirala else 19367f83cbfSVenkat Yekkirala if (!x->security) 19467f83cbfSVenkat Yekkirala /* unlabeled SA and labeled policy can't match */ 19567f83cbfSVenkat Yekkirala return 0; 19667f83cbfSVenkat Yekkirala else 19767f83cbfSVenkat Yekkirala if (!selinux_authorizable_xfrm(x)) 19867f83cbfSVenkat Yekkirala /* Not a SELinux-labeled SA */ 199e0d1caa7SVenkat Yekkirala return 0; 200e0d1caa7SVenkat Yekkirala 20167f83cbfSVenkat Yekkirala state_sid = x->security->ctx_sid; 20267f83cbfSVenkat Yekkirala 2031d28f42cSDavid S. Miller if (fl->flowi_secid != state_sid) 20467f83cbfSVenkat Yekkirala return 0; 20567f83cbfSVenkat Yekkirala 20696484348SPaul Moore /* We don't need a separate SA Vs. policy polmatch check since the SA 20796484348SPaul Moore * is now of the same label as the flow and a flow Vs. policy polmatch 20896484348SPaul Moore * check had already happened in selinux_xfrm_policy_lookup() above. */ 2096b6bc620SStephen Smalley return (avc_has_perm(&selinux_state, 2106b6bc620SStephen Smalley fl->flowi_secid, state_sid, 21196484348SPaul Moore SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, 21296484348SPaul Moore NULL) ? 0 : 1); 213e0d1caa7SVenkat Yekkirala } 214e0d1caa7SVenkat Yekkirala 215817eff71SPaul Moore static u32 selinux_xfrm_skb_sid_egress(struct sk_buff *skb) 216817eff71SPaul Moore { 217817eff71SPaul Moore struct dst_entry *dst = skb_dst(skb); 218817eff71SPaul Moore struct xfrm_state *x; 219817eff71SPaul Moore 220817eff71SPaul Moore if (dst == NULL) 221817eff71SPaul Moore return SECSID_NULL; 222817eff71SPaul Moore x = dst->xfrm; 223817eff71SPaul Moore if (x == NULL || !selinux_authorizable_xfrm(x)) 224817eff71SPaul Moore return SECSID_NULL; 225817eff71SPaul Moore 226817eff71SPaul Moore return x->security->ctx_sid; 227817eff71SPaul Moore } 228817eff71SPaul Moore 229817eff71SPaul Moore static int selinux_xfrm_skb_sid_ingress(struct sk_buff *skb, 230817eff71SPaul Moore u32 *sid, int ckall) 231e0d1caa7SVenkat Yekkirala { 232e2193695SPaul Moore u32 sid_session = SECSID_NULL; 2332294be0fSFlorian Westphal struct sec_path *sp = skb_sec_path(skb); 234e0d1caa7SVenkat Yekkirala 235e0d1caa7SVenkat Yekkirala if (sp) { 236e2193695SPaul Moore int i; 237e0d1caa7SVenkat Yekkirala 238e0d1caa7SVenkat Yekkirala for (i = sp->len - 1; i >= 0; i--) { 239e0d1caa7SVenkat Yekkirala struct xfrm_state *x = sp->xvec[i]; 240e0d1caa7SVenkat Yekkirala if (selinux_authorizable_xfrm(x)) { 241e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = x->security; 242e0d1caa7SVenkat Yekkirala 243e2193695SPaul Moore if (sid_session == SECSID_NULL) { 244e2193695SPaul Moore sid_session = ctx->ctx_sid; 245beb8d13bSVenkat Yekkirala if (!ckall) 246e2193695SPaul Moore goto out; 247e2193695SPaul Moore } else if (sid_session != ctx->ctx_sid) { 248e2193695SPaul Moore *sid = SECSID_NULL; 249e0d1caa7SVenkat Yekkirala return -EINVAL; 250e0d1caa7SVenkat Yekkirala } 251e0d1caa7SVenkat Yekkirala } 252e0d1caa7SVenkat Yekkirala } 253e2193695SPaul Moore } 254e0d1caa7SVenkat Yekkirala 255e2193695SPaul Moore out: 256e2193695SPaul Moore *sid = sid_session; 257e0d1caa7SVenkat Yekkirala return 0; 258e0d1caa7SVenkat Yekkirala } 259e0d1caa7SVenkat Yekkirala 260e0d1caa7SVenkat Yekkirala /* 261817eff71SPaul Moore * LSM hook implementation that checks and/or returns the xfrm sid for the 262817eff71SPaul Moore * incoming packet. 263817eff71SPaul Moore */ 264817eff71SPaul Moore int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) 265817eff71SPaul Moore { 266817eff71SPaul Moore if (skb == NULL) { 267817eff71SPaul Moore *sid = SECSID_NULL; 268817eff71SPaul Moore return 0; 269817eff71SPaul Moore } 270817eff71SPaul Moore return selinux_xfrm_skb_sid_ingress(skb, sid, ckall); 271817eff71SPaul Moore } 272817eff71SPaul Moore 273817eff71SPaul Moore int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid) 274817eff71SPaul Moore { 275817eff71SPaul Moore int rc; 276817eff71SPaul Moore 277817eff71SPaul Moore rc = selinux_xfrm_skb_sid_ingress(skb, sid, 0); 278817eff71SPaul Moore if (rc == 0 && *sid == SECSID_NULL) 279817eff71SPaul Moore *sid = selinux_xfrm_skb_sid_egress(skb); 280817eff71SPaul Moore 281817eff71SPaul Moore return rc; 282817eff71SPaul Moore } 283817eff71SPaul Moore 284817eff71SPaul Moore /* 2854baabeecSPaul Moore * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy. 286d28d1e08STrent Jaeger */ 28703e1ad7bSPaul Moore int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, 28852a4c640SNikolay Aleksandrov struct xfrm_user_sec_ctx *uctx, 28952a4c640SNikolay Aleksandrov gfp_t gfp) 290d28d1e08STrent Jaeger { 29152a4c640SNikolay Aleksandrov return selinux_xfrm_alloc_user(ctxp, uctx, gfp); 292d28d1e08STrent Jaeger } 293d28d1e08STrent Jaeger 294d28d1e08STrent Jaeger /* 2954baabeecSPaul Moore * LSM hook implementation that copies security data structure from old to new 2964baabeecSPaul Moore * for policy cloning. 297d28d1e08STrent Jaeger */ 29803e1ad7bSPaul Moore int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, 29903e1ad7bSPaul Moore struct xfrm_sec_ctx **new_ctxp) 300d28d1e08STrent Jaeger { 30103e1ad7bSPaul Moore struct xfrm_sec_ctx *new_ctx; 302d28d1e08STrent Jaeger 303ccf17cc4SPaul Moore if (!old_ctx) 304ccf17cc4SPaul Moore return 0; 305ccf17cc4SPaul Moore 3067d1db4b2SDuan Jiong new_ctx = kmemdup(old_ctx, sizeof(*old_ctx) + old_ctx->ctx_len, 3077d1db4b2SDuan Jiong GFP_ATOMIC); 308d28d1e08STrent Jaeger if (!new_ctx) 309d28d1e08STrent Jaeger return -ENOMEM; 310e4e8536fSPaul Moore atomic_inc(&selinux_xfrm_refcount); 31103e1ad7bSPaul Moore *new_ctxp = new_ctx; 312ccf17cc4SPaul Moore 313d28d1e08STrent Jaeger return 0; 314d28d1e08STrent Jaeger } 315d28d1e08STrent Jaeger 316d28d1e08STrent Jaeger /* 31703e1ad7bSPaul Moore * LSM hook implementation that frees xfrm_sec_ctx security information. 318d28d1e08STrent Jaeger */ 31903e1ad7bSPaul Moore void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) 320d28d1e08STrent Jaeger { 321ccf17cc4SPaul Moore selinux_xfrm_free(ctx); 322d28d1e08STrent Jaeger } 323d28d1e08STrent Jaeger 324d28d1e08STrent Jaeger /* 325c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled policies. 326c8c05a8eSCatherine Zhang */ 32703e1ad7bSPaul Moore int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) 328c8c05a8eSCatherine Zhang { 329ccf17cc4SPaul Moore return selinux_xfrm_delete(ctx); 330c8c05a8eSCatherine Zhang } 331c8c05a8eSCatherine Zhang 332c8c05a8eSCatherine Zhang /* 3332e5aa866SPaul Moore * LSM hook implementation that allocates a xfrm_sec_state, populates it using 3342e5aa866SPaul Moore * the supplied security context, and assigns it to the xfrm_state. 335d28d1e08STrent Jaeger */ 3362e5aa866SPaul Moore int selinux_xfrm_state_alloc(struct xfrm_state *x, 3372e5aa866SPaul Moore struct xfrm_user_sec_ctx *uctx) 338d28d1e08STrent Jaeger { 33952a4c640SNikolay Aleksandrov return selinux_xfrm_alloc_user(&x->security, uctx, GFP_KERNEL); 3402e5aa866SPaul Moore } 341d28d1e08STrent Jaeger 3422e5aa866SPaul Moore /* 3432e5aa866SPaul Moore * LSM hook implementation that allocates a xfrm_sec_state and populates based 3442e5aa866SPaul Moore * on a secid. 3452e5aa866SPaul Moore */ 3462e5aa866SPaul Moore int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, 3472e5aa866SPaul Moore struct xfrm_sec_ctx *polsec, u32 secid) 3482e5aa866SPaul Moore { 3492e5aa866SPaul Moore int rc; 3502e5aa866SPaul Moore struct xfrm_sec_ctx *ctx; 3512e5aa866SPaul Moore char *ctx_str = NULL; 3522e5aa866SPaul Moore int str_len; 353d28d1e08STrent Jaeger 3542e5aa866SPaul Moore if (!polsec) 3552e5aa866SPaul Moore return 0; 3562e5aa866SPaul Moore 3572e5aa866SPaul Moore if (secid == 0) 3582e5aa866SPaul Moore return -EINVAL; 3592e5aa866SPaul Moore 360aa8e712cSStephen Smalley rc = security_sid_to_context(&selinux_state, secid, &ctx_str, 361aa8e712cSStephen Smalley &str_len); 3622e5aa866SPaul Moore if (rc) 3632e5aa866SPaul Moore return rc; 3642e5aa866SPaul Moore 3652e5aa866SPaul Moore ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC); 3660af90164SGeyslan G. Bem if (!ctx) { 3670af90164SGeyslan G. Bem rc = -ENOMEM; 3680af90164SGeyslan G. Bem goto out; 3690af90164SGeyslan G. Bem } 3702e5aa866SPaul Moore 3712e5aa866SPaul Moore ctx->ctx_doi = XFRM_SC_DOI_LSM; 3722e5aa866SPaul Moore ctx->ctx_alg = XFRM_SC_ALG_SELINUX; 3732e5aa866SPaul Moore ctx->ctx_sid = secid; 3742e5aa866SPaul Moore ctx->ctx_len = str_len; 3752e5aa866SPaul Moore memcpy(ctx->ctx_str, ctx_str, str_len); 3762e5aa866SPaul Moore 3772e5aa866SPaul Moore x->security = ctx; 378d621d35eSPaul Moore atomic_inc(&selinux_xfrm_refcount); 3790af90164SGeyslan G. Bem out: 3800af90164SGeyslan G. Bem kfree(ctx_str); 3810af90164SGeyslan G. Bem return rc; 382d28d1e08STrent Jaeger } 383d28d1e08STrent Jaeger 384d28d1e08STrent Jaeger /* 385d28d1e08STrent Jaeger * LSM hook implementation that frees xfrm_state security information. 386d28d1e08STrent Jaeger */ 387d28d1e08STrent Jaeger void selinux_xfrm_state_free(struct xfrm_state *x) 388d28d1e08STrent Jaeger { 389ccf17cc4SPaul Moore selinux_xfrm_free(x->security); 390d28d1e08STrent Jaeger } 391d28d1e08STrent Jaeger 3922c7946a7SCatherine Zhang /* 393c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled SAs. 394c8c05a8eSCatherine Zhang */ 395c8c05a8eSCatherine Zhang int selinux_xfrm_state_delete(struct xfrm_state *x) 396c8c05a8eSCatherine Zhang { 397ccf17cc4SPaul Moore return selinux_xfrm_delete(x->security); 398c8c05a8eSCatherine Zhang } 399c8c05a8eSCatherine Zhang 400c8c05a8eSCatherine Zhang /* 401d28d1e08STrent Jaeger * LSM hook that controls access to unlabelled packets. If 402d28d1e08STrent Jaeger * a xfrm_state is authorizable (defined by macro) then it was 403d28d1e08STrent Jaeger * already authorized by the IPSec process. If not, then 404d28d1e08STrent Jaeger * we need to check for unlabelled access since this may not have 405d28d1e08STrent Jaeger * gone thru the IPSec process. 406d28d1e08STrent Jaeger */ 407eef9b416SPaul Moore int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb, 4082bf49690SThomas Liu struct common_audit_data *ad) 409d28d1e08STrent Jaeger { 410eef9b416SPaul Moore int i; 4112294be0fSFlorian Westphal struct sec_path *sp = skb_sec_path(skb); 412eef9b416SPaul Moore u32 peer_sid = SECINITSID_UNLABELED; 413d28d1e08STrent Jaeger 414d28d1e08STrent Jaeger if (sp) { 415d28d1e08STrent Jaeger for (i = 0; i < sp->len; i++) { 41667644726SDave Jones struct xfrm_state *x = sp->xvec[i]; 417d28d1e08STrent Jaeger 418e0d1caa7SVenkat Yekkirala if (x && selinux_authorizable_xfrm(x)) { 419e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = x->security; 420eef9b416SPaul Moore peer_sid = ctx->ctx_sid; 421e0d1caa7SVenkat Yekkirala break; 422e0d1caa7SVenkat Yekkirala } 423d28d1e08STrent Jaeger } 424d28d1e08STrent Jaeger } 425d28d1e08STrent Jaeger 426eef9b416SPaul Moore /* This check even when there's no association involved is intended, 427eef9b416SPaul Moore * according to Trent Jaeger, to make sure a process can't engage in 428eef9b416SPaul Moore * non-IPsec communication unless explicitly allowed by policy. */ 4296b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 4306b6bc620SStephen Smalley sk_sid, peer_sid, 431eef9b416SPaul Moore SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad); 432d28d1e08STrent Jaeger } 433d28d1e08STrent Jaeger 434d28d1e08STrent Jaeger /* 435d28d1e08STrent Jaeger * POSTROUTE_LAST hook's XFRM processing: 436d28d1e08STrent Jaeger * If we have no security association, then we need to determine 437d28d1e08STrent Jaeger * whether the socket is allowed to send to an unlabelled destination. 438d28d1e08STrent Jaeger * If we do have a authorizable security association, then it has already been 43967f83cbfSVenkat Yekkirala * checked in the selinux_xfrm_state_pol_flow_match hook above. 440d28d1e08STrent Jaeger */ 441eef9b416SPaul Moore int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb, 4422bf49690SThomas Liu struct common_audit_data *ad, u8 proto) 443d28d1e08STrent Jaeger { 444d28d1e08STrent Jaeger struct dst_entry *dst; 445d28d1e08STrent Jaeger 44667f83cbfSVenkat Yekkirala switch (proto) { 44767f83cbfSVenkat Yekkirala case IPPROTO_AH: 44867f83cbfSVenkat Yekkirala case IPPROTO_ESP: 44967f83cbfSVenkat Yekkirala case IPPROTO_COMP: 450eef9b416SPaul Moore /* We should have already seen this packet once before it 451eef9b416SPaul Moore * underwent xfrm(s). No need to subject it to the unlabeled 452eef9b416SPaul Moore * check. */ 453eef9b416SPaul Moore return 0; 45467f83cbfSVenkat Yekkirala default: 45567f83cbfSVenkat Yekkirala break; 45667f83cbfSVenkat Yekkirala } 45767f83cbfSVenkat Yekkirala 458eef9b416SPaul Moore dst = skb_dst(skb); 459eef9b416SPaul Moore if (dst) { 460eef9b416SPaul Moore struct dst_entry *iter; 46167f83cbfSVenkat Yekkirala 462b92cf4aaSDavid Miller for (iter = dst; iter != NULL; iter = xfrm_dst_child(iter)) { 463eef9b416SPaul Moore struct xfrm_state *x = iter->xfrm; 464eef9b416SPaul Moore 465eef9b416SPaul Moore if (x && selinux_authorizable_xfrm(x)) 466eef9b416SPaul Moore return 0; 467eef9b416SPaul Moore } 468eef9b416SPaul Moore } 469eef9b416SPaul Moore 470eef9b416SPaul Moore /* This check even when there's no association involved is intended, 471eef9b416SPaul Moore * according to Trent Jaeger, to make sure a process can't engage in 472eef9b416SPaul Moore * non-IPsec communication unless explicitly allowed by policy. */ 4736b6bc620SStephen Smalley return avc_has_perm(&selinux_state, sk_sid, SECINITSID_UNLABELED, 474eef9b416SPaul Moore SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad); 475d28d1e08STrent Jaeger } 476