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> 415a0e3ad6STejun Heo #include <linux/slab.h> 42d28d1e08STrent Jaeger #include <linux/ip.h> 43d28d1e08STrent Jaeger #include <linux/tcp.h> 44d28d1e08STrent Jaeger #include <linux/skbuff.h> 45d28d1e08STrent Jaeger #include <linux/xfrm.h> 46d28d1e08STrent Jaeger #include <net/xfrm.h> 47d28d1e08STrent Jaeger #include <net/checksum.h> 48d28d1e08STrent Jaeger #include <net/udp.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 */ 8003e1ad7bSPaul Moore int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) 81d28d1e08STrent Jaeger { 825b368e61SVenkat Yekkirala int rc; 835b368e61SVenkat Yekkirala u32 sel_sid; 84d28d1e08STrent Jaeger 85d28d1e08STrent Jaeger /* Context sid is either set to label or ANY_ASSOC */ 8603e1ad7bSPaul Moore if (ctx) { 87d28d1e08STrent Jaeger if (!selinux_authorizable_ctx(ctx)) 88d28d1e08STrent Jaeger return -EINVAL; 89d28d1e08STrent Jaeger 90d28d1e08STrent Jaeger sel_sid = ctx->ctx_sid; 9103e1ad7bSPaul Moore } else 925b368e61SVenkat Yekkirala /* 935b368e61SVenkat Yekkirala * All flows should be treated as polmatch'ing an 945b368e61SVenkat Yekkirala * otherwise applicable "non-labeled" policy. This 955b368e61SVenkat Yekkirala * would prevent inadvertent "leaks". 965b368e61SVenkat Yekkirala */ 975b368e61SVenkat Yekkirala return 0; 98d28d1e08STrent Jaeger 99e0d1caa7SVenkat Yekkirala rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, 100e0d1caa7SVenkat Yekkirala ASSOCIATION__POLMATCH, 101d28d1e08STrent Jaeger NULL); 102d28d1e08STrent Jaeger 1035b368e61SVenkat Yekkirala if (rc == -EACCES) 10403e1ad7bSPaul Moore return -ESRCH; 1055b368e61SVenkat Yekkirala 106d28d1e08STrent Jaeger return rc; 107d28d1e08STrent Jaeger } 108d28d1e08STrent Jaeger 109d28d1e08STrent Jaeger /* 110e0d1caa7SVenkat Yekkirala * LSM hook implementation that authorizes that a state matches 111e0d1caa7SVenkat Yekkirala * the given policy, flow combo. 112e0d1caa7SVenkat Yekkirala */ 113e0d1caa7SVenkat Yekkirala 114e0d1caa7SVenkat Yekkirala int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, 115e33f7704SDavid S. Miller const struct flowi *fl) 116e0d1caa7SVenkat Yekkirala { 117e0d1caa7SVenkat Yekkirala u32 state_sid; 11867f83cbfSVenkat Yekkirala int rc; 119e0d1caa7SVenkat Yekkirala 12067f83cbfSVenkat Yekkirala if (!xp->security) 1215b368e61SVenkat Yekkirala if (x->security) 1225b368e61SVenkat Yekkirala /* unlabeled policy and labeled SA can't match */ 1235b368e61SVenkat Yekkirala return 0; 124e0d1caa7SVenkat Yekkirala else 1255b368e61SVenkat Yekkirala /* unlabeled policy and unlabeled SA match all flows */ 1265b368e61SVenkat Yekkirala return 1; 12767f83cbfSVenkat Yekkirala else 12867f83cbfSVenkat Yekkirala if (!x->security) 12967f83cbfSVenkat Yekkirala /* unlabeled SA and labeled policy can't match */ 13067f83cbfSVenkat Yekkirala return 0; 13167f83cbfSVenkat Yekkirala else 13267f83cbfSVenkat Yekkirala if (!selinux_authorizable_xfrm(x)) 13367f83cbfSVenkat Yekkirala /* Not a SELinux-labeled SA */ 134e0d1caa7SVenkat Yekkirala return 0; 135e0d1caa7SVenkat Yekkirala 13667f83cbfSVenkat Yekkirala state_sid = x->security->ctx_sid; 13767f83cbfSVenkat Yekkirala 13867f83cbfSVenkat Yekkirala if (fl->secid != state_sid) 13967f83cbfSVenkat Yekkirala return 0; 14067f83cbfSVenkat Yekkirala 14167f83cbfSVenkat Yekkirala rc = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION, 1425b368e61SVenkat Yekkirala ASSOCIATION__SENDTO, 1435b368e61SVenkat Yekkirala NULL)? 0:1; 1445b368e61SVenkat Yekkirala 145e0d1caa7SVenkat Yekkirala /* 14667f83cbfSVenkat Yekkirala * We don't need a separate SA Vs. policy polmatch check 14767f83cbfSVenkat Yekkirala * since the SA is now of the same label as the flow and 14867f83cbfSVenkat Yekkirala * a flow Vs. policy polmatch check had already happened 14967f83cbfSVenkat Yekkirala * in selinux_xfrm_policy_lookup() above. 150e0d1caa7SVenkat Yekkirala */ 151e0d1caa7SVenkat Yekkirala 152e0d1caa7SVenkat Yekkirala return rc; 153e0d1caa7SVenkat Yekkirala } 154e0d1caa7SVenkat Yekkirala 155e0d1caa7SVenkat Yekkirala /* 1566b877699SVenkat Yekkirala * LSM hook implementation that checks and/or returns the xfrm sid for the 1576b877699SVenkat Yekkirala * incoming packet. 158e0d1caa7SVenkat Yekkirala */ 159e0d1caa7SVenkat Yekkirala 160beb8d13bSVenkat Yekkirala int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) 161e0d1caa7SVenkat Yekkirala { 162e0d1caa7SVenkat Yekkirala struct sec_path *sp; 163e0d1caa7SVenkat Yekkirala 164beb8d13bSVenkat Yekkirala *sid = SECSID_NULL; 165e0d1caa7SVenkat Yekkirala 166e0d1caa7SVenkat Yekkirala if (skb == NULL) 167e0d1caa7SVenkat Yekkirala return 0; 168e0d1caa7SVenkat Yekkirala 169e0d1caa7SVenkat Yekkirala sp = skb->sp; 170e0d1caa7SVenkat Yekkirala if (sp) { 171e0d1caa7SVenkat Yekkirala int i, sid_set = 0; 172e0d1caa7SVenkat Yekkirala 173e0d1caa7SVenkat Yekkirala for (i = sp->len-1; i >= 0; i--) { 174e0d1caa7SVenkat Yekkirala struct xfrm_state *x = sp->xvec[i]; 175e0d1caa7SVenkat Yekkirala if (selinux_authorizable_xfrm(x)) { 176e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = x->security; 177e0d1caa7SVenkat Yekkirala 178e0d1caa7SVenkat Yekkirala if (!sid_set) { 179beb8d13bSVenkat Yekkirala *sid = ctx->ctx_sid; 180e0d1caa7SVenkat Yekkirala sid_set = 1; 181beb8d13bSVenkat Yekkirala 182beb8d13bSVenkat Yekkirala if (!ckall) 183beb8d13bSVenkat Yekkirala break; 1843c1c88abSEric Paris } else if (*sid != ctx->ctx_sid) 185e0d1caa7SVenkat Yekkirala return -EINVAL; 186e0d1caa7SVenkat Yekkirala } 187e0d1caa7SVenkat Yekkirala } 188e0d1caa7SVenkat Yekkirala } 189e0d1caa7SVenkat Yekkirala 190e0d1caa7SVenkat Yekkirala return 0; 191e0d1caa7SVenkat Yekkirala } 192e0d1caa7SVenkat Yekkirala 193e0d1caa7SVenkat Yekkirala /* 194d28d1e08STrent Jaeger * Security blob allocation for xfrm_policy and xfrm_state 195d28d1e08STrent Jaeger * CTX does not have a meaningful value on input 196d28d1e08STrent Jaeger */ 197e0d1caa7SVenkat Yekkirala static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, 198c1a856c9SVenkat Yekkirala struct xfrm_user_sec_ctx *uctx, u32 sid) 199d28d1e08STrent Jaeger { 200d28d1e08STrent Jaeger int rc = 0; 20186a264abSDavid Howells const struct task_security_struct *tsec = current_security(); 202e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = NULL; 203e0d1caa7SVenkat Yekkirala char *ctx_str = NULL; 204e0d1caa7SVenkat Yekkirala u32 str_len; 205e0d1caa7SVenkat Yekkirala 206c1a856c9SVenkat Yekkirala BUG_ON(uctx && sid); 207e0d1caa7SVenkat Yekkirala 208cb969f07SVenkat Yekkirala if (!uctx) 209cb969f07SVenkat Yekkirala goto not_from_user; 210e0d1caa7SVenkat Yekkirala 211e0d1caa7SVenkat Yekkirala if (uctx->ctx_doi != XFRM_SC_ALG_SELINUX) 212e0d1caa7SVenkat Yekkirala return -EINVAL; 213d28d1e08STrent Jaeger 21457002bfbSStephen Rothwell str_len = uctx->ctx_len; 21557002bfbSStephen Rothwell if (str_len >= PAGE_SIZE) 216d28d1e08STrent Jaeger return -ENOMEM; 217d28d1e08STrent Jaeger 218d28d1e08STrent Jaeger *ctxp = ctx = kmalloc(sizeof(*ctx) + 21957002bfbSStephen Rothwell str_len + 1, 220d28d1e08STrent Jaeger GFP_KERNEL); 221d28d1e08STrent Jaeger 222d28d1e08STrent Jaeger if (!ctx) 223d28d1e08STrent Jaeger return -ENOMEM; 224d28d1e08STrent Jaeger 225d28d1e08STrent Jaeger ctx->ctx_doi = uctx->ctx_doi; 22657002bfbSStephen Rothwell ctx->ctx_len = str_len; 227d28d1e08STrent Jaeger ctx->ctx_alg = uctx->ctx_alg; 228d28d1e08STrent Jaeger 229d28d1e08STrent Jaeger memcpy(ctx->ctx_str, 230d28d1e08STrent Jaeger uctx+1, 23157002bfbSStephen Rothwell str_len); 23257002bfbSStephen Rothwell ctx->ctx_str[str_len] = 0; 233d28d1e08STrent Jaeger rc = security_context_to_sid(ctx->ctx_str, 23457002bfbSStephen Rothwell str_len, 235d28d1e08STrent Jaeger &ctx->ctx_sid); 236d28d1e08STrent Jaeger 237d28d1e08STrent Jaeger if (rc) 238d28d1e08STrent Jaeger goto out; 239d28d1e08STrent Jaeger 240d28d1e08STrent Jaeger /* 241c8c05a8eSCatherine Zhang * Does the subject have permission to set security context? 242d28d1e08STrent Jaeger */ 243d28d1e08STrent Jaeger rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 244d28d1e08STrent Jaeger SECCLASS_ASSOCIATION, 2455f8ac64bSTrent Jaeger ASSOCIATION__SETCONTEXT, NULL); 246d28d1e08STrent Jaeger if (rc) 247d28d1e08STrent Jaeger goto out; 248d28d1e08STrent Jaeger 249d28d1e08STrent Jaeger return rc; 250d28d1e08STrent Jaeger 251cb969f07SVenkat Yekkirala not_from_user: 252c1a856c9SVenkat Yekkirala rc = security_sid_to_context(sid, &ctx_str, &str_len); 253e0d1caa7SVenkat Yekkirala if (rc) 254e0d1caa7SVenkat Yekkirala goto out; 255e0d1caa7SVenkat Yekkirala 256e0d1caa7SVenkat Yekkirala *ctxp = ctx = kmalloc(sizeof(*ctx) + 257e0d1caa7SVenkat Yekkirala str_len, 258e0d1caa7SVenkat Yekkirala GFP_ATOMIC); 259e0d1caa7SVenkat Yekkirala 260e0d1caa7SVenkat Yekkirala if (!ctx) { 261e0d1caa7SVenkat Yekkirala rc = -ENOMEM; 262e0d1caa7SVenkat Yekkirala goto out; 263e0d1caa7SVenkat Yekkirala } 264e0d1caa7SVenkat Yekkirala 265e0d1caa7SVenkat Yekkirala ctx->ctx_doi = XFRM_SC_DOI_LSM; 266e0d1caa7SVenkat Yekkirala ctx->ctx_alg = XFRM_SC_ALG_SELINUX; 267c1a856c9SVenkat Yekkirala ctx->ctx_sid = sid; 268e0d1caa7SVenkat Yekkirala ctx->ctx_len = str_len; 269e0d1caa7SVenkat Yekkirala memcpy(ctx->ctx_str, 270e0d1caa7SVenkat Yekkirala ctx_str, 271e0d1caa7SVenkat Yekkirala str_len); 272e0d1caa7SVenkat Yekkirala 273e0d1caa7SVenkat Yekkirala goto out2; 274e0d1caa7SVenkat Yekkirala 275d28d1e08STrent Jaeger out: 276ee2e6841SLuiz Capitulino *ctxp = NULL; 277d28d1e08STrent Jaeger kfree(ctx); 278e0d1caa7SVenkat Yekkirala out2: 279e0d1caa7SVenkat Yekkirala kfree(ctx_str); 280d28d1e08STrent Jaeger return rc; 281d28d1e08STrent Jaeger } 282d28d1e08STrent Jaeger 283d28d1e08STrent Jaeger /* 284d28d1e08STrent Jaeger * LSM hook implementation that allocs and transfers uctx spec to 285d28d1e08STrent Jaeger * xfrm_policy. 286d28d1e08STrent Jaeger */ 28703e1ad7bSPaul Moore int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, 288c1a856c9SVenkat Yekkirala struct xfrm_user_sec_ctx *uctx) 289d28d1e08STrent Jaeger { 290d28d1e08STrent Jaeger int err; 291d28d1e08STrent Jaeger 292c1a856c9SVenkat Yekkirala BUG_ON(!uctx); 293d28d1e08STrent Jaeger 29403e1ad7bSPaul Moore err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0); 295d621d35eSPaul Moore if (err == 0) 296d621d35eSPaul Moore atomic_inc(&selinux_xfrm_refcount); 297d621d35eSPaul Moore 298d28d1e08STrent Jaeger return err; 299d28d1e08STrent Jaeger } 300d28d1e08STrent Jaeger 301d28d1e08STrent Jaeger 302d28d1e08STrent Jaeger /* 303d28d1e08STrent Jaeger * LSM hook implementation that copies security data structure from old to 304d28d1e08STrent Jaeger * new for policy cloning. 305d28d1e08STrent Jaeger */ 30603e1ad7bSPaul Moore int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, 30703e1ad7bSPaul Moore struct xfrm_sec_ctx **new_ctxp) 308d28d1e08STrent Jaeger { 30903e1ad7bSPaul Moore struct xfrm_sec_ctx *new_ctx; 310d28d1e08STrent Jaeger 311d28d1e08STrent Jaeger if (old_ctx) { 31203e1ad7bSPaul Moore new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len, 313d28d1e08STrent Jaeger GFP_KERNEL); 314d28d1e08STrent Jaeger if (!new_ctx) 315d28d1e08STrent Jaeger return -ENOMEM; 316d28d1e08STrent Jaeger 317d28d1e08STrent Jaeger memcpy(new_ctx, old_ctx, sizeof(*new_ctx)); 318d28d1e08STrent Jaeger memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len); 31903e1ad7bSPaul Moore *new_ctxp = new_ctx; 320d28d1e08STrent Jaeger } 321d28d1e08STrent Jaeger return 0; 322d28d1e08STrent Jaeger } 323d28d1e08STrent Jaeger 324d28d1e08STrent Jaeger /* 32503e1ad7bSPaul Moore * LSM hook implementation that frees xfrm_sec_ctx security information. 326d28d1e08STrent Jaeger */ 32703e1ad7bSPaul Moore void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) 328d28d1e08STrent Jaeger { 329d28d1e08STrent Jaeger kfree(ctx); 330d28d1e08STrent Jaeger } 331d28d1e08STrent Jaeger 332d28d1e08STrent Jaeger /* 333c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled policies. 334c8c05a8eSCatherine Zhang */ 33503e1ad7bSPaul Moore int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) 336c8c05a8eSCatherine Zhang { 33786a264abSDavid Howells const struct task_security_struct *tsec = current_security(); 338c8c05a8eSCatherine Zhang int rc = 0; 339c8c05a8eSCatherine Zhang 340d621d35eSPaul Moore if (ctx) { 341c8c05a8eSCatherine Zhang rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 342c8c05a8eSCatherine Zhang SECCLASS_ASSOCIATION, 343c8c05a8eSCatherine Zhang ASSOCIATION__SETCONTEXT, NULL); 344d621d35eSPaul Moore if (rc == 0) 345d621d35eSPaul Moore atomic_dec(&selinux_xfrm_refcount); 346d621d35eSPaul Moore } 347c8c05a8eSCatherine Zhang 348c8c05a8eSCatherine Zhang return rc; 349c8c05a8eSCatherine Zhang } 350c8c05a8eSCatherine Zhang 351c8c05a8eSCatherine Zhang /* 352d28d1e08STrent Jaeger * LSM hook implementation that allocs and transfers sec_ctx spec to 353d28d1e08STrent Jaeger * xfrm_state. 354d28d1e08STrent Jaeger */ 355e0d1caa7SVenkat Yekkirala int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, 356c1a856c9SVenkat Yekkirala u32 secid) 357d28d1e08STrent Jaeger { 358d28d1e08STrent Jaeger int err; 359d28d1e08STrent Jaeger 360d28d1e08STrent Jaeger BUG_ON(!x); 361d28d1e08STrent Jaeger 362c1a856c9SVenkat Yekkirala err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); 363d621d35eSPaul Moore if (err == 0) 364d621d35eSPaul Moore atomic_inc(&selinux_xfrm_refcount); 365d28d1e08STrent Jaeger return err; 366d28d1e08STrent Jaeger } 367d28d1e08STrent Jaeger 368d28d1e08STrent Jaeger /* 369d28d1e08STrent Jaeger * LSM hook implementation that frees xfrm_state security information. 370d28d1e08STrent Jaeger */ 371d28d1e08STrent Jaeger void selinux_xfrm_state_free(struct xfrm_state *x) 372d28d1e08STrent Jaeger { 373d28d1e08STrent Jaeger struct xfrm_sec_ctx *ctx = x->security; 374d28d1e08STrent Jaeger kfree(ctx); 375d28d1e08STrent Jaeger } 376d28d1e08STrent Jaeger 3772c7946a7SCatherine Zhang /* 378c8c05a8eSCatherine Zhang * LSM hook implementation that authorizes deletion of labeled SAs. 379c8c05a8eSCatherine Zhang */ 380c8c05a8eSCatherine Zhang int selinux_xfrm_state_delete(struct xfrm_state *x) 381c8c05a8eSCatherine Zhang { 38286a264abSDavid Howells const struct task_security_struct *tsec = current_security(); 383c8c05a8eSCatherine Zhang struct xfrm_sec_ctx *ctx = x->security; 384c8c05a8eSCatherine Zhang int rc = 0; 385c8c05a8eSCatherine Zhang 386d621d35eSPaul Moore if (ctx) { 387c8c05a8eSCatherine Zhang rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 388c8c05a8eSCatherine Zhang SECCLASS_ASSOCIATION, 389c8c05a8eSCatherine Zhang ASSOCIATION__SETCONTEXT, NULL); 390d621d35eSPaul Moore if (rc == 0) 391d621d35eSPaul Moore atomic_dec(&selinux_xfrm_refcount); 392d621d35eSPaul Moore } 393c8c05a8eSCatherine Zhang 394c8c05a8eSCatherine Zhang return rc; 395c8c05a8eSCatherine Zhang } 396c8c05a8eSCatherine Zhang 397c8c05a8eSCatherine Zhang /* 398d28d1e08STrent Jaeger * LSM hook that controls access to unlabelled packets. If 399d28d1e08STrent Jaeger * a xfrm_state is authorizable (defined by macro) then it was 400d28d1e08STrent Jaeger * already authorized by the IPSec process. If not, then 401d28d1e08STrent Jaeger * we need to check for unlabelled access since this may not have 402d28d1e08STrent Jaeger * gone thru the IPSec process. 403d28d1e08STrent Jaeger */ 404e0d1caa7SVenkat Yekkirala int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, 4052bf49690SThomas Liu struct common_audit_data *ad) 406d28d1e08STrent Jaeger { 407d28d1e08STrent Jaeger int i, rc = 0; 408d28d1e08STrent Jaeger struct sec_path *sp; 409e0d1caa7SVenkat Yekkirala u32 sel_sid = SECINITSID_UNLABELED; 410d28d1e08STrent Jaeger 411d28d1e08STrent Jaeger sp = skb->sp; 412d28d1e08STrent Jaeger 413d28d1e08STrent Jaeger if (sp) { 414d28d1e08STrent Jaeger for (i = 0; i < sp->len; i++) { 41567644726SDave Jones struct xfrm_state *x = sp->xvec[i]; 416d28d1e08STrent Jaeger 417e0d1caa7SVenkat Yekkirala if (x && selinux_authorizable_xfrm(x)) { 418e0d1caa7SVenkat Yekkirala struct xfrm_sec_ctx *ctx = x->security; 419e0d1caa7SVenkat Yekkirala sel_sid = ctx->ctx_sid; 420e0d1caa7SVenkat Yekkirala break; 421e0d1caa7SVenkat Yekkirala } 422d28d1e08STrent Jaeger } 423d28d1e08STrent Jaeger } 424d28d1e08STrent Jaeger 42567f83cbfSVenkat Yekkirala /* 42667f83cbfSVenkat Yekkirala * This check even when there's no association involved is 42767f83cbfSVenkat Yekkirala * intended, according to Trent Jaeger, to make sure a 42867f83cbfSVenkat Yekkirala * process can't engage in non-ipsec communication unless 42967f83cbfSVenkat Yekkirala * explicitly allowed by policy. 43067f83cbfSVenkat Yekkirala */ 43167f83cbfSVenkat Yekkirala 432e0d1caa7SVenkat Yekkirala rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION, 433e0d1caa7SVenkat Yekkirala ASSOCIATION__RECVFROM, ad); 434d28d1e08STrent Jaeger 435d28d1e08STrent Jaeger return rc; 436d28d1e08STrent Jaeger } 437d28d1e08STrent Jaeger 438d28d1e08STrent Jaeger /* 439d28d1e08STrent Jaeger * POSTROUTE_LAST hook's XFRM processing: 440d28d1e08STrent Jaeger * If we have no security association, then we need to determine 441d28d1e08STrent Jaeger * whether the socket is allowed to send to an unlabelled destination. 442d28d1e08STrent Jaeger * If we do have a authorizable security association, then it has already been 44367f83cbfSVenkat Yekkirala * checked in the selinux_xfrm_state_pol_flow_match hook above. 444d28d1e08STrent Jaeger */ 445e0d1caa7SVenkat Yekkirala int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, 4462bf49690SThomas Liu struct common_audit_data *ad, u8 proto) 447d28d1e08STrent Jaeger { 448d28d1e08STrent Jaeger struct dst_entry *dst; 449d28d1e08STrent Jaeger int rc = 0; 450d28d1e08STrent Jaeger 451adf30907SEric Dumazet dst = skb_dst(skb); 452d28d1e08STrent Jaeger 453d28d1e08STrent Jaeger if (dst) { 454d28d1e08STrent Jaeger struct dst_entry *dst_test; 455d28d1e08STrent Jaeger 456c80544dcSStephen Hemminger for (dst_test = dst; dst_test != NULL; 457d28d1e08STrent Jaeger dst_test = dst_test->child) { 458d28d1e08STrent Jaeger struct xfrm_state *x = dst_test->xfrm; 459d28d1e08STrent Jaeger 460d28d1e08STrent Jaeger if (x && selinux_authorizable_xfrm(x)) 4614e5ab4cbSJames Morris goto out; 462d28d1e08STrent Jaeger } 463d28d1e08STrent Jaeger } 464d28d1e08STrent Jaeger 46567f83cbfSVenkat Yekkirala switch (proto) { 46667f83cbfSVenkat Yekkirala case IPPROTO_AH: 46767f83cbfSVenkat Yekkirala case IPPROTO_ESP: 46867f83cbfSVenkat Yekkirala case IPPROTO_COMP: 46967f83cbfSVenkat Yekkirala /* 47067f83cbfSVenkat Yekkirala * We should have already seen this packet once before 47167f83cbfSVenkat Yekkirala * it underwent xfrm(s). No need to subject it to the 47267f83cbfSVenkat Yekkirala * unlabeled check. 47367f83cbfSVenkat Yekkirala */ 47467f83cbfSVenkat Yekkirala goto out; 47567f83cbfSVenkat Yekkirala default: 47667f83cbfSVenkat Yekkirala break; 47767f83cbfSVenkat Yekkirala } 47867f83cbfSVenkat Yekkirala 47967f83cbfSVenkat Yekkirala /* 48067f83cbfSVenkat Yekkirala * This check even when there's no association involved is 48167f83cbfSVenkat Yekkirala * intended, according to Trent Jaeger, to make sure a 48267f83cbfSVenkat Yekkirala * process can't engage in non-ipsec communication unless 48367f83cbfSVenkat Yekkirala * explicitly allowed by policy. 48467f83cbfSVenkat Yekkirala */ 48567f83cbfSVenkat Yekkirala 486d28d1e08STrent Jaeger rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, 487e0d1caa7SVenkat Yekkirala ASSOCIATION__SENDTO, ad); 4884e5ab4cbSJames Morris out: 4894e5ab4cbSJames Morris return rc; 490d28d1e08STrent Jaeger } 491