Commit 52148463 authored by Miklos Szeredi's avatar Miklos Szeredi

ovl: fix race in private xattr checks

Xattr operations can race with copy up.  This does not matter as long as
we consistently fiter out "trunsted.overlay.opaque" attribute on upper
directories.

Previously we checked parent against OVL_PATH_MERGE.  This is too general,
and prone to race with copy-up.  I.e. we found the parent to be on the
lower layer but ovl_dentry_real() would return the copied-up dentry,
possibly with the "opaque" attribute.

So instead use ovl_path_real() and decide to filter the attributes based on
the actual type of the dentry we'll use.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
parent a105d685
...@@ -235,26 +235,36 @@ int ovl_setxattr(struct dentry *dentry, const char *name, ...@@ -235,26 +235,36 @@ int ovl_setxattr(struct dentry *dentry, const char *name,
return err; return err;
} }
static bool ovl_need_xattr_filter(struct dentry *dentry,
enum ovl_path_type type)
{
return type == OVL_PATH_UPPER && S_ISDIR(dentry->d_inode->i_mode);
}
ssize_t ovl_getxattr(struct dentry *dentry, const char *name, ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
void *value, size_t size) void *value, size_t size)
{ {
if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && struct path realpath;
ovl_is_private_xattr(name)) enum ovl_path_type type = ovl_path_real(dentry, &realpath);
if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
return -ENODATA; return -ENODATA;
return vfs_getxattr(ovl_dentry_real(dentry), name, value, size); return vfs_getxattr(realpath.dentry, name, value, 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 path realpath;
enum ovl_path_type type = ovl_path_real(dentry, &realpath);
ssize_t res; ssize_t res;
int off; int off;
res = vfs_listxattr(ovl_dentry_real(dentry), list, size); res = vfs_listxattr(realpath.dentry, list, size);
if (res <= 0 || size == 0) if (res <= 0 || size == 0)
return res; return res;
if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE) if (!ovl_need_xattr_filter(dentry, type))
return res; return res;
/* filter out private xattrs */ /* filter out private xattrs */
...@@ -279,17 +289,16 @@ int ovl_removexattr(struct dentry *dentry, const char *name) ...@@ -279,17 +289,16 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
{ {
int err; int err;
struct path realpath; struct path realpath;
enum ovl_path_type type; enum ovl_path_type type = ovl_path_real(dentry, &realpath);
err = ovl_want_write(dentry); err = ovl_want_write(dentry);
if (err) if (err)
goto out; goto out;
if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && err = -ENODATA;
ovl_is_private_xattr(name)) if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
goto out_drop_write; goto out_drop_write;
type = ovl_path_real(dentry, &realpath);
if (type == OVL_PATH_LOWER) { if (type == OVL_PATH_LOWER) {
err = vfs_getxattr(realpath.dentry, name, NULL, 0); err = vfs_getxattr(realpath.dentry, name, NULL, 0);
if (err < 0) if (err < 0)
......
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