Re: [PATCH v5 6/7] selinux: Revalidate invalid inode security labels

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sunday, November 01, 2015 06:24:32 PM Andreas Gruenbacher wrote:
> When fetching an inode's security label, check if it is still valid, and
> try reloading it if it is not. Reloading will fail when we are in RCU
> context which doesn't allow sleeping, or when we can't find a dentry for
> the inode.  (Reloading happens via iop->getxattr which takes a dentry
> parameter.)  When reloading fails, continue using the old, invalid
> label.
> 
> Signed-off-by: Andreas Gruenbacher <agruenba@xxxxxxxxxx>
> Acked-by: Stephen Smalley <sds@xxxxxxxxxxxxx>

Generally I would say that you made enough changes between v4 and v5 that 
Stephen's ACK should have been dropped, but considering that he suggested the 
changes I think's it's okay to leave it as-is.

Stephen, I'm reviewing/merging these changes now for the selinux#next-queue, 
speak up if you have want your ACK removed.

> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index dcac6dc..0f94c2d 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -241,11 +241,63 @@ static int inode_alloc_security(struct inode *inode)
>  	return 0;
>  }
> 
> +static int inode_doinit_with_dentry(struct inode *inode, struct dentry
> *opt_dentry); +
> +/*
> + * Try reloading inode security labels that have been marked as invalid. 
> The + * @may_sleep parameter indicates when sleeping and thus reloading
> labels is + * allowed; when set to false, returns ERR_PTR(-ECHILD) when the
> label is + * invalid.  The @opt_dentry parameter should be set to a dentry
> of the inode; + * when no dentry is available, set it to NULL instead.
> + */
> +static int __inode_security_revalidate(struct inode *inode,
> +				       struct dentry *opt_dentry,
> +				       bool may_sleep)
> +{
> +	struct inode_security_struct *isec = inode->i_security;
> +
> +	might_sleep_if(may_sleep);
> +
> +	if (isec->initialized == LABEL_INVALID) {
> +		if (!may_sleep)
> +			return -ECHILD;
> +
> +		/*
> +		 * Try reloading the inode security label.  This will fail if
> +		 * @opt_dentry is NULL and no dentry for this inode can be
> +		 * found; in that case, continue using the old label.
> +		 */
> +		inode_doinit_with_dentry(inode, opt_dentry);
> +	}
> +	return 0;
> +}
> +
> +static void inode_security_revalidate(struct inode *inode)
> +{
> +	__inode_security_revalidate(inode, NULL, true);
> +}
> +
> +static struct inode_security_struct *inode_security_novalidate(struct inode
> *inode) +{
> +	return inode->i_security;
> +}
> +
> +static struct inode_security_struct *inode_security_rcu(struct inode
> *inode, bool rcu) +{
> +	int error;
> +
> +	error = __inode_security_revalidate(inode, NULL, !rcu);
> +	if (error)
> +		return ERR_PTR(error);
> +	return inode->i_security;
> +}
> +
>  /*
>   * Get the security label of an inode.
>   */
>  static struct inode_security_struct *inode_security(struct inode *inode)
>  {
> +	__inode_security_revalidate(inode, NULL, true);
>  	return inode->i_security;
>  }
> 
> @@ -256,6 +308,7 @@ static struct inode_security_struct
> *backing_inode_security(struct dentry *dentr {
>  	struct inode *inode = d_backing_inode(dentry);
> 
> +	__inode_security_revalidate(inode, dentry, true);
>  	return inode->i_security;
>  }
> 
> @@ -362,8 +415,6 @@ static const char *labeling_behaviors[7] = {
>  	"uses native labeling",
>  };
> 
> -static int inode_doinit_with_dentry(struct inode *inode, struct dentry
> *opt_dentry); -
>  static inline int inode_doinit(struct inode *inode)
>  {
>  	return inode_doinit_with_dentry(inode, NULL);
> @@ -1655,6 +1706,7 @@ static inline int dentry_has_perm(const struct cred
> *cred,
> 
>  	ad.type = LSM_AUDIT_DATA_DENTRY;
>  	ad.u.dentry = dentry;
> +	__inode_security_revalidate(inode, dentry, true);
>  	return inode_has_perm(cred, inode, av, &ad);
>  }
> 
> @@ -1670,6 +1722,7 @@ static inline int path_has_perm(const struct cred
> *cred,
> 
>  	ad.type = LSM_AUDIT_DATA_PATH;
>  	ad.u.path = *path;
> +	__inode_security_revalidate(inode, path->dentry, true);
>  	return inode_has_perm(cred, inode, av, &ad);
>  }
> 
> @@ -2874,7 +2927,9 @@ static int selinux_inode_follow_link(struct dentry
> *dentry, struct inode *inode, ad.type = LSM_AUDIT_DATA_DENTRY;
>  	ad.u.dentry = dentry;
>  	sid = cred_sid(cred);
> -	isec = inode_security(inode);
> +	isec = inode_security_rcu(inode, rcu);
> +	if (IS_ERR(isec))
> +		return PTR_ERR(isec);
> 
>  	return avc_has_perm_flags(sid, isec->sid, isec->sclass, FILE__READ, &ad,
>  				  rcu ? MAY_NOT_BLOCK : 0);
> @@ -2926,7 +2981,9 @@ static int selinux_inode_permission(struct inode
> *inode, int mask) perms = file_mask_to_av(inode->i_mode, mask);
> 
>  	sid = cred_sid(cred);
> -	isec = inode_security(inode);
> +	isec = inode_security_rcu(inode, flags & MAY_NOT_BLOCK);
> +	if (IS_ERR(isec))
> +		return PTR_ERR(isec);
> 
>  	rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
>  	audited = avc_audit_required(perms, &avd, rc,
> @@ -3234,6 +3291,7 @@ static int selinux_file_permission(struct file *file,
> int mask) /* No change since file_open check. */
>  		return 0;
> 
> +	inode_security_revalidate(inode);
>  	return selinux_revalidate_file_permission(file, mask);
>  }
> 
> @@ -3539,6 +3597,7 @@ static int selinux_file_open(struct file *file, const
> struct cred *cred) * new inode label or new policy.
>  	 * This check is not redundant - do not remove.
>  	 */
> +	inode_security_revalidate(file_inode(file));
>  	return file_path_has_perm(cred, file, open_file_to_av(file));
>  }
> 
> @@ -4080,7 +4139,7 @@ static int selinux_socket_post_create(struct socket
> *sock, int family, int type, int protocol, int kern)
>  {
>  	const struct task_security_struct *tsec = current_security();
> -	struct inode_security_struct *isec = inode_security(SOCK_INODE(sock));
> +	struct inode_security_struct *isec =
> inode_security_novalidate(SOCK_INODE(sock)); struct sk_security_struct
> *sksec;
>  	int err = 0;
> 
> @@ -4280,9 +4339,9 @@ static int selinux_socket_accept(struct socket *sock,
> struct socket *newsock) if (err)
>  		return err;
> 
> -	newisec = inode_security(SOCK_INODE(newsock));
> +	newisec = inode_security_novalidate(SOCK_INODE(newsock));
> 
> -	isec = inode_security(SOCK_INODE(sock));
> +	isec = inode_security_novalidate(SOCK_INODE(sock));
>  	newisec->sclass = isec->sclass;
>  	newisec->sid = isec->sid;
>  	newisec->initialized = LABEL_INITIALIZED;
> @@ -4620,7 +4679,8 @@ static void selinux_sk_getsecid(struct sock *sk, u32
> *secid)
> 
>  static void selinux_sock_graft(struct sock *sk, struct socket *parent)
>  {
> -	struct inode_security_struct *isec = inode_security(SOCK_INODE(parent));
> +	struct inode_security_struct *isec =
> +		inode_security_novalidate(SOCK_INODE(parent));
>  	struct sk_security_struct *sksec = sk->sk_security;
> 
>  	if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||

-- 
paul moore
www.paul-moore.com

_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.



[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux