ovl: fix xattr get and set with selinux
inode_doinit_with_dentry() in SELinux wants to read the upper inode's xattr
to get security label, and ovl_xattr_get() calls ovl_dentry_real(), which
depends on dentry->d_inode, but d_inode is null and not initialized yet at
this point resulting in an Oops.
Fix by getting the upperdentry info from the inode directly in this case.
Reported-by: Eryu Guan <eguan@redhat.com>
Fixes: 09d8b58673
("ovl: move __upperdentry to ovl_inode")
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
a59f97ff66
commit
1d88f18373
|
@ -202,37 +202,38 @@ bool ovl_is_private_xattr(const char *name)
|
|||
sizeof(OVL_XATTR_PREFIX) - 1) == 0;
|
||||
}
|
||||
|
||||
int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
int err;
|
||||
struct path realpath;
|
||||
enum ovl_path_type type = ovl_path_real(dentry, &realpath);
|
||||
struct dentry *upperdentry = ovl_i_dentry_upper(inode);
|
||||
struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
|
||||
const struct cred *old_cred;
|
||||
|
||||
err = ovl_want_write(dentry);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!value && !OVL_TYPE_UPPER(type)) {
|
||||
err = vfs_getxattr(realpath.dentry, name, NULL, 0);
|
||||
if (!value && !upperdentry) {
|
||||
err = vfs_getxattr(realdentry, name, NULL, 0);
|
||||
if (err < 0)
|
||||
goto out_drop_write;
|
||||
}
|
||||
|
||||
err = ovl_copy_up(dentry);
|
||||
if (err)
|
||||
goto out_drop_write;
|
||||
if (!upperdentry) {
|
||||
err = ovl_copy_up(dentry);
|
||||
if (err)
|
||||
goto out_drop_write;
|
||||
|
||||
if (!OVL_TYPE_UPPER(type))
|
||||
ovl_path_upper(dentry, &realpath);
|
||||
realdentry = ovl_dentry_upper(dentry);
|
||||
}
|
||||
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
if (value)
|
||||
err = vfs_setxattr(realpath.dentry, name, value, size, flags);
|
||||
err = vfs_setxattr(realdentry, name, value, size, flags);
|
||||
else {
|
||||
WARN_ON(flags != XATTR_REPLACE);
|
||||
err = vfs_removexattr(realpath.dentry, name);
|
||||
err = vfs_removexattr(realdentry, name);
|
||||
}
|
||||
revert_creds(old_cred);
|
||||
|
||||
|
@ -242,12 +243,13 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
int ovl_xattr_get(struct dentry *dentry, const char *name,
|
||||
int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
void *value, size_t size)
|
||||
{
|
||||
struct dentry *realdentry = ovl_dentry_real(dentry);
|
||||
ssize_t res;
|
||||
const struct cred *old_cred;
|
||||
struct dentry *realdentry =
|
||||
ovl_i_dentry_upper(inode) ?: ovl_dentry_lower(dentry);
|
||||
|
||||
old_cred = ovl_override_creds(dentry->d_sb);
|
||||
res = vfs_getxattr(realdentry, name, value, size);
|
||||
|
|
|
@ -200,6 +200,7 @@ enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
|
|||
struct dentry *ovl_dentry_upper(struct dentry *dentry);
|
||||
struct dentry *ovl_dentry_lower(struct dentry *dentry);
|
||||
struct dentry *ovl_dentry_real(struct dentry *dentry);
|
||||
struct dentry *ovl_i_dentry_upper(struct inode *inode);
|
||||
struct inode *ovl_inode_upper(struct inode *inode);
|
||||
struct inode *ovl_inode_lower(struct inode *inode);
|
||||
struct inode *ovl_inode_real(struct inode *inode);
|
||||
|
@ -271,9 +272,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr);
|
|||
int ovl_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags);
|
||||
int ovl_permission(struct inode *inode, int mask);
|
||||
int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
|
||||
size_t size, int flags);
|
||||
int ovl_xattr_get(struct dentry *dentry, const char *name,
|
||||
int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
|
||||
void *value, size_t size);
|
||||
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
|
||||
struct posix_acl *ovl_get_acl(struct inode *inode, int type);
|
||||
|
|
|
@ -692,7 +692,7 @@ ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
|
|||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return ovl_xattr_get(dentry, handler->name, buffer, size);
|
||||
return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
|
||||
}
|
||||
|
||||
static int __maybe_unused
|
||||
|
@ -742,7 +742,7 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
|
|||
return err;
|
||||
}
|
||||
|
||||
err = ovl_xattr_set(dentry, handler->name, value, size, flags);
|
||||
err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
|
||||
if (!err)
|
||||
ovl_copyattr(ovl_inode_real(inode), inode);
|
||||
|
||||
|
@ -772,7 +772,7 @@ static int ovl_other_xattr_get(const struct xattr_handler *handler,
|
|||
struct dentry *dentry, struct inode *inode,
|
||||
const char *name, void *buffer, size_t size)
|
||||
{
|
||||
return ovl_xattr_get(dentry, name, buffer, size);
|
||||
return ovl_xattr_get(dentry, inode, name, buffer, size);
|
||||
}
|
||||
|
||||
static int ovl_other_xattr_set(const struct xattr_handler *handler,
|
||||
|
@ -780,7 +780,7 @@ static int ovl_other_xattr_set(const struct xattr_handler *handler,
|
|||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
return ovl_xattr_set(dentry, name, value, size, flags);
|
||||
return ovl_xattr_set(dentry, inode, name, value, size, flags);
|
||||
}
|
||||
|
||||
static const struct xattr_handler __maybe_unused
|
||||
|
|
|
@ -157,9 +157,14 @@ struct dentry *ovl_dentry_real(struct dentry *dentry)
|
|||
return ovl_dentry_upper(dentry) ?: ovl_dentry_lower(dentry);
|
||||
}
|
||||
|
||||
struct dentry *ovl_i_dentry_upper(struct inode *inode)
|
||||
{
|
||||
return ovl_upperdentry_dereference(OVL_I(inode));
|
||||
}
|
||||
|
||||
struct inode *ovl_inode_upper(struct inode *inode)
|
||||
{
|
||||
struct dentry *upperdentry = ovl_upperdentry_dereference(OVL_I(inode));
|
||||
struct dentry *upperdentry = ovl_i_dentry_upper(inode);
|
||||
|
||||
return upperdentry ? d_inode(upperdentry) : NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue