Skip to content

Commit 5214846

Browse files
author
Miklos Szeredi
committed
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: Miklos Szeredi <[email protected]>
1 parent a105d68 commit 5214846

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

fs/overlayfs/inode.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,26 +235,36 @@ int ovl_setxattr(struct dentry *dentry, const char *name,
235235
return err;
236236
}
237237

238+
static bool ovl_need_xattr_filter(struct dentry *dentry,
239+
enum ovl_path_type type)
240+
{
241+
return type == OVL_PATH_UPPER && S_ISDIR(dentry->d_inode->i_mode);
242+
}
243+
238244
ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
239245
void *value, size_t size)
240246
{
241-
if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
242-
ovl_is_private_xattr(name))
247+
struct path realpath;
248+
enum ovl_path_type type = ovl_path_real(dentry, &realpath);
249+
250+
if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
243251
return -ENODATA;
244252

245-
return vfs_getxattr(ovl_dentry_real(dentry), name, value, size);
253+
return vfs_getxattr(realpath.dentry, name, value, size);
246254
}
247255

248256
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
249257
{
258+
struct path realpath;
259+
enum ovl_path_type type = ovl_path_real(dentry, &realpath);
250260
ssize_t res;
251261
int off;
252262

253-
res = vfs_listxattr(ovl_dentry_real(dentry), list, size);
263+
res = vfs_listxattr(realpath.dentry, list, size);
254264
if (res <= 0 || size == 0)
255265
return res;
256266

257-
if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE)
267+
if (!ovl_need_xattr_filter(dentry, type))
258268
return res;
259269

260270
/* filter out private xattrs */
@@ -279,17 +289,16 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
279289
{
280290
int err;
281291
struct path realpath;
282-
enum ovl_path_type type;
292+
enum ovl_path_type type = ovl_path_real(dentry, &realpath);
283293

284294
err = ovl_want_write(dentry);
285295
if (err)
286296
goto out;
287297

288-
if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
289-
ovl_is_private_xattr(name))
298+
err = -ENODATA;
299+
if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
290300
goto out_drop_write;
291301

292-
type = ovl_path_real(dentry, &realpath);
293302
if (type == OVL_PATH_LOWER) {
294303
err = vfs_getxattr(realpath.dentry, name, NULL, 0);
295304
if (err < 0)

0 commit comments

Comments
 (0)