diff mbox

[PATCHv2,2/2] selinux: add gfp argument to security_xfrm_policy_alloc and fix callers

Message ID 1394192659-10764-3-git-send-email-nikolay@redhat.com
State Awaiting Upstream, archived
Delegated to: David Miller
Headers show

Commit Message

Nikolay Aleksandrov March 7, 2014, 11:44 a.m. UTC
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>
---
v2: Add SELinux list to CCs, add gfp argument to security_context_to_sid
and adjust callers

 include/linux/security.h            | 10 +++++++---
 net/key/af_key.c                    |  6 +++---
 net/xfrm/xfrm_user.c                |  6 +++---
 security/capability.c               |  3 ++-
 security/security.c                 |  6 ++++--
 security/selinux/hooks.c            | 13 +++++++------
 security/selinux/include/security.h |  2 +-
 security/selinux/include/xfrm.h     |  3 ++-
 security/selinux/selinuxfs.c        | 28 ++++++++++++++++++----------
 security/selinux/ss/services.c      |  6 ++++--
 security/selinux/xfrm.c             | 14 ++++++++------
 11 files changed, 59 insertions(+), 38 deletions(-)

Comments

Paul Moore March 7, 2014, 10:27 p.m. UTC | #1
On Friday, March 07, 2014 12:44:19 PM Nikolay Aleksandrov wrote:
> 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>

This looks good to me, thanks for finding this and following through with a 
patch.

Acked-by: Paul Moore <paul@paul-moore.com>

> ---
> v2: Add SELinux list to CCs, add gfp argument to security_context_to_sid
> and adjust callers
> 
>  include/linux/security.h            | 10 +++++++---
>  net/key/af_key.c                    |  6 +++---
>  net/xfrm/xfrm_user.c                |  6 +++---
>  security/capability.c               |  3 ++-
>  security/security.c                 |  6 ++++--
>  security/selinux/hooks.c            | 13 +++++++------
>  security/selinux/include/security.h |  2 +-
>  security/selinux/include/xfrm.h     |  3 ++-
>  security/selinux/selinuxfs.c        | 28 ++++++++++++++++++----------
>  security/selinux/ss/services.c      |  6 ++++--
>  security/selinux/xfrm.c             | 14 ++++++++------
>  11 files changed, 59 insertions(+), 38 deletions(-)
> 
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 5623a7f965b7..2fc42d191f79 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -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 *	field is initialized to NULL when the
> xfrm_policy is allocated. *	Return 0 if operation was successful (memory 
to
> allocate, legal context) + *	@gfp is to specify the context for the
> allocation
>   * @xfrm_policy_clone_security:
>   *	@old_ctx contains an existing xfrm_sec_ctx.
>   *	@new_ctxp contains a new xfrm_sec_ctx being cloned from old.
> @@ -1683,7 +1684,7 @@ struct security_operations {
> 
>  #ifdef CONFIG_SECURITY_NETWORK_XFRM
>  	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); void (*xfrm_policy_free_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
> 
> -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); void security_xfrm_policy_free(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 */
> 
> -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;
>  }
> diff --git a/net/key/af_key.c b/net/key/af_key.c
> index 1526023f99ed..79326978517a 100644
> --- a/net/key/af_key.c
> +++ b/net/key/af_key.c
> @@ -2239,7 +2239,7 @@ static int pfkey_spdadd(struct sock *sk, struct
> sk_buff *skb, const struct sadb_ goto out;
>  		}
> 
> -		err = security_xfrm_policy_alloc(&xp->security, uctx);
> +		err = security_xfrm_policy_alloc(&xp->security, uctx, GFP_KERNEL);
>  		kfree(uctx);
> 
>  		if (err)
> @@ -2341,7 +2341,7 @@ static int pfkey_spddelete(struct sock *sk, struct
> sk_buff *skb, const struct sa if (!uctx)
>  			return -ENOMEM;
> 
> -		err = security_xfrm_policy_alloc(&pol_ctx, uctx);
> +		err = security_xfrm_policy_alloc(&pol_ctx, uctx, GFP_KERNEL);
>  		kfree(uctx);
>  		if (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)))
>  			goto out;
>  		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);
> 
>  		if (*dir)
> diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
> index c274179d60a2..2f7ddc3a59b4 100644
> --- a/net/xfrm/xfrm_user.c
> +++ b/net/xfrm/xfrm_user.c
> @@ -1221,7 +1221,7 @@ static int copy_from_user_sec_ctx(struct xfrm_policy
> *pol, struct nlattr **attrs return 0;
> 
>  	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, @@ -1626,7 +1626,7 @@ static int xfrm_get_policy(struct sk_buff *skb,
> struct nlmsghdr *nlh, if (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)
>  				return err;
>  		}
> @@ -1928,7 +1928,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb,
> struct nlmsghdr *nlh, if (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)
>  				return err;
>  		}
> diff --git a/security/capability.c b/security/capability.c
> index 8b4f24ae4338..21e2b9cae685 100644
> --- a/security/capability.c
> +++ b/security/capability.c
> @@ -757,7 +757,8 @@ static void cap_skb_owned_by(struct sk_buff *skb, struct
> sock *sk)
> 
>  #ifdef CONFIG_SECURITY_NETWORK_XFRM
>  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;
>  }
> diff --git a/security/security.c b/security/security.c
> index 15b6928592ef..919cad93ac82 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1317,9 +1317,11 @@ void security_skb_owned_by(struct sk_buff *skb,
> struct sock *sk)
> 
>  #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);
> 
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 4b34847208cc..b332e2cc0954 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -668,7 +668,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
>  		if (flags[i] == SBLABEL_MNT)
>  			continue;
>  		rc = security_context_to_sid(mount_options[i],
> -					     strlen(mount_options[i]), &sid);
> +					     strlen(mount_options[i]), &sid, GFP_KERNEL);
>  		if (rc) {
>  			printk(KERN_WARNING "SELinux: security_context_to_sid"
>  			       "(%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)
>  			continue;
>  		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) {
>  			printk(KERN_WARNING "SELinux: security_context_to_sid"
>  			       "(%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)
>  		return rc;
> 
> -	rc = security_context_to_sid(value, size, &newsid);
> +	rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
>  	if (rc == -EINVAL) {
>  		if (!capable(CAP_MAC_ADMIN)) {
>  			struct audit_buffer *ab;
> @@ -3050,7 +3051,7 @@ static int selinux_inode_setsecurity(struct inode
> *inode, const char *name, if (!value || !size)
>  		return -EACCES;
> 
> -	rc = security_context_to_sid((void *)value, size, &newsid);
> +	rc = security_context_to_sid((void *)value, size, &newsid, GFP_KERNEL);
>  	if (rc)
>  		return rc;
> 
> @@ -5529,7 +5530,7 @@ static int selinux_setprocattr(struct task_struct *p,
>  			str[size-1] = 0;
>  			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 (!capable(CAP_MAC_ADMIN)) {
>  				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) {
> -	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)
> diff --git a/security/selinux/include/security.h
> b/security/selinux/include/security.h index 8ed8daf7f1ee..ce7852cf526b
> 100644
> --- a/security/selinux/include/security.h
> +++ b/security/selinux/include/security.h
> @@ -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_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,
> u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
> diff --git a/security/selinux/include/xfrm.h
> b/security/selinux/include/xfrm.h index 48c3cc94c168..9f0584710c85 100644
> --- a/security/selinux/include/xfrm.h
> +++ b/security/selinux/include/xfrm.h
> @@ -10,7 +10,8 @@
>  #include <net/flow.h>
> 
>  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,
>  			      struct xfrm_sec_ctx **new_ctxp);
>  void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
> diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
> index 5122affe06a8..d60c0ee66387 100644
> --- a/security/selinux/selinuxfs.c
> +++ b/security/selinux/selinuxfs.c
> @@ -576,7 +576,7 @@ static ssize_t sel_write_context(struct file *file, char
> *buf, size_t size) if (length)
>  		goto out;
> 
> -	length = security_context_to_sid(buf, size, &sid);
> +	length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
>  	if (length)
>  		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)
>  		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)
>  		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)
>  		goto out;
> 
> @@ -817,11 +819,13 @@ static ssize_t sel_write_create(struct file *file,
> char *buf, size_t size) 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)
>  		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)
>  		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)
>  		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)
>  		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)
>  		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)
>  		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)
>  		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)
>  		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)
>  		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)
>  		goto out;
> 
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index 5d0144ee8ed6..4bca49414a40 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -1289,16 +1289,18 @@ out:
>   * @scontext: security context
>   * @scontext_len: length in bytes
>   * @sid: security identifier, SID
> + * @gfp: context for the allocation
>   *
>   * Obtains a SID associated with the security context that
>   * has the string representation specified by @scontext.
>   * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
>   * 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,
> -					    sid, SECSID_NULL, GFP_KERNEL, 0);
> +					    sid, SECSID_NULL, gfp, 0);
>  }
> 
>  /**
> diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
> index 0462cb3ff0a7..98b042630a9e 100644
> --- a/security/selinux/xfrm.c
> +++ b/security/selinux/xfrm.c
> @@ -78,7 +78,8 @@ static inline int selinux_authorizable_xfrm(struct
> xfrm_state *x) * xfrm_user_sec_ctx context.
>   */
>  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;
>  	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)
>  		return -ENOMEM;
> 
> -	ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL);
> +	ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp);
>  	if (!ctx)
>  		return -ENOMEM;
> 
> @@ -103,7 +104,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx
> **ctxp, ctx->ctx_len = str_len;
>  	memcpy(ctx->ctx_str, &uctx[1], str_len);
>  	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)
>  		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. */
>  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,
>  			     struct xfrm_user_sec_ctx *uctx)
>  {
> -	return selinux_xfrm_alloc_user(&x->security, uctx);
> +	return selinux_xfrm_alloc_user(&x->security, uctx, GFP_KERNEL);
>  }
> 
>  /*
Steffen Klassert March 10, 2014, 12:52 p.m. UTC | #2
On Fri, Mar 07, 2014 at 05:27:17PM -0500, Paul Moore wrote:
> On Friday, March 07, 2014 12:44:19 PM Nikolay Aleksandrov wrote:
> > 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>
> 
> This looks good to me, thanks for finding this and following through with a 
> patch.
> 
> Acked-by: Paul Moore <paul@paul-moore.com>
> 

Both patches applied to the ipsec tree.

Thanks everyone!
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/security.h b/include/linux/security.h
index 5623a7f965b7..2fc42d191f79 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -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
  *	field is initialized to NULL when the xfrm_policy is allocated.
  *	Return 0 if operation was successful (memory to allocate, legal context)
+ *	@gfp is to specify the context for the allocation
  * @xfrm_policy_clone_security:
  *	@old_ctx contains an existing xfrm_sec_ctx.
  *	@new_ctxp contains a new xfrm_sec_ctx being cloned from old.
@@ -1683,7 +1684,7 @@  struct security_operations {
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 	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);
 	void (*xfrm_policy_free_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
 
-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);
 void security_xfrm_policy_free(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 */
 
-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;
 }
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 1526023f99ed..79326978517a 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2239,7 +2239,7 @@  static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, const struct sadb_
 			goto out;
 		}
 
-		err = security_xfrm_policy_alloc(&xp->security, uctx);
+		err = security_xfrm_policy_alloc(&xp->security, uctx, GFP_KERNEL);
 		kfree(uctx);
 
 		if (err)
@@ -2341,7 +2341,7 @@  static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sa
 		if (!uctx)
 			return -ENOMEM;
 
-		err = security_xfrm_policy_alloc(&pol_ctx, uctx);
+		err = security_xfrm_policy_alloc(&pol_ctx, uctx, GFP_KERNEL);
 		kfree(uctx);
 		if (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)))
 			goto out;
 		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);
 
 		if (*dir)
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index c274179d60a2..2f7ddc3a59b4 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1221,7 +1221,7 @@  static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs
 		return 0;
 
 	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,
@@ -1626,7 +1626,7 @@  static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 		if (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)
 				return err;
 		}
@@ -1928,7 +1928,7 @@  static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
 		if (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)
 				return err;
 		}
diff --git a/security/capability.c b/security/capability.c
index 8b4f24ae4338..21e2b9cae685 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -757,7 +757,8 @@  static void cap_skb_owned_by(struct sk_buff *skb, struct sock *sk)
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
 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;
 }
diff --git a/security/security.c b/security/security.c
index 15b6928592ef..919cad93ac82 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1317,9 +1317,11 @@  void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
 
 #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);
 
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4b34847208cc..b332e2cc0954 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -668,7 +668,7 @@  static int selinux_set_mnt_opts(struct super_block *sb,
 		if (flags[i] == SBLABEL_MNT)
 			continue;
 		rc = security_context_to_sid(mount_options[i],
-					     strlen(mount_options[i]), &sid);
+					     strlen(mount_options[i]), &sid, GFP_KERNEL);
 		if (rc) {
 			printk(KERN_WARNING "SELinux: security_context_to_sid"
 			       "(%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)
 			continue;
 		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) {
 			printk(KERN_WARNING "SELinux: security_context_to_sid"
 			       "(%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)
 		return rc;
 
-	rc = security_context_to_sid(value, size, &newsid);
+	rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
 	if (rc == -EINVAL) {
 		if (!capable(CAP_MAC_ADMIN)) {
 			struct audit_buffer *ab;
@@ -3050,7 +3051,7 @@  static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 	if (!value || !size)
 		return -EACCES;
 
-	rc = security_context_to_sid((void *)value, size, &newsid);
+	rc = security_context_to_sid((void *)value, size, &newsid, GFP_KERNEL);
 	if (rc)
 		return rc;
 
@@ -5529,7 +5530,7 @@  static int selinux_setprocattr(struct task_struct *p,
 			str[size-1] = 0;
 			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 (!capable(CAP_MAC_ADMIN)) {
 				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)
 {
-	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)
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 8ed8daf7f1ee..ce7852cf526b 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -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_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,
 				    u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 48c3cc94c168..9f0584710c85 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -10,7 +10,8 @@ 
 #include <net/flow.h>
 
 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,
 			      struct xfrm_sec_ctx **new_ctxp);
 void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 5122affe06a8..d60c0ee66387 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -576,7 +576,7 @@  static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
 	if (length)
 		goto out;
 
-	length = security_context_to_sid(buf, size, &sid);
+	length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
 	if (length)
 		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)
 		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)
 		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)
 		goto out;
 
@@ -817,11 +819,13 @@  static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 		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)
 		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)
 		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)
 		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)
 		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)
 		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)
 		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)
 		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)
 		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)
 		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)
 		goto out;
 
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 5d0144ee8ed6..4bca49414a40 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1289,16 +1289,18 @@  out:
  * @scontext: security context
  * @scontext_len: length in bytes
  * @sid: security identifier, SID
+ * @gfp: context for the allocation
  *
  * Obtains a SID associated with the security context that
  * has the string representation specified by @scontext.
  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
  * 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,
-					    sid, SECSID_NULL, GFP_KERNEL, 0);
+					    sid, SECSID_NULL, gfp, 0);
 }
 
 /**
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 0462cb3ff0a7..98b042630a9e 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -78,7 +78,8 @@  static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
  * xfrm_user_sec_ctx context.
  */
 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;
 	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)
 		return -ENOMEM;
 
-	ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL);
+	ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp);
 	if (!ctx)
 		return -ENOMEM;
 
@@ -103,7 +104,7 @@  static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
 	ctx->ctx_len = str_len;
 	memcpy(ctx->ctx_str, &uctx[1], str_len);
 	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)
 		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.
  */
 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,
 			     struct xfrm_user_sec_ctx *uctx)
 {
-	return selinux_xfrm_alloc_user(&x->security, uctx);
+	return selinux_xfrm_alloc_user(&x->security, uctx, GFP_KERNEL);
 }
 
 /*