aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-05-27 19:44:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-27 19:44:39 -0400
commit0121a32201dcc72933fb6019c41661e2f8a02fc5 (patch)
tree3e4944d4c1c7f1213413ac99f779629d67373c85 /fs/overlayfs
parent559b6d90a0beb375c46dffe18133012bfa29f441 (diff)
parent21765194cecf2e4514ad75244df459f188140a0f (diff)
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs update from Miklos Szeredi: "The meat of this is a change to use the mounter's credentials for operations that require elevated privileges (such as whiteout creation). This fixes behavior under user namespaces as well as being a nice cleanup" * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: Do d_type check only if work dir creation was successful ovl: update documentation ovl: override creds with the ones from the superblock mounter
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/copy_up.c26
-rw-r--r--fs/overlayfs/dir.c67
-rw-r--r--fs/overlayfs/overlayfs.h1
-rw-r--r--fs/overlayfs/readdir.c14
-rw-r--r--fs/overlayfs/super.c37
5 files changed, 38 insertions, 107 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index cc514da6f3e7..80aa6f1eb336 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -336,7 +336,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
336 struct dentry *upperdir; 336 struct dentry *upperdir;
337 struct dentry *upperdentry; 337 struct dentry *upperdentry;
338 const struct cred *old_cred; 338 const struct cred *old_cred;
339 struct cred *override_cred;
340 char *link = NULL; 339 char *link = NULL;
341 340
342 if (WARN_ON(!workdir)) 341 if (WARN_ON(!workdir))
@@ -357,28 +356,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
357 return PTR_ERR(link); 356 return PTR_ERR(link);
358 } 357 }
359 358
360 err = -ENOMEM; 359 old_cred = ovl_override_creds(dentry->d_sb);
361 override_cred = prepare_creds();
362 if (!override_cred)
363 goto out_free_link;
364
365 override_cred->fsuid = stat->uid;
366 override_cred->fsgid = stat->gid;
367 /*
368 * CAP_SYS_ADMIN for copying up extended attributes
369 * CAP_DAC_OVERRIDE for create
370 * CAP_FOWNER for chmod, timestamp update
371 * CAP_FSETID for chmod
372 * CAP_CHOWN for chown
373 * CAP_MKNOD for mknod
374 */
375 cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
376 cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
377 cap_raise(override_cred->cap_effective, CAP_FOWNER);
378 cap_raise(override_cred->cap_effective, CAP_FSETID);
379 cap_raise(override_cred->cap_effective, CAP_CHOWN);
380 cap_raise(override_cred->cap_effective, CAP_MKNOD);
381 old_cred = override_creds(override_cred);
382 360
383 err = -EIO; 361 err = -EIO;
384 if (lock_rename(workdir, upperdir) != NULL) { 362 if (lock_rename(workdir, upperdir) != NULL) {
@@ -401,9 +379,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
401out_unlock: 379out_unlock:
402 unlock_rename(workdir, upperdir); 380 unlock_rename(workdir, upperdir);
403 revert_creds(old_cred); 381 revert_creds(old_cred);
404 put_cred(override_cred);
405 382
406out_free_link:
407 if (link) 383 if (link)
408 free_page((unsigned long) link); 384 free_page((unsigned long) link);
409 385
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index b3fc0a35bf62..22f0253a3567 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -405,28 +405,13 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
405 err = ovl_create_upper(dentry, inode, &stat, link, hardlink); 405 err = ovl_create_upper(dentry, inode, &stat, link, hardlink);
406 } else { 406 } else {
407 const struct cred *old_cred; 407 const struct cred *old_cred;
408 struct cred *override_cred;
409 408
410 err = -ENOMEM; 409 old_cred = ovl_override_creds(dentry->d_sb);
411 override_cred = prepare_creds();
412 if (!override_cred)
413 goto out_iput;
414
415 /*
416 * CAP_SYS_ADMIN for setting opaque xattr
417 * CAP_DAC_OVERRIDE for create in workdir, rename
418 * CAP_FOWNER for removing whiteout from sticky dir
419 */
420 cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
421 cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
422 cap_raise(override_cred->cap_effective, CAP_FOWNER);
423 old_cred = override_creds(override_cred);
424 410
425 err = ovl_create_over_whiteout(dentry, inode, &stat, link, 411 err = ovl_create_over_whiteout(dentry, inode, &stat, link,
426 hardlink); 412 hardlink);
427 413
428 revert_creds(old_cred); 414 revert_creds(old_cred);
429 put_cred(override_cred);
430 } 415 }
431 416
432 if (!err) 417 if (!err)
@@ -662,32 +647,11 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
662 if (OVL_TYPE_PURE_UPPER(type)) { 647 if (OVL_TYPE_PURE_UPPER(type)) {
663 err = ovl_remove_upper(dentry, is_dir); 648 err = ovl_remove_upper(dentry, is_dir);
664 } else { 649 } else {
665 const struct cred *old_cred; 650 const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
666 struct cred *override_cred;
667
668 err = -ENOMEM;
669 override_cred = prepare_creds();
670 if (!override_cred)
671 goto out_drop_write;
672
673 /*
674 * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
675 * CAP_DAC_OVERRIDE for create in workdir, rename
676 * CAP_FOWNER for removing whiteout from sticky dir
677 * CAP_FSETID for chmod of opaque dir
678 * CAP_CHOWN for chown of opaque dir
679 */
680 cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
681 cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
682 cap_raise(override_cred->cap_effective, CAP_FOWNER);
683 cap_raise(override_cred->cap_effective, CAP_FSETID);
684 cap_raise(override_cred->cap_effective, CAP_CHOWN);
685 old_cred = override_creds(override_cred);
686 651
687 err = ovl_remove_and_whiteout(dentry, is_dir); 652 err = ovl_remove_and_whiteout(dentry, is_dir);
688 653
689 revert_creds(old_cred); 654 revert_creds(old_cred);
690 put_cred(override_cred);
691 } 655 }
692out_drop_write: 656out_drop_write:
693 ovl_drop_write(dentry); 657 ovl_drop_write(dentry);
@@ -725,7 +689,6 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
725 bool new_is_dir = false; 689 bool new_is_dir = false;
726 struct dentry *opaquedir = NULL; 690 struct dentry *opaquedir = NULL;
727 const struct cred *old_cred = NULL; 691 const struct cred *old_cred = NULL;
728 struct cred *override_cred = NULL;
729 692
730 err = -EINVAL; 693 err = -EINVAL;
731 if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE)) 694 if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
@@ -794,26 +757,8 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
794 old_opaque = !OVL_TYPE_PURE_UPPER(old_type); 757 old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
795 new_opaque = !OVL_TYPE_PURE_UPPER(new_type); 758 new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
796 759
797 if (old_opaque || new_opaque) { 760 if (old_opaque || new_opaque)
798 err = -ENOMEM; 761 old_cred = ovl_override_creds(old->d_sb);
799 override_cred = prepare_creds();
800 if (!override_cred)
801 goto out_drop_write;
802
803 /*
804 * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
805 * CAP_DAC_OVERRIDE for create in workdir
806 * CAP_FOWNER for removing whiteout from sticky dir
807 * CAP_FSETID for chmod of opaque dir
808 * CAP_CHOWN for chown of opaque dir
809 */
810 cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
811 cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
812 cap_raise(override_cred->cap_effective, CAP_FOWNER);
813 cap_raise(override_cred->cap_effective, CAP_FSETID);
814 cap_raise(override_cred->cap_effective, CAP_CHOWN);
815 old_cred = override_creds(override_cred);
816 }
817 762
818 if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) { 763 if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
819 opaquedir = ovl_check_empty_and_clear(new); 764 opaquedir = ovl_check_empty_and_clear(new);
@@ -943,10 +888,8 @@ out_dput_old:
943out_unlock: 888out_unlock:
944 unlock_rename(new_upperdir, old_upperdir); 889 unlock_rename(new_upperdir, old_upperdir);
945out_revert_creds: 890out_revert_creds:
946 if (old_opaque || new_opaque) { 891 if (old_opaque || new_opaque)
947 revert_creds(old_cred); 892 revert_creds(old_cred);
948 put_cred(override_cred);
949 }
950out_drop_write: 893out_drop_write:
951 ovl_drop_write(old); 894 ovl_drop_write(old);
952out: 895out:
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 99ec4b035237..724f5fcb4e24 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -153,6 +153,7 @@ void ovl_drop_write(struct dentry *dentry);
153bool ovl_dentry_is_opaque(struct dentry *dentry); 153bool ovl_dentry_is_opaque(struct dentry *dentry);
154void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque); 154void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
155bool ovl_is_whiteout(struct dentry *dentry); 155bool ovl_is_whiteout(struct dentry *dentry);
156const struct cred *ovl_override_creds(struct super_block *sb);
156void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); 157void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
157struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, 158struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
158 unsigned int flags); 159 unsigned int flags);
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index da186ee4f846..d11ae826bcbc 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -36,6 +36,7 @@ struct ovl_dir_cache {
36 36
37struct ovl_readdir_data { 37struct ovl_readdir_data {
38 struct dir_context ctx; 38 struct dir_context ctx;
39 struct dentry *dentry;
39 bool is_lowest; 40 bool is_lowest;
40 struct rb_root root; 41 struct rb_root root;
41 struct list_head *list; 42 struct list_head *list;
@@ -206,17 +207,8 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
206 struct ovl_cache_entry *p; 207 struct ovl_cache_entry *p;
207 struct dentry *dentry; 208 struct dentry *dentry;
208 const struct cred *old_cred; 209 const struct cred *old_cred;
209 struct cred *override_cred;
210
211 override_cred = prepare_creds();
212 if (!override_cred)
213 return -ENOMEM;
214 210
215 /* 211 old_cred = ovl_override_creds(rdd->dentry->d_sb);
216 * CAP_DAC_OVERRIDE for lookup
217 */
218 cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
219 old_cred = override_creds(override_cred);
220 212
221 inode_lock(dir->d_inode); 213 inode_lock(dir->d_inode);
222 err = 0; 214 err = 0;
@@ -234,7 +226,6 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
234 inode_unlock(dir->d_inode); 226 inode_unlock(dir->d_inode);
235 } 227 }
236 revert_creds(old_cred); 228 revert_creds(old_cred);
237 put_cred(override_cred);
238 229
239 return err; 230 return err;
240} 231}
@@ -290,6 +281,7 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
290 struct path realpath; 281 struct path realpath;
291 struct ovl_readdir_data rdd = { 282 struct ovl_readdir_data rdd = {
292 .ctx.actor = ovl_fill_merge, 283 .ctx.actor = ovl_fill_merge,
284 .dentry = dentry,
293 .list = list, 285 .list = list,
294 .root = RB_ROOT, 286 .root = RB_ROOT,
295 .is_lowest = false, 287 .is_lowest = false,
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index ed53ae0fe868..ce02f46029da 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -42,6 +42,8 @@ struct ovl_fs {
42 long lower_namelen; 42 long lower_namelen;
43 /* pathnames of lower and upper dirs, for show_options */ 43 /* pathnames of lower and upper dirs, for show_options */
44 struct ovl_config config; 44 struct ovl_config config;
45 /* creds of process who forced instantiation of super block */
46 const struct cred *creator_cred;
45}; 47};
46 48
47struct ovl_dir_cache; 49struct ovl_dir_cache;
@@ -265,6 +267,13 @@ bool ovl_is_whiteout(struct dentry *dentry)
265 return inode && IS_WHITEOUT(inode); 267 return inode && IS_WHITEOUT(inode);
266} 268}
267 269
270const struct cred *ovl_override_creds(struct super_block *sb)
271{
272 struct ovl_fs *ofs = sb->s_fs_info;
273
274 return override_creds(ofs->creator_cred);
275}
276
268static bool ovl_is_opaquedir(struct dentry *dentry) 277static bool ovl_is_opaquedir(struct dentry *dentry)
269{ 278{
270 int res; 279 int res;
@@ -603,6 +612,7 @@ static void ovl_put_super(struct super_block *sb)
603 kfree(ufs->config.lowerdir); 612 kfree(ufs->config.lowerdir);
604 kfree(ufs->config.upperdir); 613 kfree(ufs->config.upperdir);
605 kfree(ufs->config.workdir); 614 kfree(ufs->config.workdir);
615 put_cred(ufs->creator_cred);
606 kfree(ufs); 616 kfree(ufs);
607} 617}
608 618
@@ -1064,16 +1074,19 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1064 /* 1074 /*
1065 * Upper should support d_type, else whiteouts are visible. 1075 * Upper should support d_type, else whiteouts are visible.
1066 * Given workdir and upper are on same fs, we can do 1076 * Given workdir and upper are on same fs, we can do
1067 * iterate_dir() on workdir. 1077 * iterate_dir() on workdir. This check requires successful
1078 * creation of workdir in previous step.
1068 */ 1079 */
1069 err = ovl_check_d_type_supported(&workpath); 1080 if (ufs->workdir) {
1070 if (err < 0) 1081 err = ovl_check_d_type_supported(&workpath);
1071 goto out_put_workdir; 1082 if (err < 0)
1083 goto out_put_workdir;
1072 1084
1073 if (!err) { 1085 if (!err) {
1074 pr_err("overlayfs: upper fs needs to support d_type.\n"); 1086 pr_err("overlayfs: upper fs needs to support d_type.\n");
1075 err = -EINVAL; 1087 err = -EINVAL;
1076 goto out_put_workdir; 1088 goto out_put_workdir;
1089 }
1077 } 1090 }
1078 } 1091 }
1079 1092
@@ -1108,10 +1121,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1108 else 1121 else
1109 sb->s_d_op = &ovl_dentry_operations; 1122 sb->s_d_op = &ovl_dentry_operations;
1110 1123
1124 ufs->creator_cred = prepare_creds();
1125 if (!ufs->creator_cred)
1126 goto out_put_lower_mnt;
1127
1111 err = -ENOMEM; 1128 err = -ENOMEM;
1112 oe = ovl_alloc_entry(numlower); 1129 oe = ovl_alloc_entry(numlower);
1113 if (!oe) 1130 if (!oe)
1114 goto out_put_lower_mnt; 1131 goto out_put_cred;
1115 1132
1116 root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe)); 1133 root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));
1117 if (!root_dentry) 1134 if (!root_dentry)
@@ -1144,6 +1161,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1144 1161
1145out_free_oe: 1162out_free_oe:
1146 kfree(oe); 1163 kfree(oe);
1164out_put_cred:
1165 put_cred(ufs->creator_cred);
1147out_put_lower_mnt: 1166out_put_lower_mnt:
1148 for (i = 0; i < ufs->numlower; i++) 1167 for (i = 0; i < ufs->numlower; i++)
1149 mntput(ufs->lower_mnt[i]); 1168 mntput(ufs->lower_mnt[i]);