selinux: add gfp argument to security_xfrm_policy_alloc and fix callers

security_xfrm_policy_alloc can be called in atomic context so the
allocation should be done with GFP_ATOMIC. Add an argument to let the
callers choose the appropriate way. In order to do so a gfp argument
needs to be added to the method xfrm_policy_alloc_security in struct
security_operations and to the internal function
selinux_xfrm_alloc_user. After that switch to GFP_ATOMIC in the atomic
callers and leave GFP_KERNEL as before for the rest.
The path that needed the gfp argument addition is:
security_xfrm_policy_alloc -> security_ops.xfrm_policy_alloc_security ->
all users of xfrm_policy_alloc_security (e.g. selinux_xfrm_policy_alloc) ->
selinux_xfrm_alloc_user (here the allocation used to be GFP_KERNEL only)

Now adding a gfp argument to selinux_xfrm_alloc_user requires us to also
add it to security_context_to_sid which is used inside and prior to this
patch did only GFP_KERNEL allocation. So add gfp argument to
security_context_to_sid and adjust all of its callers as well.

CC: Paul Moore <paul@paul-moore.com>
CC: Dave Jones <davej@redhat.com>
CC: Steffen Klassert <steffen.klassert@secunet.com>
CC: Fan Du <fan.du@windriver.com>
CC: David S. Miller <davem@davemloft.net>
CC: LSM list <linux-security-module@vger.kernel.org>
CC: SELinux list <selinux@tycho.nsa.gov>

Signed-off-by: Nikolay Aleksandrov <nikolay@redhat.com>
Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
Nikolay Aleksandrov 2014-03-07 12:44:19 +01:00 committed by Steffen Klassert
parent 87536a81e1
commit 52a4c6404f
11 changed files with 59 additions and 38 deletions

View File

@ -1040,6 +1040,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* Allocate a security structure to the xp->security field; the security * Allocate a security structure to the xp->security field; the security
* field is initialized to NULL when the xfrm_policy is allocated. * field is initialized to NULL when the xfrm_policy is allocated.
* Return 0 if operation was successful (memory to allocate, legal context) * Return 0 if operation was successful (memory to allocate, legal context)
* @gfp is to specify the context for the allocation
* @xfrm_policy_clone_security: * @xfrm_policy_clone_security:
* @old_ctx contains an existing xfrm_sec_ctx. * @old_ctx contains an existing xfrm_sec_ctx.
* @new_ctxp contains a new xfrm_sec_ctx being cloned from old. * @new_ctxp contains a new xfrm_sec_ctx being cloned from old.
@ -1683,7 +1684,7 @@ struct security_operations {
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
int (*xfrm_policy_alloc_security) (struct xfrm_sec_ctx **ctxp, int (*xfrm_policy_alloc_security) (struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx); struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp);
int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx); int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx);
void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx); void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx);
int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx); int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx);
@ -2859,7 +2860,8 @@ static inline void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx); int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp);
int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp); int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp);
void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx); void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx);
@ -2877,7 +2879,9 @@ void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl);
#else /* CONFIG_SECURITY_NETWORK_XFRM */ #else /* CONFIG_SECURITY_NETWORK_XFRM */
static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx) static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx,
gfp_t gfp)
{ {
return 0; return 0;
} }

View File

@ -2239,7 +2239,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, const struct sadb_
goto out; goto out;
} }
err = security_xfrm_policy_alloc(&xp->security, uctx); err = security_xfrm_policy_alloc(&xp->security, uctx, GFP_KERNEL);
kfree(uctx); kfree(uctx);
if (err) if (err)
@ -2341,7 +2341,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa
if (!uctx) if (!uctx)
return -ENOMEM; return -ENOMEM;
err = security_xfrm_policy_alloc(&pol_ctx, uctx); err = security_xfrm_policy_alloc(&pol_ctx, uctx, GFP_KERNEL);
kfree(uctx); kfree(uctx);
if (err) if (err)
return err; return err;
@ -3241,7 +3241,7 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
if ((*dir = verify_sec_ctx_len(p))) if ((*dir = verify_sec_ctx_len(p)))
goto out; goto out;
uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_ATOMIC); uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx, GFP_ATOMIC);
*dir = security_xfrm_policy_alloc(&xp->security, uctx); *dir = security_xfrm_policy_alloc(&xp->security, uctx, GFP_ATOMIC);
kfree(uctx); kfree(uctx);
if (*dir) if (*dir)

View File

@ -1221,7 +1221,7 @@ static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs
return 0; return 0;
uctx = nla_data(rt); uctx = nla_data(rt);
return security_xfrm_policy_alloc(&pol->security, uctx); return security_xfrm_policy_alloc(&pol->security, uctx, GFP_KERNEL);
} }
static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
@ -1626,7 +1626,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
if (rt) { if (rt) {
struct xfrm_user_sec_ctx *uctx = nla_data(rt); struct xfrm_user_sec_ctx *uctx = nla_data(rt);
err = security_xfrm_policy_alloc(&ctx, uctx); err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
if (err) if (err)
return err; return err;
} }
@ -1928,7 +1928,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
if (rt) { if (rt) {
struct xfrm_user_sec_ctx *uctx = nla_data(rt); struct xfrm_user_sec_ctx *uctx = nla_data(rt);
err = security_xfrm_policy_alloc(&ctx, uctx); err = security_xfrm_policy_alloc(&ctx, uctx, GFP_KERNEL);
if (err) if (err)
return err; return err;
} }

View File

@ -757,7 +757,8 @@ static void cap_skb_owned_by(struct sk_buff *skb, struct sock *sk)
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
static int cap_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp, static int cap_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx) struct xfrm_user_sec_ctx *sec_ctx,
gfp_t gfp)
{ {
return 0; return 0;
} }

View File

@ -1317,9 +1317,11 @@ void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx) int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx,
gfp_t gfp)
{ {
return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx); return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx, gfp);
} }
EXPORT_SYMBOL(security_xfrm_policy_alloc); EXPORT_SYMBOL(security_xfrm_policy_alloc);

View File

@ -668,7 +668,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
if (flags[i] == SBLABEL_MNT) if (flags[i] == SBLABEL_MNT)
continue; continue;
rc = security_context_to_sid(mount_options[i], rc = security_context_to_sid(mount_options[i],
strlen(mount_options[i]), &sid); strlen(mount_options[i]), &sid, GFP_KERNEL);
if (rc) { if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid" printk(KERN_WARNING "SELinux: security_context_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n", "(%s) failed for (dev %s, type %s) errno=%d\n",
@ -2489,7 +2489,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
if (flags[i] == SBLABEL_MNT) if (flags[i] == SBLABEL_MNT)
continue; continue;
len = strlen(mount_options[i]); len = strlen(mount_options[i]);
rc = security_context_to_sid(mount_options[i], len, &sid); rc = security_context_to_sid(mount_options[i], len, &sid,
GFP_KERNEL);
if (rc) { if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid" printk(KERN_WARNING "SELinux: security_context_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n", "(%s) failed for (dev %s, type %s) errno=%d\n",
@ -2893,7 +2894,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
if (rc) if (rc)
return rc; return rc;
rc = security_context_to_sid(value, size, &newsid); rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
if (rc == -EINVAL) { if (rc == -EINVAL) {
if (!capable(CAP_MAC_ADMIN)) { if (!capable(CAP_MAC_ADMIN)) {
struct audit_buffer *ab; struct audit_buffer *ab;
@ -3050,7 +3051,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (!value || !size) if (!value || !size)
return -EACCES; return -EACCES;
rc = security_context_to_sid((void *)value, size, &newsid); rc = security_context_to_sid((void *)value, size, &newsid, GFP_KERNEL);
if (rc) if (rc)
return rc; return rc;
@ -5529,7 +5530,7 @@ static int selinux_setprocattr(struct task_struct *p,
str[size-1] = 0; str[size-1] = 0;
size--; size--;
} }
error = security_context_to_sid(value, size, &sid); error = security_context_to_sid(value, size, &sid, GFP_KERNEL);
if (error == -EINVAL && !strcmp(name, "fscreate")) { if (error == -EINVAL && !strcmp(name, "fscreate")) {
if (!capable(CAP_MAC_ADMIN)) { if (!capable(CAP_MAC_ADMIN)) {
struct audit_buffer *ab; struct audit_buffer *ab;
@ -5638,7 +5639,7 @@ static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{ {
return security_context_to_sid(secdata, seclen, secid); return security_context_to_sid(secdata, seclen, secid, GFP_KERNEL);
} }
static void selinux_release_secctx(char *secdata, u32 seclen) static void selinux_release_secctx(char *secdata, u32 seclen)

View File

@ -134,7 +134,7 @@ int security_sid_to_context(u32 sid, char **scontext,
int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len); int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len);
int security_context_to_sid(const char *scontext, u32 scontext_len, int security_context_to_sid(const char *scontext, u32 scontext_len,
u32 *out_sid); u32 *out_sid, gfp_t gfp);
int security_context_to_sid_default(const char *scontext, u32 scontext_len, int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags); u32 *out_sid, u32 def_sid, gfp_t gfp_flags);

View File

@ -10,7 +10,8 @@
#include <net/flow.h> #include <net/flow.h>
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *uctx); struct xfrm_user_sec_ctx *uctx,
gfp_t gfp);
int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp); struct xfrm_sec_ctx **new_ctxp);
void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);

View File

@ -576,7 +576,7 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
if (length) if (length)
goto out; goto out;
length = security_context_to_sid(buf, size, &sid); length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
@ -731,11 +731,13 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out; goto out;
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
GFP_KERNEL);
if (length) if (length)
goto out; goto out;
@ -817,11 +819,13 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
objname = namebuf; objname = namebuf;
} }
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
GFP_KERNEL);
if (length) if (length)
goto out; goto out;
@ -878,11 +882,13 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out; goto out;
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
GFP_KERNEL);
if (length) if (length)
goto out; goto out;
@ -934,7 +940,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s", con, user) != 2) if (sscanf(buf, "%s %s", con, user) != 2)
goto out; goto out;
length = security_context_to_sid(con, strlen(con) + 1, &sid); length = security_context_to_sid(con, strlen(con) + 1, &sid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
@ -994,11 +1000,13 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out; goto out;
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); length = security_context_to_sid(scon, strlen(scon) + 1, &ssid,
GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid,
GFP_KERNEL);
if (length) if (length)
goto out; goto out;

View File

@ -1289,16 +1289,18 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
* @scontext: security context * @scontext: security context
* @scontext_len: length in bytes * @scontext_len: length in bytes
* @sid: security identifier, SID * @sid: security identifier, SID
* @gfp: context for the allocation
* *
* Obtains a SID associated with the security context that * Obtains a SID associated with the security context that
* has the string representation specified by @scontext. * has the string representation specified by @scontext.
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success. * memory is available, or 0 on success.
*/ */
int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
gfp_t gfp)
{ {
return security_context_to_sid_core(scontext, scontext_len, return security_context_to_sid_core(scontext, scontext_len,
sid, SECSID_NULL, GFP_KERNEL, 0); sid, SECSID_NULL, gfp, 0);
} }
/** /**

View File

@ -78,7 +78,8 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
* xfrm_user_sec_ctx context. * xfrm_user_sec_ctx context.
*/ */
static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *uctx) struct xfrm_user_sec_ctx *uctx,
gfp_t gfp)
{ {
int rc; int rc;
const struct task_security_struct *tsec = current_security(); const struct task_security_struct *tsec = current_security();
@ -94,7 +95,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
if (str_len >= PAGE_SIZE) if (str_len >= PAGE_SIZE)
return -ENOMEM; return -ENOMEM;
ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL); ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp);
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
@ -103,7 +104,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
ctx->ctx_len = str_len; ctx->ctx_len = str_len;
memcpy(ctx->ctx_str, &uctx[1], str_len); memcpy(ctx->ctx_str, &uctx[1], str_len);
ctx->ctx_str[str_len] = '\0'; ctx->ctx_str[str_len] = '\0';
rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid); rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid, gfp);
if (rc) if (rc)
goto err; goto err;
@ -282,9 +283,10 @@ int selinux_xfrm_skb_sid(struct sk_buff *skb, u32 *sid)
* LSM hook implementation that allocs and transfers uctx spec to xfrm_policy. * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
*/ */
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *uctx) struct xfrm_user_sec_ctx *uctx,
gfp_t gfp)
{ {
return selinux_xfrm_alloc_user(ctxp, uctx); return selinux_xfrm_alloc_user(ctxp, uctx, gfp);
} }
/* /*
@ -332,7 +334,7 @@ int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
int selinux_xfrm_state_alloc(struct xfrm_state *x, int selinux_xfrm_state_alloc(struct xfrm_state *x,
struct xfrm_user_sec_ctx *uctx) struct xfrm_user_sec_ctx *uctx)
{ {
return selinux_xfrm_alloc_user(&x->security, uctx); return selinux_xfrm_alloc_user(&x->security, uctx, GFP_KERNEL);
} }
/* /*