|
@@ -242,11 +242,63 @@ static int inode_alloc_security(struct inode *inode)
|
|
return 0;
|
|
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.
|
|
* Get the security label of an inode.
|
|
*/
|
|
*/
|
|
static struct inode_security_struct *inode_security(struct inode *inode)
|
|
static struct inode_security_struct *inode_security(struct inode *inode)
|
|
{
|
|
{
|
|
|
|
+ __inode_security_revalidate(inode, NULL, true);
|
|
return inode->i_security;
|
|
return inode->i_security;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -257,6 +309,7 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr
|
|
{
|
|
{
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
struct inode *inode = d_backing_inode(dentry);
|
|
|
|
|
|
|
|
+ __inode_security_revalidate(inode, dentry, true);
|
|
return inode->i_security;
|
|
return inode->i_security;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -363,8 +416,6 @@ static const char *labeling_behaviors[7] = {
|
|
"uses native labeling",
|
|
"uses native labeling",
|
|
};
|
|
};
|
|
|
|
|
|
-static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
|
|
|
|
-
|
|
|
|
static inline int inode_doinit(struct inode *inode)
|
|
static inline int inode_doinit(struct inode *inode)
|
|
{
|
|
{
|
|
return inode_doinit_with_dentry(inode, NULL);
|
|
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.type = LSM_AUDIT_DATA_DENTRY;
|
|
ad.u.dentry = dentry;
|
|
ad.u.dentry = dentry;
|
|
|
|
+ __inode_security_revalidate(inode, dentry, true);
|
|
return inode_has_perm(cred, inode, av, &ad);
|
|
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.type = LSM_AUDIT_DATA_PATH;
|
|
ad.u.path = *path;
|
|
ad.u.path = *path;
|
|
|
|
+ __inode_security_revalidate(inode, path->dentry, true);
|
|
return inode_has_perm(cred, inode, av, &ad);
|
|
return inode_has_perm(cred, inode, av, &ad);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2871,7 +2924,9 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
|
|
ad.type = LSM_AUDIT_DATA_DENTRY;
|
|
ad.type = LSM_AUDIT_DATA_DENTRY;
|
|
ad.u.dentry = dentry;
|
|
ad.u.dentry = dentry;
|
|
sid = cred_sid(cred);
|
|
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,
|
|
return avc_has_perm_flags(sid, isec->sid, isec->sclass, FILE__READ, &ad,
|
|
rcu ? MAY_NOT_BLOCK : 0);
|
|
rcu ? MAY_NOT_BLOCK : 0);
|
|
@@ -2923,7 +2978,9 @@ static int selinux_inode_permission(struct inode *inode, int mask)
|
|
perms = file_mask_to_av(inode->i_mode, mask);
|
|
perms = file_mask_to_av(inode->i_mode, mask);
|
|
|
|
|
|
sid = cred_sid(cred);
|
|
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);
|
|
rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
|
|
audited = avc_audit_required(perms, &avd, rc,
|
|
audited = avc_audit_required(perms, &avd, rc,
|
|
@@ -3232,6 +3289,7 @@ static int selinux_file_permission(struct file *file, int mask)
|
|
/* No change since file_open check. */
|
|
/* No change since file_open check. */
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ inode_security_revalidate(inode);
|
|
return selinux_revalidate_file_permission(file, mask);
|
|
return selinux_revalidate_file_permission(file, mask);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3537,6 +3595,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
|
|
* new inode label or new policy.
|
|
* new inode label or new policy.
|
|
* This check is not redundant - do not remove.
|
|
* 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));
|
|
return file_path_has_perm(cred, file, open_file_to_av(file));
|
|
}
|
|
}
|
|
|
|
|
|
@@ -4078,7 +4137,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
|
|
int type, int protocol, int kern)
|
|
int type, int protocol, int kern)
|
|
{
|
|
{
|
|
const struct task_security_struct *tsec = current_security();
|
|
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;
|
|
struct sk_security_struct *sksec;
|
|
int err = 0;
|
|
int err = 0;
|
|
|
|
|
|
@@ -4278,9 +4337,9 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
|
|
if (err)
|
|
if (err)
|
|
return 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->sclass = isec->sclass;
|
|
newisec->sid = isec->sid;
|
|
newisec->sid = isec->sid;
|
|
newisec->initialized = LABEL_INITIALIZED;
|
|
newisec->initialized = LABEL_INITIALIZED;
|
|
@@ -4618,7 +4677,8 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
|
|
|
|
|
|
static void selinux_sock_graft(struct sock *sk, struct socket *parent)
|
|
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;
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
|
|
|
|
|
if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
|
|
if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
|