Skip to content

Commit 2e5aa86

Browse files
pcmooreeparis
authored andcommitted
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>
1 parent 8bb495e commit 2e5aa86

File tree

6 files changed

+128
-132
lines changed

6 files changed

+128
-132
lines changed

include/linux/security.h

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1039,17 +1039,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
10391039
* @xfrm_policy_delete_security:
10401040
* @ctx contains the xfrm_sec_ctx.
10411041
* Authorize deletion of xp->security.
1042-
* @xfrm_state_alloc_security:
1042+
* @xfrm_state_alloc:
10431043
* @x contains the xfrm_state being added to the Security Association
10441044
* Database by the XFRM system.
10451045
* @sec_ctx contains the security context information being provided by
10461046
* 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.
10481047
* Allocate a security structure to the x->security field; the security
10491048
* 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).
10531061
* @xfrm_state_free_security:
10541062
* @x contains the xfrm_state.
10551063
* Deallocate x->security.
@@ -1651,9 +1659,11 @@ struct security_operations {
16511659
int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx);
16521660
void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx);
16531661
int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx);
1654-
int (*xfrm_state_alloc_security) (struct xfrm_state *x,
1655-
struct xfrm_user_sec_ctx *sec_ctx,
1656-
u32 secid);
1662+
int (*xfrm_state_alloc) (struct xfrm_state *x,
1663+
struct xfrm_user_sec_ctx *sec_ctx);
1664+
int (*xfrm_state_alloc_acquire) (struct xfrm_state *x,
1665+
struct xfrm_sec_ctx *polsec,
1666+
u32 secid);
16571667
void (*xfrm_state_free_security) (struct xfrm_state *x);
16581668
int (*xfrm_state_delete_security) (struct xfrm_state *x);
16591669
int (*xfrm_policy_lookup) (struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);

security/capability.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -767,9 +767,15 @@ static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
767767
return 0;
768768
}
769769

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)
773779
{
774780
return 0;
775781
}
@@ -1084,7 +1090,8 @@ void __init security_fixup_ops(struct security_operations *ops)
10841090
set_to_cap_if_null(ops, xfrm_policy_clone_security);
10851091
set_to_cap_if_null(ops, xfrm_policy_free_security);
10861092
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);
10881095
set_to_cap_if_null(ops, xfrm_state_free_security);
10891096
set_to_cap_if_null(ops, xfrm_state_delete_security);
10901097
set_to_cap_if_null(ops, xfrm_policy_lookup);

security/security.c

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,22 +1322,17 @@ int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
13221322
return security_ops->xfrm_policy_delete_security(ctx);
13231323
}
13241324

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)
13261327
{
1327-
return security_ops->xfrm_state_alloc_security(x, sec_ctx, 0);
1328+
return security_ops->xfrm_state_alloc(x, sec_ctx);
13281329
}
13291330
EXPORT_SYMBOL(security_xfrm_state_alloc);
13301331

13311332
int security_xfrm_state_alloc_acquire(struct xfrm_state *x,
13321333
struct xfrm_sec_ctx *polsec, u32 secid)
13331334
{
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);
13411336
}
13421337

13431338
int security_xfrm_state_delete(struct xfrm_state *x)

security/selinux/hooks.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5708,7 +5708,8 @@ static struct security_operations selinux_ops = {
57085708
.xfrm_policy_clone_security = selinux_xfrm_policy_clone,
57095709
.xfrm_policy_free_security = selinux_xfrm_policy_free,
57105710
.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,
57125713
.xfrm_state_free_security = selinux_xfrm_state_free,
57135714
.xfrm_state_delete_security = selinux_xfrm_state_delete,
57145715
.xfrm_policy_lookup = selinux_xfrm_policy_lookup,

security/selinux/include/xfrm.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
1616
void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
1717
int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx);
1818
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);
2022
void selinux_xfrm_state_free(struct xfrm_state *x);
2123
int selinux_xfrm_state_delete(struct xfrm_state *x);
2224
int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);

security/selinux/xfrm.c

Lines changed: 90 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,54 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
7373
return selinux_authorizable_ctx(x->security);
7474
}
7575

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+
76124
/*
77125
* LSM hook implementation that authorizes that a flow can use
78126
* a xfrm policy rule.
@@ -190,112 +238,14 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
190238
return 0;
191239
}
192240

193-
/*
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-
283241
/*
284242
* LSM hook implementation that allocs and transfers uctx spec to
285243
* xfrm_policy.
286244
*/
287245
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
288246
struct xfrm_user_sec_ctx *uctx)
289247
{
290-
int err;
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;
248+
return selinux_xfrm_alloc_user(ctxp, uctx);
299249
}
300250

301251

@@ -347,20 +297,51 @@ int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
347297
}
348298

349299
/*
350-
* LSM hook implementation that allocs and transfers sec_ctx spec to
351-
* xfrm_state.
300+
* LSM hook implementation that allocates a xfrm_sec_state, populates it using
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.
352312
*/
353-
int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx,
354-
u32 secid)
313+
int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
314+
struct xfrm_sec_ctx *polsec, u32 secid)
355315
{
356-
int err;
316+
int rc;
317+
struct xfrm_sec_ctx *ctx;
318+
char *ctx_str = NULL;
319+
int str_len;
357320

358-
BUG_ON(!x);
321+
if (!polsec)
322+
return 0;
359323

360-
err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid);
361-
if (err == 0)
362-
atomic_inc(&selinux_xfrm_refcount);
363-
return err;
324+
if (secid == 0)
325+
return -EINVAL;
326+
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;
364345
}
365346

366347
/*

0 commit comments

Comments
 (0)