aboutsummaryrefslogtreecommitdiffstats
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
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
-rw-r--r--Documentation/filesystems/overlayfs.txt9
-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
6 files changed, 38 insertions, 116 deletions
diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt
index 28091457b71a..d6259c786316 100644
--- a/Documentation/filesystems/overlayfs.txt
+++ b/Documentation/filesystems/overlayfs.txt
@@ -194,15 +194,6 @@ If a file with multiple hard links is copied up, then this will
194"break" the link. Changes will not be propagated to other names 194"break" the link. Changes will not be propagated to other names
195referring to the same inode. 195referring to the same inode.
196 196
197Symlinks in /proc/PID/ and /proc/PID/fd which point to a non-directory
198object in overlayfs will not contain valid absolute paths, only
199relative paths leading up to the filesystem's root. This will be
200fixed in the future.
201
202Some operations are not atomic, for example a crash during copy_up or
203rename will leave the filesystem in an inconsistent state. This will
204be addressed in the future.
205
206Changes to underlying filesystems 197Changes to underlying filesystems
207--------------------------------- 198---------------------------------
208 199
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]);