Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lsm: split the xfrm_state_alloc_security() hook implementation

The xfrm_state_alloc_security() LSM hook implementation is really a
multiplexed hook with two different behaviors depending on the
arguments passed to it by the caller. This patch splits the LSM hook
implementation into two new hook implementations, which match the
LSM hooks in the rest of the kernel:

* xfrm_state_alloc
* xfrm_state_alloc_acquire

Also included in this patch are the necessary changes to the SELinux
code; no other LSMs are affected.

Signed-off-by: Paul Moore <pmoore@redhat.com>
Signed-off-by: Eric Paris <eparis@redhat.com>

authored by

Paul Moore and committed by
Eric Paris
2e5aa866 8bb495e3

+128 -132
+18 -8
include/linux/security.h
··· 1039 1039 * @xfrm_policy_delete_security: 1040 1040 * @ctx contains the xfrm_sec_ctx. 1041 1041 * Authorize deletion of xp->security. 1042 - * @xfrm_state_alloc_security: 1042 + * @xfrm_state_alloc: 1043 1043 * @x contains the xfrm_state being added to the Security Association 1044 1044 * Database by the XFRM system. 1045 1045 * @sec_ctx contains the security context information being provided by 1046 1046 * the user-level SA generation program (e.g., setkey or racoon). 1047 - * @secid contains the secid from which to take the mls portion of the context. 1048 1047 * Allocate a security structure to the x->security field; the security 1049 1048 * field is initialized to NULL when the xfrm_state is allocated. Set the 1050 - * context to correspond to either sec_ctx or polsec, with the mls portion 1051 - * taken from secid in the latter case. 1052 - * Return 0 if operation was successful (memory to allocate, legal context). 1049 + * context to correspond to sec_ctx. Return 0 if operation was successful 1050 + * (memory to allocate, legal context). 1051 + * @xfrm_state_alloc_acquire: 1052 + * @x contains the xfrm_state being added to the Security Association 1053 + * Database by the XFRM system. 1054 + * @polsec contains the policy's security context. 1055 + * @secid contains the secid from which to take the mls portion of the 1056 + * context. 1057 + * Allocate a security structure to the x->security field; the security 1058 + * field is initialized to NULL when the xfrm_state is allocated. Set the 1059 + * context to correspond to secid. Return 0 if operation was successful 1060 + * (memory to allocate, legal context). 1053 1061 * @xfrm_state_free_security: 1054 1062 * @x contains the xfrm_state. 1055 1063 * Deallocate x->security. ··· 1659 1651 int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx); 1660 1652 void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx); 1661 1653 int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx); 1662 - int (*xfrm_state_alloc_security) (struct xfrm_state *x, 1663 - struct xfrm_user_sec_ctx *sec_ctx, 1664 - u32 secid); 1654 + int (*xfrm_state_alloc) (struct xfrm_state *x, 1655 + struct xfrm_user_sec_ctx *sec_ctx); 1656 + int (*xfrm_state_alloc_acquire) (struct xfrm_state *x, 1657 + struct xfrm_sec_ctx *polsec, 1658 + u32 secid); 1665 1659 void (*xfrm_state_free_security) (struct xfrm_state *x); 1666 1660 int (*xfrm_state_delete_security) (struct xfrm_state *x); 1667 1661 int (*xfrm_policy_lookup) (struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
+11 -4
security/capability.c
··· 767 767 return 0; 768 768 } 769 769 770 - static int cap_xfrm_state_alloc_security(struct xfrm_state *x, 771 - struct xfrm_user_sec_ctx *sec_ctx, 772 - u32 secid) 770 + static int cap_xfrm_state_alloc(struct xfrm_state *x, 771 + struct xfrm_user_sec_ctx *sec_ctx) 772 + { 773 + return 0; 774 + } 775 + 776 + static int cap_xfrm_state_alloc_acquire(struct xfrm_state *x, 777 + struct xfrm_sec_ctx *polsec, 778 + u32 secid) 773 779 { 774 780 return 0; 775 781 } ··· 1090 1084 set_to_cap_if_null(ops, xfrm_policy_clone_security); 1091 1085 set_to_cap_if_null(ops, xfrm_policy_free_security); 1092 1086 set_to_cap_if_null(ops, xfrm_policy_delete_security); 1093 - set_to_cap_if_null(ops, xfrm_state_alloc_security); 1087 + set_to_cap_if_null(ops, xfrm_state_alloc); 1088 + set_to_cap_if_null(ops, xfrm_state_alloc_acquire); 1094 1089 set_to_cap_if_null(ops, xfrm_state_free_security); 1095 1090 set_to_cap_if_null(ops, xfrm_state_delete_security); 1096 1091 set_to_cap_if_null(ops, xfrm_policy_lookup);
+4 -9
security/security.c
··· 1322 1322 return security_ops->xfrm_policy_delete_security(ctx); 1323 1323 } 1324 1324 1325 - int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) 1325 + int security_xfrm_state_alloc(struct xfrm_state *x, 1326 + struct xfrm_user_sec_ctx *sec_ctx) 1326 1327 { 1327 - return security_ops->xfrm_state_alloc_security(x, sec_ctx, 0); 1328 + return security_ops->xfrm_state_alloc(x, sec_ctx); 1328 1329 } 1329 1330 EXPORT_SYMBOL(security_xfrm_state_alloc); 1330 1331 1331 1332 int security_xfrm_state_alloc_acquire(struct xfrm_state *x, 1332 1333 struct xfrm_sec_ctx *polsec, u32 secid) 1333 1334 { 1334 - if (!polsec) 1335 - return 0; 1336 - /* 1337 - * We want the context to be taken from secid which is usually 1338 - * from the sock. 1339 - */ 1340 - return security_ops->xfrm_state_alloc_security(x, NULL, secid); 1335 + return security_ops->xfrm_state_alloc_acquire(x, polsec, secid); 1341 1336 } 1342 1337 1343 1338 int security_xfrm_state_delete(struct xfrm_state *x)
+2 -1
security/selinux/hooks.c
··· 5708 5708 .xfrm_policy_clone_security = selinux_xfrm_policy_clone, 5709 5709 .xfrm_policy_free_security = selinux_xfrm_policy_free, 5710 5710 .xfrm_policy_delete_security = selinux_xfrm_policy_delete, 5711 - .xfrm_state_alloc_security = selinux_xfrm_state_alloc, 5711 + .xfrm_state_alloc = selinux_xfrm_state_alloc, 5712 + .xfrm_state_alloc_acquire = selinux_xfrm_state_alloc_acquire, 5712 5713 .xfrm_state_free_security = selinux_xfrm_state_free, 5713 5714 .xfrm_state_delete_security = selinux_xfrm_state_delete, 5714 5715 .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
+3 -1
security/selinux/include/xfrm.h
··· 16 16 void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); 17 17 int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); 18 18 int selinux_xfrm_state_alloc(struct xfrm_state *x, 19 - struct xfrm_user_sec_ctx *sec_ctx, u32 secid); 19 + struct xfrm_user_sec_ctx *uctx); 20 + int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, 21 + struct xfrm_sec_ctx *polsec, u32 secid); 20 22 void selinux_xfrm_state_free(struct xfrm_state *x); 21 23 int selinux_xfrm_state_delete(struct xfrm_state *x); 22 24 int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
+90 -109
security/selinux/xfrm.c
··· 74 74 } 75 75 76 76 /* 77 + * Allocates a xfrm_sec_state and populates it using the supplied security 78 + * xfrm_user_sec_ctx context. 79 + */ 80 + static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, 81 + struct xfrm_user_sec_ctx *uctx) 82 + { 83 + int rc; 84 + const struct task_security_struct *tsec = current_security(); 85 + struct xfrm_sec_ctx *ctx = NULL; 86 + u32 str_len; 87 + 88 + if (ctxp == NULL || uctx == NULL || 89 + uctx->ctx_doi != XFRM_SC_DOI_LSM || 90 + uctx->ctx_alg != XFRM_SC_ALG_SELINUX) 91 + return -EINVAL; 92 + 93 + str_len = uctx->ctx_len; 94 + if (str_len >= PAGE_SIZE) 95 + return -ENOMEM; 96 + 97 + ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL); 98 + if (!ctx) 99 + return -ENOMEM; 100 + 101 + ctx->ctx_doi = XFRM_SC_DOI_LSM; 102 + ctx->ctx_alg = XFRM_SC_ALG_SELINUX; 103 + ctx->ctx_len = str_len; 104 + memcpy(ctx->ctx_str, &uctx[1], str_len); 105 + ctx->ctx_str[str_len] = '\0'; 106 + rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid); 107 + if (rc) 108 + goto err; 109 + 110 + rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 111 + SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL); 112 + if (rc) 113 + goto err; 114 + 115 + *ctxp = ctx; 116 + atomic_inc(&selinux_xfrm_refcount); 117 + return 0; 118 + 119 + err: 120 + kfree(ctx); 121 + return rc; 122 + } 123 + 124 + /* 77 125 * LSM hook implementation that authorizes that a flow can use 78 126 * a xfrm policy rule. 79 127 */ ··· 239 191 } 240 192 241 193 /* 242 - * Security blob allocation for xfrm_policy and xfrm_state 243 - * CTX does not have a meaningful value on input 244 - */ 245 - static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, 246 - struct xfrm_user_sec_ctx *uctx, u32 sid) 247 - { 248 - int rc = 0; 249 - const struct task_security_struct *tsec = current_security(); 250 - struct xfrm_sec_ctx *ctx = NULL; 251 - char *ctx_str = NULL; 252 - u32 str_len; 253 - 254 - BUG_ON(uctx && sid); 255 - 256 - if (!uctx) 257 - goto not_from_user; 258 - 259 - if (uctx->ctx_alg != XFRM_SC_ALG_SELINUX) 260 - return -EINVAL; 261 - 262 - str_len = uctx->ctx_len; 263 - if (str_len >= PAGE_SIZE) 264 - return -ENOMEM; 265 - 266 - *ctxp = ctx = kmalloc(sizeof(*ctx) + 267 - str_len + 1, 268 - GFP_KERNEL); 269 - 270 - if (!ctx) 271 - return -ENOMEM; 272 - 273 - ctx->ctx_doi = uctx->ctx_doi; 274 - ctx->ctx_len = str_len; 275 - ctx->ctx_alg = uctx->ctx_alg; 276 - 277 - memcpy(ctx->ctx_str, 278 - uctx+1, 279 - str_len); 280 - ctx->ctx_str[str_len] = 0; 281 - rc = security_context_to_sid(ctx->ctx_str, 282 - str_len, 283 - &ctx->ctx_sid); 284 - 285 - if (rc) 286 - goto out; 287 - 288 - /* 289 - * Does the subject have permission to set security context? 290 - */ 291 - rc = avc_has_perm(tsec->sid, ctx->ctx_sid, 292 - SECCLASS_ASSOCIATION, 293 - ASSOCIATION__SETCONTEXT, NULL); 294 - if (rc) 295 - goto out; 296 - 297 - return rc; 298 - 299 - not_from_user: 300 - rc = security_sid_to_context(sid, &ctx_str, &str_len); 301 - if (rc) 302 - goto out; 303 - 304 - *ctxp = ctx = kmalloc(sizeof(*ctx) + 305 - str_len, 306 - GFP_ATOMIC); 307 - 308 - if (!ctx) { 309 - rc = -ENOMEM; 310 - goto out; 311 - } 312 - 313 - ctx->ctx_doi = XFRM_SC_DOI_LSM; 314 - ctx->ctx_alg = XFRM_SC_ALG_SELINUX; 315 - ctx->ctx_sid = sid; 316 - ctx->ctx_len = str_len; 317 - memcpy(ctx->ctx_str, 318 - ctx_str, 319 - str_len); 320 - 321 - goto out2; 322 - 323 - out: 324 - *ctxp = NULL; 325 - kfree(ctx); 326 - out2: 327 - kfree(ctx_str); 328 - return rc; 329 - } 330 - 331 - /* 332 194 * LSM hook implementation that allocs and transfers uctx spec to 333 195 * xfrm_policy. 334 196 */ 335 197 int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, 336 198 struct xfrm_user_sec_ctx *uctx) 337 199 { 338 - int err; 339 - 340 - BUG_ON(!uctx); 341 - 342 - err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0); 343 - if (err == 0) 344 - atomic_inc(&selinux_xfrm_refcount); 345 - 346 - return err; 200 + return selinux_xfrm_alloc_user(ctxp, uctx); 347 201 } 348 202 349 203 ··· 297 347 } 298 348 299 349 /* 300 - * LSM hook implementation that allocs and transfers sec_ctx spec to 301 - * xfrm_state. 350 + * LSM hook implementation that allocates a xfrm_sec_state, populates it using 351 + * the supplied security context, and assigns it to the xfrm_state. 302 352 */ 303 - int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, 304 - u32 secid) 353 + int selinux_xfrm_state_alloc(struct xfrm_state *x, 354 + struct xfrm_user_sec_ctx *uctx) 305 355 { 306 - int err; 356 + return selinux_xfrm_alloc_user(&x->security, uctx); 357 + } 307 358 308 - BUG_ON(!x); 359 + /* 360 + * LSM hook implementation that allocates a xfrm_sec_state and populates based 361 + * on a secid. 362 + */ 363 + int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, 364 + struct xfrm_sec_ctx *polsec, u32 secid) 365 + { 366 + int rc; 367 + struct xfrm_sec_ctx *ctx; 368 + char *ctx_str = NULL; 369 + int str_len; 309 370 310 - err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); 311 - if (err == 0) 312 - atomic_inc(&selinux_xfrm_refcount); 313 - return err; 371 + if (!polsec) 372 + return 0; 373 + 374 + if (secid == 0) 375 + return -EINVAL; 376 + 377 + rc = security_sid_to_context(secid, &ctx_str, &str_len); 378 + if (rc) 379 + return rc; 380 + 381 + ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC); 382 + if (!ctx) 383 + return -ENOMEM; 384 + 385 + ctx->ctx_doi = XFRM_SC_DOI_LSM; 386 + ctx->ctx_alg = XFRM_SC_ALG_SELINUX; 387 + ctx->ctx_sid = secid; 388 + ctx->ctx_len = str_len; 389 + memcpy(ctx->ctx_str, ctx_str, str_len); 390 + kfree(ctx_str); 391 + 392 + x->security = ctx; 393 + atomic_inc(&selinux_xfrm_refcount); 394 + return 0; 314 395 } 315 396 316 397 /*