Commit 521484639ec19a6f1ed56de6993feb255f5f676c
1 parent
a105d685a8
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
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) |