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> 38d28d1e08STrent Jaeger #include <linux/netfilter.h> 39d28d1e08STrent Jaeger #include <linux/netfilter_ipv4.h> 40d28d1e08STrent Jaeger #include <linux/netfilter_ipv6.h> 41d28d1e08STrent Jaeger #include <linux/ip.h> 42d28d1e08STrent Jaeger #include <linux/tcp.h> 43d28d1e08STrent Jaeger #include <linux/skbuff.h> 44d28d1e08STrent Jaeger #include <linux/xfrm.h> 45d28d1e08STrent Jaeger #include <net/xfrm.h> 46d28d1e08STrent Jaeger #include <net/checksum.h> 47d28d1e08STrent Jaeger #include <net/udp.h> 48d28d1e08STrent Jaeger #include <asm/semaphore.h> 49d621d35eSPaul Moore #include <asm/atomic.h> 50d28d1e08STrent Jaeger 51d28d1e08STrent Jaeger #include "avc.h" 52d28d1e08STrent Jaeger #include "objsec.h" 53d28d1e08STrent Jaeger #include "xfrm.h" 54d28d1e08STrent Jaeger 55d621d35eSPaul Moore /* Labeled XFRM instance counter */ 56d621d35eSPaul Moore atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0); 57d28d1e08STrent Jaeger 58d28d1e08STrent Jaeger /* 59d28d1e08STrent Jaeger * Returns true if an LSM/SELinux context 60d28d1e08STrent Jaeger */ 61d28d1e08STrent Jaeger static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx) 62d28d1e08STrent Jaeger { 63d28d1e08STrent Jaeger return (ctx && 64d28d1e08STrent Jaeger (ctx->ctx_doi == XFRM_SC_DOI_LSM) && 65d28d1e08STrent Jaeger (ctx->ctx_alg == XFRM_SC_ALG_SELINUX)); 66d28d1e08STrent Jaeger } 67d28d1e08STrent Jaeger 68d28d1e08STrent Jaeger /* 69d28d1e08STrent Jaeger * Returns true if the xfrm contains a security blob for SELinux 70d28d1e08STrent Jaeger */ 71d28d1e08STrent Jaeger static inline int selinux_authorizable_xfrm(struct xfrm_state *x) 72d28d1e08STrent Jaeger { 73d28d1e08STrent Jaeger return selinux_authorizable_ctx(x->security); 74d28d1e08STrent Jaeger } 75d28d1e08STrent Jaeger 76d28d1e08STrent Jaeger /* 77e0d1caa7SVenkat Yekkirala * LSM hook implementation that authorizes that a flow can use 78e0d1caa7SVenkat Yekkirala * a xfrm policy rule. 79d28d1e08STrent Jaeger */ 80e0d1caa7SVenkat Yekkirala int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) 81d28d1e08STrent Jaeger { 825b368e61SVenkat Yekkirala int rc; 835b368e61SVenkat Yekkirala u32 sel_sid; 84d28d1e08STrent Jaeger struct xfrm_sec_ctx *ctx; 85d28d1e08STrent Jaeger 86d28d1e08STrent Jaeger /* Context sid is either set to label or ANY_ASSOC */ 87d28d1e08STrent Jaeger if ((ctx = xp->security)) { 88d28d1e08STrent Jaeger if (!selinux_authorizable_ctx(ctx)) 89d28d1e08STrent Jaeger return -EINVAL; 90d28d1e08STrent Jaeger 91d28d1e08STrent Jaeger sel_sid = ctx->ctx_sid; 92d28d1e08STrent Jaeger } 935b368e61SVenkat Yekkirala else 945b368e61SVenkat Yekkirala /* 955b368e61SVenkat Yekkirala * All flows should be treated as polmatch'ing an 965b368e61SVenkat Yekkirala * otherwise applicable "non-labeled" policy. This 975b368e61SVenkat Yekkirala * would prevent inadvertent "leaks". 985b368e61SVenkat Yekkirala */ 995b368e61SVenkat Yekkirala return 0; 100d28d1e08STrent Jaeger 101e0d1caa7SVenkat Yekkirala rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, 102e0d1caa7SVenkat Yekkirala ASSOCIATION__POLMATCH, 103d28d1e08STrent Jaeger NULL); 104d28d1e08STrent Jaeger 1055b368e61SVenkat Yekkirala if (rc == -EACCES) 1065b368e61SVenkat Yekkirala rc = -ESRCH; 1075b368e61SVenkat Yekkirala 108d28d1e08STrent Jaeger return rc; 109d28d1e08STrent Jaeger } 110d28d1e08STrent Jaeger 111d28d1e08STrent Jaeger /* 112e0d1caa7SVenkat Yekkirala * LSM hook implementation that authorizes that a state matches 113e0d1caa7SVenkat Yekkirala * the given policy, flow combo. 114e0d1caa7SVenkat Yekkirala */ 115e0d1caa7SVenkat Yekkirala 116e0d1caa7SVenkat Yekkirala int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, 117e0d1caa7SVenkat Yekkirala struct flowi *fl) 118e0d1caa7SVenkat Yekkirala { 119e0d1caa7SVenkat Yekkirala u32 state_sid; 12067f83cbfSVenkat Yekkirala int rc; 121e0d1caa7SVenkat Yekkirala 12267f83cbfSVenkat Yekkirala if (!xp->security) 1235b368e61SVenkat Yekkirala if (x->security) 1245b368e61SVenkat Yekkirala /* unlabeled policy and labeled SA can't match */ 1255b368e61SVenkat Yekkirala return 0; 126e0d1caa7SVenkat Yekkirala else 1275b368e61SVenkat Yekkirala /* unlabeled policy and unlabeled SA match all flows */ 1285b368e61SVenkat Yekkirala return 1; 12967f83cbfSVenkat Yekkirala else 13067f83cbfSVenkat Yekkirala if (!x->security) 13167f83cbfSVenkat Yekkirala /* unlabeled SA and labeled policy can't match */ 13267f83cbfSVenkat Yekkirala return 0; 13367f83cbfSVenkat Yekkirala else 13467f83cbfSVenkat Yekkirala if (!selinux_authorizable_xfrm(x)) 13567f83cbfSVenkat Yekkirala /* Not a SELinux-labeled SA */ 136e0d1caa7SVenkat Yekkirala return 0; 137e0d1caa7SVenkat Yekkirala 13867f83cbfSVenkat Yekkirala state_sid = x->security->ctx_sid; 13967f83cbfSVenkat Yekkirala 14067f83cbfSVenkat Yekkirala if (fl->secid != state_sid) 14167f83cbfSVenkat Yekkirala return 0; 14267f83cbfSVenkat Yekkirala 14367f83cbfSVenkat Yekkirala rc = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, 1445b368e61SVenkat Yekkirala ASSOCIATION__SENDTO, 1455b368e61SVenkat Yekkirala NULL)? 0:1; 1465b368e61SVenkat Yekkirala 147e0d1caa7SVenkat Yekkirala /* 14867f83cbfSVenkat Yekkirala * We don't need a separate SA Vs. policy polmatch check 14967f83cbfSVenkat Yekkirala * since the SA is now of the same label as the flow and 15067f83cbfSVenkat Yekkirala * a flow Vs. policy polmatch check had already happened 15167f83cbfSVenkat Yekkirala * in selinux_xfrm_policy_lookup() above. 152e0d1caa7SVenkat Yekkirala */ 153e0d1caa7SVenkat Yekkirala 154e0d1caa7SVenkat Yekkirala return rc; 155e0d1caa7SVenkat Yekkirala } 156e0d1caa7SVenkat Yekkirala 157e0d1caa7SVenkat Yekkirala /* 1586b877699SVenkat Yekkirala * LSM hook implementation that checks and/or returns the xfrm sid for the 1596b877699SVenkat Yekkirala * incoming packet. 160e0d1caa7SVenkat Yekkirala */ 161e0d1caa7SVenkat Yekkirala 162beb8d13bSVenkat Yekkirala int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) 163e0d1caa7SVenkat Yekkirala { 164e0d1caa7SVenkat Yekkirala struct sec_path *sp; 165e0d1caa7SVenkat Yekkirala 166beb8d13bSVenkat Yekkirala *sid = SECSID_NULL; 167e0d1caa7SVenkat Yekkirala 168e0d1caa7SVenkat Yekkirala if (skb == NULL) 169e0d1caa7SVenkat Yekkirala return 0; 170e0d1caa7SVenkat Yekkirala 171e0d1caa7SVenkat Yekkirala sp = skb->sp; 172e0d1caa7SVenkat Yekkirala if (sp) { 173e0d1caa7SVenkat Yekkirala int i, sid_set = 0; 174e0d1caa7SVenkat Yekkirala 175e0d1caa7SVenkat Yekkirala for (i = sp->len-1; i >= 0; i--) { 176e0d1caa7SVenkat Yekkirala struct xfrm_state *x = sp->xvec[i]; 177e0d1caa7SVenkat Yekkirala if (selinux_authorizable_xfrm(x)) { 178e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = x->security; 179e0d1caa7SVenkat Yekkirala 180e0d1caa7SVenkat Yekkirala if (!sid_set) { 181beb8d13bSVenkat Yekkirala *sid = ctx->ctx_sid; 182e0d1caa7SVenkat Yekkirala sid_set = 1; 183beb8d13bSVenkat Yekkirala 184beb8d13bSVenkat Yekkirala if (!ckall) 185beb8d13bSVenkat Yekkirala break; 186e0d1caa7SVenkat Yekkirala } 187beb8d13bSVenkat Yekkirala else if (*sid != ctx->ctx_sid) 188e0d1caa7SVenkat Yekkirala return -EINVAL; 189e0d1caa7SVenkat Yekkirala } 190e0d1caa7SVenkat Yekkirala } 191e0d1caa7SVenkat Yekkirala } 192e0d1caa7SVenkat Yekkirala 193e0d1caa7SVenkat Yekkirala return 0; 194e0d1caa7SVenkat Yekkirala } 195e0d1caa7SVenkat Yekkirala 196e0d1caa7SVenkat Yekkirala /* 197d28d1e08STrent Jaeger * Security blob allocation for xfrm_policy and xfrm_state 198d28d1e08STrent Jaeger * CTX does not have a meaningful value on input 199d28d1e08STrent Jaeger */ 200e0d1caa7SVenkat Yekkirala static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, 201c1a856c9SVenkat Yekkirala struct xfrm_user_sec_ctx *uctx, u32 sid) 202d28d1e08STrent Jaeger { 203d28d1e08STrent Jaeger int rc = 0; 204d28d1e08STrent Jaeger struct task_security_struct *tsec = current->security; 205e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = NULL; 206e0d1caa7SVenkat Yekkirala char *ctx_str = NULL; 207e0d1caa7SVenkat Yekkirala u32 str_len; 208e0d1caa7SVenkat Yekkirala 209c1a856c9SVenkat Yekkirala BUG_ON(uctx && sid); 210e0d1caa7SVenkat Yekkirala 211cb969f07SVenkat Yekkirala if (!uctx) 212cb969f07SVenkat Yekkirala goto not_from_user; 213e0d1caa7SVenkat Yekkirala 214e0d1caa7SVenkat Yekkirala if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX) 215e0d1caa7SVenkat Yekkirala return -EINVAL; 216d28d1e08STrent Jaeger 21757002bfbSStephen Rothwell str_len = uctx->ctx_len; 21857002bfbSStephen Rothwell if (str_len >= PAGE_SIZE) 219d28d1e08STrent Jaeger return -ENOMEM; 220d28d1e08STrent Jaeger 221d28d1e08STrent Jaeger *ctxp = ctx = kmalloc(sizeof(*ctx) + 22257002bfbSStephen Rothwell str_len + 1, 223d28d1e08STrent Jaeger GFP_KERNEL); 224d28d1e08STrent Jaeger 225d28d1e08STrent Jaeger if (!ctx) 226d28d1e08STrent Jaeger return -ENOMEM; 227d28d1e08STrent Jaeger 228d28d1e08STrent Jaeger ctx->ctx_doi = uctx->ctx_doi; 22957002bfbSStephen Rothwell ctx->ctx_len = str_len; 230d28d1e08STrent Jaeger ctx->ctx_alg = uctx->ctx_alg; 231d28d1e08STrent Jaeger 232d28d1e08STrent Jaeger memcpy(ctx->ctx_str, 233d28d1e08STrent Jaeger uctx+1, 23457002bfbSStephen Rothwell str_len); 23557002bfbSStephen Rothwell ctx->ctx_str[str_len] = 0; 236d28d1e08STrent Jaeger rc = security_context_to_sid(ctx->ctx_str, 23757002bfbSStephen Rothwell str_len, 238d28d1e08STrent Jaeger &ctx->ctx_sid); 239d28d1e08STrent Jaeger 240d28d1e08STrent Jaeger if (rc) 241d28d1e08STrent Jaeger goto out; 242d28d1e08STrent Jaeger 243d28d1e08STrent Jaeger /* 244c8c05a8eSCatherine Zhang * Does the subject have permission to set security context? 245d28d1e08STrent Jaeger */ 246d28d1e08STrent Jaeger rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 247d28d1e08STrent Jaeger SECCLASS_ASSOCIATION, 2485f8ac64bSTrent Jaeger ASSOCIATION__SETCONTEXT, NULL); 249d28d1e08STrent Jaeger if (rc) 250d28d1e08STrent Jaeger goto out; 251d28d1e08STrent Jaeger 252d28d1e08STrent Jaeger return rc; 253d28d1e08STrent Jaeger 254cb969f07SVenkat Yekkirala not_from_user: 255c1a856c9SVenkat Yekkirala rc = security_sid_to_context(sid, &ctx_str, &str_len); 256e0d1caa7SVenkat Yekkirala if (rc) 257e0d1caa7SVenkat Yekkirala goto out; 258e0d1caa7SVenkat Yekkirala 259e0d1caa7SVenkat Yekkirala *ctxp = ctx = kmalloc(sizeof(*ctx) + 260e0d1caa7SVenkat Yekkirala str_len, 261e0d1caa7SVenkat Yekkirala GFP_ATOMIC); 262e0d1caa7SVenkat Yekkirala 263e0d1caa7SVenkat Yekkirala if (!ctx) { 264e0d1caa7SVenkat Yekkirala rc = -ENOMEM; 265e0d1caa7SVenkat Yekkirala goto out; 266e0d1caa7SVenkat Yekkirala } 267e0d1caa7SVenkat Yekkirala 268e0d1caa7SVenkat Yekkirala ctx->ctx_doi = XFRM_SC_DOI_LSM; 269e0d1caa7SVenkat Yekkirala ctx->ctx_alg = XFRM_SC_ALG_SELINUX; 270c1a856c9SVenkat Yekkirala ctx->ctx_sid = sid; 271e0d1caa7SVenkat Yekkirala ctx->ctx_len = str_len; 272e0d1caa7SVenkat Yekkirala memcpy(ctx->ctx_str, 273e0d1caa7SVenkat Yekkirala ctx_str, 274e0d1caa7SVenkat Yekkirala str_len); 275e0d1caa7SVenkat Yekkirala 276e0d1caa7SVenkat Yekkirala goto out2; 277e0d1caa7SVenkat Yekkirala 278d28d1e08STrent Jaeger out: 279ee2e6841SLuiz Capitulino *ctxp = NULL; 280d28d1e08STrent Jaeger kfree(ctx); 281e0d1caa7SVenkat Yekkirala out2: 282e0d1caa7SVenkat Yekkirala kfree(ctx_str); 283d28d1e08STrent Jaeger return rc; 284d28d1e08STrent Jaeger } 285d28d1e08STrent Jaeger 286d28d1e08STrent Jaeger /* 287d28d1e08STrent Jaeger * LSM hook implementation that allocs and transfers uctx spec to 288d28d1e08STrent Jaeger * xfrm_policy. 289d28d1e08STrent Jaeger */ 290cb969f07SVenkat Yekkirala int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, 291c1a856c9SVenkat Yekkirala struct xfrm_user_sec_ctx *uctx) 292d28d1e08STrent Jaeger { 293d28d1e08STrent Jaeger int err; 294d28d1e08STrent Jaeger 295d28d1e08STrent Jaeger BUG_ON(!xp); 296c1a856c9SVenkat Yekkirala BUG_ON(!uctx); 297d28d1e08STrent Jaeger 298c1a856c9SVenkat Yekkirala err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); 299d621d35eSPaul Moore if (err == 0) 300d621d35eSPaul Moore atomic_inc(&selinux_xfrm_refcount); 301d621d35eSPaul Moore 302d28d1e08STrent Jaeger return err; 303d28d1e08STrent Jaeger } 304d28d1e08STrent Jaeger 305d28d1e08STrent Jaeger 306d28d1e08STrent Jaeger /* 307d28d1e08STrent Jaeger * LSM hook implementation that copies security data structure from old to 308d28d1e08STrent Jaeger * new for policy cloning. 309d28d1e08STrent Jaeger */ 310d28d1e08STrent Jaeger int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) 311d28d1e08STrent Jaeger { 312d28d1e08STrent Jaeger struct xfrm_sec_ctx *old_ctx, *new_ctx; 313d28d1e08STrent Jaeger 314d28d1e08STrent Jaeger old_ctx = old->security; 315d28d1e08STrent Jaeger 316d28d1e08STrent Jaeger if (old_ctx) { 317d28d1e08STrent Jaeger new_ctx = new->security = kmalloc(sizeof(*new_ctx) + 318d28d1e08STrent Jaeger old_ctx->ctx_len, 319d28d1e08STrent Jaeger GFP_KERNEL); 320d28d1e08STrent Jaeger 321d28d1e08STrent Jaeger if (!new_ctx) 322d28d1e08STrent Jaeger return -ENOMEM; 323d28d1e08STrent Jaeger 324d28d1e08STrent Jaeger memcpy(new_ctx, old_ctx, sizeof(*new_ctx)); 325d28d1e08STrent Jaeger memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len); 326d28d1e08STrent Jaeger } 327d28d1e08STrent Jaeger return 0; 328d28d1e08STrent Jaeger } 329d28d1e08STrent Jaeger 330d28d1e08STrent Jaeger /* 331d28d1e08STrent Jaeger * LSM hook implementation that frees xfrm_policy security information. 332d28d1e08STrent Jaeger */ 333d28d1e08STrent Jaeger void selinux_xfrm_policy_free(struct xfrm_policy *xp) 334d28d1e08STrent Jaeger { 335d28d1e08STrent Jaeger struct xfrm_sec_ctx *ctx = xp->security; 336d28d1e08STrent Jaeger if (ctx) 337d28d1e08STrent Jaeger kfree(ctx); 338d28d1e08STrent Jaeger } 339d28d1e08STrent Jaeger 340d28d1e08STrent Jaeger /* 341c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled policies. 342c8c05a8eSCatherine Zhang */ 343c8c05a8eSCatherine Zhang int selinux_xfrm_policy_delete(struct xfrm_policy *xp) 344c8c05a8eSCatherine Zhang { 345c8c05a8eSCatherine Zhang struct task_security_struct *tsec = current->security; 346c8c05a8eSCatherine Zhang struct xfrm_sec_ctx *ctx = xp->security; 347c8c05a8eSCatherine Zhang int rc = 0; 348c8c05a8eSCatherine Zhang 349d621d35eSPaul Moore if (ctx) { 350c8c05a8eSCatherine Zhang rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 351c8c05a8eSCatherine Zhang SECCLASS_ASSOCIATION, 352c8c05a8eSCatherine Zhang ASSOCIATION__SETCONTEXT, NULL); 353d621d35eSPaul Moore if (rc == 0) 354d621d35eSPaul Moore atomic_dec(&selinux_xfrm_refcount); 355d621d35eSPaul Moore } 356c8c05a8eSCatherine Zhang 357c8c05a8eSCatherine Zhang return rc; 358c8c05a8eSCatherine Zhang } 359c8c05a8eSCatherine Zhang 360c8c05a8eSCatherine Zhang /* 361d28d1e08STrent Jaeger * LSM hook implementation that allocs and transfers sec_ctx spec to 362d28d1e08STrent Jaeger * xfrm_state. 363d28d1e08STrent Jaeger */ 364e0d1caa7SVenkat Yekkirala int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, 365c1a856c9SVenkat Yekkirala u32 secid) 366d28d1e08STrent Jaeger { 367d28d1e08STrent Jaeger int err; 368d28d1e08STrent Jaeger 369d28d1e08STrent Jaeger BUG_ON(!x); 370d28d1e08STrent Jaeger 371c1a856c9SVenkat Yekkirala err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); 372d621d35eSPaul Moore if (err == 0) 373d621d35eSPaul Moore atomic_inc(&selinux_xfrm_refcount); 374d28d1e08STrent Jaeger return err; 375d28d1e08STrent Jaeger } 376d28d1e08STrent Jaeger 377d28d1e08STrent Jaeger /* 378d28d1e08STrent Jaeger * LSM hook implementation that frees xfrm_state security information. 379d28d1e08STrent Jaeger */ 380d28d1e08STrent Jaeger void selinux_xfrm_state_free(struct xfrm_state *x) 381d28d1e08STrent Jaeger { 382d28d1e08STrent Jaeger struct xfrm_sec_ctx *ctx = x->security; 383d28d1e08STrent Jaeger if (ctx) 384d28d1e08STrent Jaeger kfree(ctx); 385d28d1e08STrent Jaeger } 386d28d1e08STrent Jaeger 3872c7946a7SCatherine Zhang /* 388c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled SAs. 389c8c05a8eSCatherine Zhang */ 390c8c05a8eSCatherine Zhang int selinux_xfrm_state_delete(struct xfrm_state *x) 391c8c05a8eSCatherine Zhang { 392c8c05a8eSCatherine Zhang struct task_security_struct *tsec = current->security; 393c8c05a8eSCatherine Zhang struct xfrm_sec_ctx *ctx = x->security; 394c8c05a8eSCatherine Zhang int rc = 0; 395c8c05a8eSCatherine Zhang 396d621d35eSPaul Moore if (ctx) { 397c8c05a8eSCatherine Zhang rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 398c8c05a8eSCatherine Zhang SECCLASS_ASSOCIATION, 399c8c05a8eSCatherine Zhang ASSOCIATION__SETCONTEXT, NULL); 400d621d35eSPaul Moore if (rc == 0) 401d621d35eSPaul Moore atomic_dec(&selinux_xfrm_refcount); 402d621d35eSPaul Moore } 403c8c05a8eSCatherine Zhang 404c8c05a8eSCatherine Zhang return rc; 405c8c05a8eSCatherine Zhang } 406c8c05a8eSCatherine Zhang 407c8c05a8eSCatherine Zhang /* 408d28d1e08STrent Jaeger * LSM hook that controls access to unlabelled packets. If 409d28d1e08STrent Jaeger * a xfrm_state is authorizable (defined by macro) then it was 410d28d1e08STrent Jaeger * already authorized by the IPSec process. If not, then 411d28d1e08STrent Jaeger * we need to check for unlabelled access since this may not have 412d28d1e08STrent Jaeger * gone thru the IPSec process. 413d28d1e08STrent Jaeger */ 414e0d1caa7SVenkat Yekkirala int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, 415e0d1caa7SVenkat Yekkirala struct avc_audit_data *ad) 416d28d1e08STrent Jaeger { 417d28d1e08STrent Jaeger int i, rc = 0; 418d28d1e08STrent Jaeger struct sec_path *sp; 419e0d1caa7SVenkat Yekkirala u32 sel_sid = SECINITSID_UNLABELED; 420d28d1e08STrent Jaeger 421d28d1e08STrent Jaeger sp = skb->sp; 422d28d1e08STrent Jaeger 423d28d1e08STrent Jaeger if (sp) { 424d28d1e08STrent Jaeger for (i = 0; i < sp->len; i++) { 42567644726SDave Jones struct xfrm_state *x = sp->xvec[i]; 426d28d1e08STrent Jaeger 427e0d1caa7SVenkat Yekkirala if (x && selinux_authorizable_xfrm(x)) { 428e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = x->security; 429e0d1caa7SVenkat Yekkirala sel_sid = ctx->ctx_sid; 430e0d1caa7SVenkat Yekkirala break; 431e0d1caa7SVenkat Yekkirala } 432d28d1e08STrent Jaeger } 433d28d1e08STrent Jaeger } 434d28d1e08STrent Jaeger 43567f83cbfSVenkat Yekkirala /* 43667f83cbfSVenkat Yekkirala * This check even when there's no association involved is 43767f83cbfSVenkat Yekkirala * intended, according to Trent Jaeger, to make sure a 43867f83cbfSVenkat Yekkirala * process can't engage in non-ipsec communication unless 43967f83cbfSVenkat Yekkirala * explicitly allowed by policy. 44067f83cbfSVenkat Yekkirala */ 44167f83cbfSVenkat Yekkirala 442e0d1caa7SVenkat Yekkirala rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, 443e0d1caa7SVenkat Yekkirala ASSOCIATION__RECVFROM, ad); 444d28d1e08STrent Jaeger 445d28d1e08STrent Jaeger return rc; 446d28d1e08STrent Jaeger } 447d28d1e08STrent Jaeger 448d28d1e08STrent Jaeger /* 449d28d1e08STrent Jaeger * POSTROUTE_LAST hook's XFRM processing: 450d28d1e08STrent Jaeger * If we have no security association, then we need to determine 451d28d1e08STrent Jaeger * whether the socket is allowed to send to an unlabelled destination. 452d28d1e08STrent Jaeger * If we do have a authorizable security association, then it has already been 45367f83cbfSVenkat Yekkirala * checked in the selinux_xfrm_state_pol_flow_match hook above. 454d28d1e08STrent Jaeger */ 455e0d1caa7SVenkat Yekkirala int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, 45667f83cbfSVenkat Yekkirala struct avc_audit_data *ad, u8 proto) 457d28d1e08STrent Jaeger { 458d28d1e08STrent Jaeger struct dst_entry *dst; 459d28d1e08STrent Jaeger int rc = 0; 460d28d1e08STrent Jaeger 461d28d1e08STrent Jaeger dst = skb->dst; 462d28d1e08STrent Jaeger 463d28d1e08STrent Jaeger if (dst) { 464d28d1e08STrent Jaeger struct dst_entry *dst_test; 465d28d1e08STrent Jaeger 466c80544dcSStephen Hemminger for (dst_test = dst; dst_test != NULL; 467d28d1e08STrent Jaeger dst_test = dst_test->child) { 468d28d1e08STrent Jaeger struct xfrm_state *x = dst_test->xfrm; 469d28d1e08STrent Jaeger 470d28d1e08STrent Jaeger if (x && selinux_authorizable_xfrm(x)) 4714e5ab4cbSJames Morris goto out; 472d28d1e08STrent Jaeger } 473d28d1e08STrent Jaeger } 474d28d1e08STrent Jaeger 47567f83cbfSVenkat Yekkirala switch (proto) { 47667f83cbfSVenkat Yekkirala case IPPROTO_AH: 47767f83cbfSVenkat Yekkirala case IPPROTO_ESP: 47867f83cbfSVenkat Yekkirala case IPPROTO_COMP: 47967f83cbfSVenkat Yekkirala /* 48067f83cbfSVenkat Yekkirala * We should have already seen this packet once before 48167f83cbfSVenkat Yekkirala * it underwent xfrm(s). No need to subject it to the 48267f83cbfSVenkat Yekkirala * unlabeled check. 48367f83cbfSVenkat Yekkirala */ 48467f83cbfSVenkat Yekkirala goto out; 48567f83cbfSVenkat Yekkirala default: 48667f83cbfSVenkat Yekkirala break; 48767f83cbfSVenkat Yekkirala } 48867f83cbfSVenkat Yekkirala 48967f83cbfSVenkat Yekkirala /* 49067f83cbfSVenkat Yekkirala * This check even when there's no association involved is 49167f83cbfSVenkat Yekkirala * intended, according to Trent Jaeger, to make sure a 49267f83cbfSVenkat Yekkirala * process can't engage in non-ipsec communication unless 49367f83cbfSVenkat Yekkirala * explicitly allowed by policy. 49467f83cbfSVenkat Yekkirala */ 49567f83cbfSVenkat Yekkirala 496d28d1e08STrent Jaeger rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, 497e0d1caa7SVenkat Yekkirala ASSOCIATION__SENDTO, ad); 4984e5ab4cbSJames Morris out: 4994e5ab4cbSJames Morris return rc; 500d28d1e08STrent Jaeger } 501