aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2017-06-21 08:28:42 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2017-07-04 16:03:17 -0400
commit415543d5c64fe490b4b6a7e21c3ea2f1310c442f (patch)
treefe8d24c2f1b441845f29eece566cbd45be00d3ee
parent359f392ca53e9122cafa5fc103545558b0b85d54 (diff)
ovl: cleanup bad and stale index entries on mount
Bad index entries are entries whose name does not match the origin file handle stored in trusted.overlay.origin xattr. Bad index entries could be a result of a system power off in the middle of copy up. Stale index entries are entries whose origin file handle is stale. Stale index entries could be a result of copying layers or removing lower entries while the overlay is not mounted. The case of copying layers should be detected earlier by the verification of upper root dir origin and index dir origin. Both bad and stale index entries are detected and removed on mount. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/dir.c4
-rw-r--r--fs/overlayfs/namei.c74
-rw-r--r--fs/overlayfs/overlayfs.h6
-rw-r--r--fs/overlayfs/readdir.c50
-rw-r--r--fs/overlayfs/super.c6
5 files changed, 130 insertions, 10 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index d0d6292e069a..a072c27e03bc 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -24,7 +24,7 @@ module_param_named(redirect_max, ovl_redirect_max, ushort, 0644);
24MODULE_PARM_DESC(ovl_redirect_max, 24MODULE_PARM_DESC(ovl_redirect_max,
25 "Maximum length of absolute redirect xattr value"); 25 "Maximum length of absolute redirect xattr value");
26 26
27void ovl_cleanup(struct inode *wdir, struct dentry *wdentry) 27int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
28{ 28{
29 int err; 29 int err;
30 30
@@ -39,6 +39,8 @@ void ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
39 pr_err("overlayfs: cleanup of '%pd2' failed (%i)\n", 39 pr_err("overlayfs: cleanup of '%pd2' failed (%i)\n",
40 wdentry, err); 40 wdentry, err);
41 } 41 }
42
43 return err;
42} 44}
43 45
44struct dentry *ovl_lookup_temp(struct dentry *workdir) 46struct dentry *ovl_lookup_temp(struct dentry *workdir)
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 3bec4cb39967..4df37e805eb7 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -285,17 +285,17 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
285} 285}
286 286
287 287
288static int ovl_check_origin(struct dentry *dentry, struct dentry *upperdentry, 288static int ovl_check_origin(struct dentry *upperdentry,
289 struct path *lowerstack, unsigned int numlower,
289 struct path **stackp, unsigned int *ctrp) 290 struct path **stackp, unsigned int *ctrp)
290{ 291{
291 struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata;
292 struct vfsmount *mnt; 292 struct vfsmount *mnt;
293 struct dentry *origin = NULL; 293 struct dentry *origin = NULL;
294 int i; 294 int i;
295 295
296 296
297 for (i = 0; i < roe->numlower; i++) { 297 for (i = 0; i < numlower; i++) {
298 mnt = roe->lowerstack[i].mnt; 298 mnt = lowerstack[i].mnt;
299 origin = ovl_get_origin(upperdentry, mnt); 299 origin = ovl_get_origin(upperdentry, mnt);
300 if (IS_ERR(origin)) 300 if (IS_ERR(origin))
301 return PTR_ERR(origin); 301 return PTR_ERR(origin);
@@ -307,8 +307,9 @@ static int ovl_check_origin(struct dentry *dentry, struct dentry *upperdentry,
307 if (!origin) 307 if (!origin)
308 return 0; 308 return 0;
309 309
310 BUG_ON(*stackp || *ctrp); 310 BUG_ON(*ctrp);
311 *stackp = kmalloc(sizeof(struct path), GFP_TEMPORARY); 311 if (!*stackp)
312 *stackp = kmalloc(sizeof(struct path), GFP_TEMPORARY);
312 if (!*stackp) { 313 if (!*stackp) {
313 dput(origin); 314 dput(origin);
314 return -ENOMEM; 315 return -ENOMEM;
@@ -379,6 +380,63 @@ fail:
379} 380}
380 381
381/* 382/*
383 * Verify that an index entry name matches the origin file handle stored in
384 * OVL_XATTR_ORIGIN and that origin file handle can be decoded to lower path.
385 * Return 0 on match, -ESTALE on mismatch or stale origin, < 0 on error.
386 */
387int ovl_verify_index(struct dentry *index, struct path *lowerstack,
388 unsigned int numlower)
389{
390 struct ovl_fh *fh = NULL;
391 size_t len;
392 struct path origin = { };
393 struct path *stack = &origin;
394 unsigned int ctr = 0;
395 int err;
396
397 if (!d_inode(index))
398 return 0;
399
400 err = -EISDIR;
401 if (d_is_dir(index))
402 goto fail;
403
404 err = -EINVAL;
405 if (index->d_name.len < sizeof(struct ovl_fh)*2)
406 goto fail;
407
408 err = -ENOMEM;
409 len = index->d_name.len / 2;
410 fh = kzalloc(len, GFP_TEMPORARY);
411 if (!fh)
412 goto fail;
413
414 err = -EINVAL;
415 if (hex2bin((u8 *)fh, index->d_name.name, len) || len != fh->len)
416 goto fail;
417
418 err = ovl_verify_origin_fh(index, fh);
419 if (err)
420 goto fail;
421
422 err = ovl_check_origin(index, lowerstack, numlower, &stack, &ctr);
423 if (!err && !ctr)
424 err = -ESTALE;
425 if (err)
426 goto fail;
427
428 dput(origin.dentry);
429out:
430 kfree(fh);
431 return err;
432
433fail:
434 pr_warn_ratelimited("overlayfs: failed to verify index (%pd2, err=%i)\n",
435 index, err);
436 goto out;
437}
438
439/*
382 * Lookup in indexdir for the index entry of a lower real inode or a copy up 440 * Lookup in indexdir for the index entry of a lower real inode or a copy up
383 * origin inode. The index entry name is the hex representation of the lower 441 * origin inode. The index entry name is the hex representation of the lower
384 * inode file handle. 442 * inode file handle.
@@ -541,8 +599,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
541 * number - it's the same as if we held a reference 599 * number - it's the same as if we held a reference
542 * to a dentry in lower layer that was moved under us. 600 * to a dentry in lower layer that was moved under us.
543 */ 601 */
544 err = ovl_check_origin(dentry, upperdentry, 602 err = ovl_check_origin(upperdentry, roe->lowerstack,
545 &stack, &ctr); 603 roe->numlower, &stack, &ctr);
546 if (err) 604 if (err)
547 goto out; 605 goto out;
548 } 606 }
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 437a0301e1b6..f3e49cf34517 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -237,6 +237,8 @@ static inline bool ovl_is_impuredir(struct dentry *dentry)
237/* namei.c */ 237/* namei.c */
238int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt, 238int ovl_verify_origin(struct dentry *dentry, struct vfsmount *mnt,
239 struct dentry *origin, bool is_upper, bool set); 239 struct dentry *origin, bool is_upper, bool set);
240int ovl_verify_index(struct dentry *index, struct path *lowerstack,
241 unsigned int numlower);
240int ovl_get_index_name(struct dentry *origin, struct qstr *name); 242int ovl_get_index_name(struct dentry *origin, struct qstr *name);
241int ovl_path_next(int idx, struct dentry *dentry, struct path *path); 243int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
242struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); 244struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags);
@@ -250,6 +252,8 @@ void ovl_cache_free(struct list_head *list);
250int ovl_check_d_type_supported(struct path *realpath); 252int ovl_check_d_type_supported(struct path *realpath);
251void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt, 253void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
252 struct dentry *dentry, int level); 254 struct dentry *dentry, int level);
255int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
256 struct path *lowerstack, unsigned int numlower);
253 257
254/* inode.c */ 258/* inode.c */
255int ovl_setattr(struct dentry *dentry, struct iattr *attr); 259int ovl_setattr(struct dentry *dentry, struct iattr *attr);
@@ -289,7 +293,7 @@ struct cattr {
289int ovl_create_real(struct inode *dir, struct dentry *newdentry, 293int ovl_create_real(struct inode *dir, struct dentry *newdentry,
290 struct cattr *attr, 294 struct cattr *attr,
291 struct dentry *hardlink, bool debug); 295 struct dentry *hardlink, bool debug);
292void ovl_cleanup(struct inode *dir, struct dentry *dentry); 296int ovl_cleanup(struct inode *dir, struct dentry *dentry);
293 297
294/* copy_up.c */ 298/* copy_up.c */
295int ovl_copy_up(struct dentry *dentry); 299int ovl_copy_up(struct dentry *dentry);
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index f241b4ee3d8a..0298463cf9c3 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -667,3 +667,53 @@ void ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
667 ovl_cleanup(dir, dentry); 667 ovl_cleanup(dir, dentry);
668 } 668 }
669} 669}
670
671int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
672 struct path *lowerstack, unsigned int numlower)
673{
674 int err;
675 struct inode *dir = dentry->d_inode;
676 struct path path = { .mnt = mnt, .dentry = dentry };
677 LIST_HEAD(list);
678 struct ovl_cache_entry *p;
679 struct ovl_readdir_data rdd = {
680 .ctx.actor = ovl_fill_merge,
681 .dentry = NULL,
682 .list = &list,
683 .root = RB_ROOT,
684 .is_lowest = false,
685 };
686
687 err = ovl_dir_read(&path, &rdd);
688 if (err)
689 goto out;
690
691 inode_lock_nested(dir, I_MUTEX_PARENT);
692 list_for_each_entry(p, &list, l_node) {
693 struct dentry *index;
694
695 if (p->name[0] == '.') {
696 if (p->len == 1)
697 continue;
698 if (p->len == 2 && p->name[1] == '.')
699 continue;
700 }
701 index = lookup_one_len(p->name, dentry, p->len);
702 if (IS_ERR(index)) {
703 err = PTR_ERR(index);
704 break;
705 }
706 if (ovl_verify_index(index, lowerstack, numlower)) {
707 err = ovl_cleanup(dir, index);
708 if (err)
709 break;
710 }
711 dput(index);
712 }
713 inode_unlock(dir);
714out:
715 ovl_cache_free(&list);
716 if (err)
717 pr_err("overlayfs: failed index dir cleanup (%i)\n", err);
718 return err;
719}
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index a313af25dac2..791581c370f5 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1068,6 +1068,12 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1068 upperpath.dentry, true, true); 1068 upperpath.dentry, true, true);
1069 if (err) 1069 if (err)
1070 pr_err("overlayfs: failed to verify index dir origin\n"); 1070 pr_err("overlayfs: failed to verify index dir origin\n");
1071
1072 /* Cleanup bad/stale index entries */
1073 if (!err)
1074 err = ovl_indexdir_cleanup(ufs->indexdir,
1075 ufs->upper_mnt,
1076 stack, numlower);
1071 } 1077 }
1072 if (err || !ufs->indexdir) 1078 if (err || !ufs->indexdir)
1073 pr_warn("overlayfs: try deleting index dir or mounting with '-o index=off' to disable inodes index.\n"); 1079 pr_warn("overlayfs: try deleting index dir or mounting with '-o index=off' to disable inodes index.\n");