diff options
-rw-r--r-- | include/linux/security.h | 26 | ||||
-rw-r--r-- | security/capability.c | 15 | ||||
-rw-r--r-- | security/security.c | 13 | ||||
-rw-r--r-- | security/selinux/hooks.c | 3 | ||||
-rw-r--r-- | security/selinux/include/xfrm.h | 4 | ||||
-rw-r--r-- | security/selinux/xfrm.c | 199 |
6 files changed, 128 insertions, 132 deletions
diff --git a/include/linux/security.h b/include/linux/security.h index 4686491852a7..e5a5e8a41e55 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
@@ -1039,17 +1039,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
1039 | * @xfrm_policy_delete_security: | 1039 | * @xfrm_policy_delete_security: |
1040 | * @ctx contains the xfrm_sec_ctx. | 1040 | * @ctx contains the xfrm_sec_ctx. |
1041 | * Authorize deletion of xp->security. | 1041 | * Authorize deletion of xp->security. |
1042 | * @xfrm_state_alloc_security: | 1042 | * @xfrm_state_alloc: |
1043 | * @x contains the xfrm_state being added to the Security Association | 1043 | * @x contains the xfrm_state being added to the Security Association |
1044 | * Database by the XFRM system. | 1044 | * Database by the XFRM system. |
1045 | * @sec_ctx contains the security context information being provided by | 1045 | * @sec_ctx contains the security context information being provided by |
1046 | * the user-level SA generation program (e.g., setkey or racoon). | 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 | * Allocate a security structure to the x->security field; the security | 1047 | * Allocate a security structure to the x->security field; the security |
1049 | * field is initialized to NULL when the xfrm_state is allocated. Set the | 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 | 1049 | * context to correspond to sec_ctx. Return 0 if operation was successful |
1051 | * taken from secid in the latter case. | 1050 | * (memory to allocate, legal context). |
1052 | * Return 0 if operation was successful (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 | * @xfrm_state_free_security: | 1061 | * @xfrm_state_free_security: |
1054 | * @x contains the xfrm_state. | 1062 | * @x contains the xfrm_state. |
1055 | * Deallocate x->security. | 1063 | * Deallocate x->security. |
@@ -1651,9 +1659,11 @@ struct security_operations { | |||
1651 | int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx); | 1659 | int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx); |
1652 | void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx); | 1660 | void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx); |
1653 | int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx); | 1661 | int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx); |
1654 | int (*xfrm_state_alloc_security) (struct xfrm_state *x, | 1662 | int (*xfrm_state_alloc) (struct xfrm_state *x, |
1655 | struct xfrm_user_sec_ctx *sec_ctx, | 1663 | struct xfrm_user_sec_ctx *sec_ctx); |
1656 | u32 secid); | 1664 | int (*xfrm_state_alloc_acquire) (struct xfrm_state *x, |
1665 | struct xfrm_sec_ctx *polsec, | ||
1666 | u32 secid); | ||
1657 | void (*xfrm_state_free_security) (struct xfrm_state *x); | 1667 | void (*xfrm_state_free_security) (struct xfrm_state *x); |
1658 | int (*xfrm_state_delete_security) (struct xfrm_state *x); | 1668 | int (*xfrm_state_delete_security) (struct xfrm_state *x); |
1659 | int (*xfrm_policy_lookup) (struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); | 1669 | int (*xfrm_policy_lookup) (struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); |
diff --git a/security/capability.c b/security/capability.c index 1728d4e375db..67afc679719a 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -767,9 +767,15 @@ static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx) | |||
767 | return 0; | 767 | return 0; |
768 | } | 768 | } |
769 | 769 | ||
770 | static int cap_xfrm_state_alloc_security(struct xfrm_state *x, | 770 | static int cap_xfrm_state_alloc(struct xfrm_state *x, |
771 | struct xfrm_user_sec_ctx *sec_ctx, | 771 | struct xfrm_user_sec_ctx *sec_ctx) |
772 | u32 secid) | 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 | return 0; | 780 | return 0; |
775 | } | 781 | } |
@@ -1084,7 +1090,8 @@ void __init security_fixup_ops(struct security_operations *ops) | |||
1084 | set_to_cap_if_null(ops, xfrm_policy_clone_security); | 1090 | set_to_cap_if_null(ops, xfrm_policy_clone_security); |
1085 | set_to_cap_if_null(ops, xfrm_policy_free_security); | 1091 | set_to_cap_if_null(ops, xfrm_policy_free_security); |
1086 | set_to_cap_if_null(ops, xfrm_policy_delete_security); | 1092 | set_to_cap_if_null(ops, xfrm_policy_delete_security); |
1087 | set_to_cap_if_null(ops, xfrm_state_alloc_security); | 1093 | set_to_cap_if_null(ops, xfrm_state_alloc); |
1094 | set_to_cap_if_null(ops, xfrm_state_alloc_acquire); | ||
1088 | set_to_cap_if_null(ops, xfrm_state_free_security); | 1095 | set_to_cap_if_null(ops, xfrm_state_free_security); |
1089 | set_to_cap_if_null(ops, xfrm_state_delete_security); | 1096 | set_to_cap_if_null(ops, xfrm_state_delete_security); |
1090 | set_to_cap_if_null(ops, xfrm_policy_lookup); | 1097 | set_to_cap_if_null(ops, xfrm_policy_lookup); |
diff --git a/security/security.c b/security/security.c index a3dce87d1aef..57e25c962968 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -1322,22 +1322,17 @@ int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) | |||
1322 | return security_ops->xfrm_policy_delete_security(ctx); | 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 | EXPORT_SYMBOL(security_xfrm_state_alloc); | 1330 | EXPORT_SYMBOL(security_xfrm_state_alloc); |
1330 | 1331 | ||
1331 | int security_xfrm_state_alloc_acquire(struct xfrm_state *x, | 1332 | int security_xfrm_state_alloc_acquire(struct xfrm_state *x, |
1332 | struct xfrm_sec_ctx *polsec, u32 secid) | 1333 | struct xfrm_sec_ctx *polsec, u32 secid) |
1333 | { | 1334 | { |
1334 | if (!polsec) | 1335 | return security_ops->xfrm_state_alloc_acquire(x, polsec, secid); |
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); | ||
1341 | } | 1336 | } |
1342 | 1337 | ||
1343 | int security_xfrm_state_delete(struct xfrm_state *x) | 1338 | int security_xfrm_state_delete(struct xfrm_state *x) |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 5c6f2cd2d095..d3555bdf66af 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -5708,7 +5708,8 @@ static struct security_operations selinux_ops = { | |||
5708 | .xfrm_policy_clone_security = selinux_xfrm_policy_clone, | 5708 | .xfrm_policy_clone_security = selinux_xfrm_policy_clone, |
5709 | .xfrm_policy_free_security = selinux_xfrm_policy_free, | 5709 | .xfrm_policy_free_security = selinux_xfrm_policy_free, |
5710 | .xfrm_policy_delete_security = selinux_xfrm_policy_delete, | 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 | .xfrm_state_free_security = selinux_xfrm_state_free, | 5713 | .xfrm_state_free_security = selinux_xfrm_state_free, |
5713 | .xfrm_state_delete_security = selinux_xfrm_state_delete, | 5714 | .xfrm_state_delete_security = selinux_xfrm_state_delete, |
5714 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, | 5715 | .xfrm_policy_lookup = selinux_xfrm_policy_lookup, |
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 65f67cb0aefb..f2a2314aac1a 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h | |||
@@ -16,7 +16,9 @@ int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, | |||
16 | void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); | 16 | void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); |
17 | int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); | 17 | int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); |
18 | int selinux_xfrm_state_alloc(struct xfrm_state *x, | 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 | void selinux_xfrm_state_free(struct xfrm_state *x); | 22 | void selinux_xfrm_state_free(struct xfrm_state *x); |
21 | int selinux_xfrm_state_delete(struct xfrm_state *x); | 23 | int selinux_xfrm_state_delete(struct xfrm_state *x); |
22 | int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); | 24 | int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); |
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index d03081886214..07ae0c06dfc3 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c | |||
@@ -74,6 +74,54 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) | |||
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 | * LSM hook implementation that authorizes that a flow can use | 125 | * LSM hook implementation that authorizes that a flow can use |
78 | * a xfrm policy rule. | 126 | * a xfrm policy rule. |
79 | */ | 127 | */ |
@@ -191,111 +239,13 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) | |||
191 | } | 239 | } |
192 | 240 | ||
193 | /* | 241 | /* |
194 | * Security blob allocation for xfrm_policy and xfrm_state | ||
195 | * CTX does not have a meaningful value on input | ||
196 | */ | ||
197 | static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp, | ||
198 | struct xfrm_user_sec_ctx *uctx, u32 sid) | ||
199 | { | ||
200 | int rc = 0; | ||
201 | const struct task_security_struct *tsec = current_security(); | ||
202 | struct xfrm_sec_ctx *ctx = NULL; | ||
203 | char *ctx_str = NULL; | ||
204 | u32 str_len; | ||
205 | |||
206 | BUG_ON(uctx && sid); | ||
207 | |||
208 | if (!uctx) | ||
209 | goto not_from_user; | ||
210 | |||
211 | if (uctx->ctx_alg != XFRM_SC_ALG_SELINUX) | ||
212 | return -EINVAL; | ||
213 | |||
214 | str_len = uctx->ctx_len; | ||
215 | if (str_len >= PAGE_SIZE) | ||
216 | return -ENOMEM; | ||
217 | |||
218 | *ctxp = ctx = kmalloc(sizeof(*ctx) + | ||
219 | str_len + 1, | ||
220 | GFP_KERNEL); | ||
221 | |||
222 | if (!ctx) | ||
223 | return -ENOMEM; | ||
224 | |||
225 | ctx->ctx_doi = uctx->ctx_doi; | ||
226 | ctx->ctx_len = str_len; | ||
227 | ctx->ctx_alg = uctx->ctx_alg; | ||
228 | |||
229 | memcpy(ctx->ctx_str, | ||
230 | uctx+1, | ||
231 | str_len); | ||
232 | ctx->ctx_str[str_len] = 0; | ||
233 | rc = security_context_to_sid(ctx->ctx_str, | ||
234 | str_len, | ||
235 | &ctx->ctx_sid); | ||
236 | |||
237 | if (rc) | ||
238 | goto out; | ||
239 | |||
240 | /* | ||
241 | * Does the subject have permission to set security context? | ||
242 | */ | ||
243 | rc = avc_has_perm(tsec->sid, ctx->ctx_sid, | ||
244 | SECCLASS_ASSOCIATION, | ||
245 | ASSOCIATION__SETCONTEXT, NULL); | ||
246 | if (rc) | ||
247 | goto out; | ||
248 | |||
249 | return rc; | ||
250 | |||
251 | not_from_user: | ||
252 | rc = security_sid_to_context(sid, &ctx_str, &str_len); | ||
253 | if (rc) | ||
254 | goto out; | ||
255 | |||
256 | *ctxp = ctx = kmalloc(sizeof(*ctx) + | ||
257 | str_len, | ||
258 | GFP_ATOMIC); | ||
259 | |||
260 | if (!ctx) { | ||
261 | rc = -ENOMEM; | ||
262 | goto out; | ||
263 | } | ||
264 | |||
265 | ctx->ctx_doi = XFRM_SC_DOI_LSM; | ||
266 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; | ||
267 | ctx->ctx_sid = sid; | ||
268 | ctx->ctx_len = str_len; | ||
269 | memcpy(ctx->ctx_str, | ||
270 | ctx_str, | ||
271 | str_len); | ||
272 | |||
273 | goto out2; | ||
274 | |||
275 | out: | ||
276 | *ctxp = NULL; | ||
277 | kfree(ctx); | ||
278 | out2: | ||
279 | kfree(ctx_str); | ||
280 | return rc; | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * LSM hook implementation that allocs and transfers uctx spec to | 242 | * LSM hook implementation that allocs and transfers uctx spec to |
285 | * xfrm_policy. | 243 | * xfrm_policy. |
286 | */ | 244 | */ |
287 | int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, | 245 | int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, |
288 | struct xfrm_user_sec_ctx *uctx) | 246 | struct xfrm_user_sec_ctx *uctx) |
289 | { | 247 | { |
290 | int err; | 248 | return selinux_xfrm_alloc_user(ctxp, uctx); |
291 | |||
292 | BUG_ON(!uctx); | ||
293 | |||
294 | err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0); | ||
295 | if (err == 0) | ||
296 | atomic_inc(&selinux_xfrm_refcount); | ||
297 | |||
298 | return err; | ||
299 | } | 249 | } |
300 | 250 | ||
301 | 251 | ||
@@ -347,20 +297,51 @@ int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) | |||
347 | } | 297 | } |
348 | 298 | ||
349 | /* | 299 | /* |
350 | * LSM hook implementation that allocs and transfers sec_ctx spec to | 300 | * LSM hook implementation that allocates a xfrm_sec_state, populates it using |
351 | * xfrm_state. | 301 | * the supplied security context, and assigns it to the xfrm_state. |
302 | */ | ||
303 | int selinux_xfrm_state_alloc(struct xfrm_state *x, | ||
304 | struct xfrm_user_sec_ctx *uctx) | ||
305 | { | ||
306 | return selinux_xfrm_alloc_user(&x->security, uctx); | ||
307 | } | ||
308 | |||
309 | /* | ||
310 | * LSM hook implementation that allocates a xfrm_sec_state and populates based | ||
311 | * on a secid. | ||
352 | */ | 312 | */ |
353 | int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx, | 313 | int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, |
354 | u32 secid) | 314 | struct xfrm_sec_ctx *polsec, u32 secid) |
355 | { | 315 | { |
356 | int err; | 316 | int rc; |
317 | struct xfrm_sec_ctx *ctx; | ||
318 | char *ctx_str = NULL; | ||
319 | int str_len; | ||
357 | 320 | ||
358 | BUG_ON(!x); | 321 | if (!polsec) |
322 | return 0; | ||
359 | 323 | ||
360 | err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); | 324 | if (secid == 0) |
361 | if (err == 0) | 325 | return -EINVAL; |
362 | atomic_inc(&selinux_xfrm_refcount); | 326 | |
363 | return err; | 327 | rc = security_sid_to_context(secid, &ctx_str, &str_len); |
328 | if (rc) | ||
329 | return rc; | ||
330 | |||
331 | ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC); | ||
332 | if (!ctx) | ||
333 | return -ENOMEM; | ||
334 | |||
335 | ctx->ctx_doi = XFRM_SC_DOI_LSM; | ||
336 | ctx->ctx_alg = XFRM_SC_ALG_SELINUX; | ||
337 | ctx->ctx_sid = secid; | ||
338 | ctx->ctx_len = str_len; | ||
339 | memcpy(ctx->ctx_str, ctx_str, str_len); | ||
340 | kfree(ctx_str); | ||
341 | |||
342 | x->security = ctx; | ||
343 | atomic_inc(&selinux_xfrm_refcount); | ||
344 | return 0; | ||
364 | } | 345 | } |
365 | 346 | ||
366 | /* | 347 | /* |