Commit 521484639ec19a6f1ed56de6993feb255f5f676c

Authored by Miklos Szeredi
1 parent a105d685a8

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 <mszeredi@suse.cz>

Showing 1 changed file with 18 additions and 9 deletions Side-by-side Diff

fs/overlayfs/inode.c
... ... @@ -235,26 +235,36 @@
235 235 return err;
236 236 }
237 237  
  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 +
238 244 ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
239 245 void *value, size_t size)
240 246 {
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))
243 251 return -ENODATA;
244 252  
245   - return vfs_getxattr(ovl_dentry_real(dentry), name, value, size);
  253 + return vfs_getxattr(realpath.dentry, name, value, size);
246 254 }
247 255  
248 256 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
249 257 {
  258 + struct path realpath;
  259 + enum ovl_path_type type = ovl_path_real(dentry, &realpath);
250 260 ssize_t res;
251 261 int off;
252 262  
253   - res = vfs_listxattr(ovl_dentry_real(dentry), list, size);
  263 + res = vfs_listxattr(realpath.dentry, list, size);
254 264 if (res <= 0 || size == 0)
255 265 return res;
256 266  
257   - if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE)
  267 + if (!ovl_need_xattr_filter(dentry, type))
258 268 return res;
259 269  
260 270 /* filter out private xattrs */
261 271  
262 272  
... ... @@ -279,17 +289,16 @@
279 289 {
280 290 int err;
281 291 struct path realpath;
282   - enum ovl_path_type type;
  292 + enum ovl_path_type type = ovl_path_real(dentry, &realpath);
283 293  
284 294 err = ovl_want_write(dentry);
285 295 if (err)
286 296 goto out;
287 297  
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))
290 300 goto out_drop_write;
291 301  
292   - type = ovl_path_real(dentry, &realpath);
293 302 if (type == OVL_PATH_LOWER) {
294 303 err = vfs_getxattr(realpath.dentry, name, NULL, 0);
295 304 if (err < 0)