Commit 1d88f183 authored by Miklos Szeredi's avatar Miklos Szeredi

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: default avatarEryu Guan <eguan@redhat.com>
Fixes: 09d8b586 ("ovl: move __upperdentry to ovl_inode")
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent a59f97ff
...@@ -202,37 +202,38 @@ bool ovl_is_private_xattr(const char *name) ...@@ -202,37 +202,38 @@ bool ovl_is_private_xattr(const char *name)
sizeof(OVL_XATTR_PREFIX) - 1) == 0; sizeof(OVL_XATTR_PREFIX) - 1) == 0;
} }
int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
size_t size, int flags) const void *value, size_t size, int flags)
{ {
int err; int err;
struct path realpath; struct dentry *upperdentry = ovl_i_dentry_upper(inode);
enum ovl_path_type type = ovl_path_real(dentry, &realpath); struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
const struct cred *old_cred; const struct cred *old_cred;
err = ovl_want_write(dentry); err = ovl_want_write(dentry);
if (err) if (err)
goto out; goto out;
if (!value && !OVL_TYPE_UPPER(type)) { if (!value && !upperdentry) {
err = vfs_getxattr(realpath.dentry, name, NULL, 0); err = vfs_getxattr(realdentry, name, NULL, 0);
if (err < 0) if (err < 0)
goto out_drop_write; goto out_drop_write;
} }
if (!upperdentry) {
err = ovl_copy_up(dentry); err = ovl_copy_up(dentry);
if (err) if (err)
goto out_drop_write; goto out_drop_write;
if (!OVL_TYPE_UPPER(type)) realdentry = ovl_dentry_upper(dentry);
ovl_path_upper(dentry, &realpath); }
old_cred = ovl_override_creds(dentry->d_sb); old_cred = ovl_override_creds(dentry->d_sb);
if (value) if (value)
err = vfs_setxattr(realpath.dentry, name, value, size, flags); err = vfs_setxattr(realdentry, name, value, size, flags);
else { else {
WARN_ON(flags != XATTR_REPLACE); WARN_ON(flags != XATTR_REPLACE);
err = vfs_removexattr(realpath.dentry, name); err = vfs_removexattr(realdentry, name);
} }
revert_creds(old_cred); revert_creds(old_cred);
...@@ -242,12 +243,13 @@ int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, ...@@ -242,12 +243,13 @@ int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value,
return err; 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) void *value, size_t size)
{ {
struct dentry *realdentry = ovl_dentry_real(dentry);
ssize_t res; ssize_t res;
const struct cred *old_cred; 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); old_cred = ovl_override_creds(dentry->d_sb);
res = vfs_getxattr(realdentry, name, value, size); res = vfs_getxattr(realdentry, name, value, size);
......
...@@ -200,6 +200,7 @@ enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path); ...@@ -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_upper(struct dentry *dentry);
struct dentry *ovl_dentry_lower(struct dentry *dentry); struct dentry *ovl_dentry_lower(struct dentry *dentry);
struct dentry *ovl_dentry_real(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_upper(struct inode *inode);
struct inode *ovl_inode_lower(struct inode *inode); struct inode *ovl_inode_lower(struct inode *inode);
struct inode *ovl_inode_real(struct inode *inode); struct inode *ovl_inode_real(struct inode *inode);
...@@ -271,9 +272,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr); ...@@ -271,9 +272,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr);
int ovl_getattr(const struct path *path, struct kstat *stat, int ovl_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags); u32 request_mask, unsigned int flags);
int ovl_permission(struct inode *inode, int mask); int ovl_permission(struct inode *inode, int mask);
int ovl_xattr_set(struct dentry *dentry, const char *name, const void *value, int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
size_t size, int flags); const void *value, size_t size, int flags);
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); void *value, size_t size);
ssize_t ovl_listxattr(struct dentry *dentry, char *list, 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); 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, ...@@ -692,7 +692,7 @@ ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode, struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size) 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 static int __maybe_unused
...@@ -742,7 +742,7 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler, ...@@ -742,7 +742,7 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
return err; 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) if (!err)
ovl_copyattr(ovl_inode_real(inode), inode); ovl_copyattr(ovl_inode_real(inode), inode);
...@@ -772,7 +772,7 @@ static int ovl_other_xattr_get(const struct xattr_handler *handler, ...@@ -772,7 +772,7 @@ static int ovl_other_xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode, struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size) 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, 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, ...@@ -780,7 +780,7 @@ static int ovl_other_xattr_set(const struct xattr_handler *handler,
const char *name, const void *value, const char *name, const void *value,
size_t size, int flags) 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 static const struct xattr_handler __maybe_unused
......
...@@ -157,9 +157,14 @@ struct dentry *ovl_dentry_real(struct dentry *dentry) ...@@ -157,9 +157,14 @@ struct dentry *ovl_dentry_real(struct dentry *dentry)
return ovl_dentry_upper(dentry) ?: ovl_dentry_lower(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 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; return upperdentry ? d_inode(upperdentry) : NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment