diff options
Diffstat (limited to 'security/selinux/xfrm.c')
-rw-r--r-- | security/selinux/xfrm.c | 199 |
1 files changed, 90 insertions, 109 deletions
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 | /* |