aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-21 15:20:46 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-21 15:20:46 -0500
commite9f57ebcba563e0cd532926cab83c92bb4d79360 (patch)
tree6cf11baa7851129145cc35f9218583287f41dd64 /fs/overlayfs
parent5c89e9ea7ef1feaa147325b2ab47a89a147fb903 (diff)
parent84889d49335627bc770b32787c1ef9ebad1da232 (diff)
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs updates from Miklos Szeredi: "This contains several bug fixes and a new mount option 'default_permissions' that allows read-only exported NFS filesystems to be used as lower layer" * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: check dentry positiveness in ovl_cleanup_whiteouts() ovl: setattr: check permissions before copy-up ovl: root: copy attr ovl: move super block magic number to magic.h ovl: use a minimal buffer in ovl_copy_xattr ovl: allow zero size xattr ovl: default permissions
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/copy_up.c41
-rw-r--r--fs/overlayfs/inode.c36
-rw-r--r--fs/overlayfs/overlayfs.h3
-rw-r--r--fs/overlayfs/readdir.c3
-rw-r--r--fs/overlayfs/super.c35
5 files changed, 100 insertions, 18 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 0a8983492d91..eff6319d5037 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -22,9 +22,9 @@
22 22
23int ovl_copy_xattr(struct dentry *old, struct dentry *new) 23int ovl_copy_xattr(struct dentry *old, struct dentry *new)
24{ 24{
25 ssize_t list_size, size; 25 ssize_t list_size, size, value_size = 0;
26 char *buf, *name, *value; 26 char *buf, *name, *value = NULL;
27 int error; 27 int uninitialized_var(error);
28 28
29 if (!old->d_inode->i_op->getxattr || 29 if (!old->d_inode->i_op->getxattr ||
30 !new->d_inode->i_op->getxattr) 30 !new->d_inode->i_op->getxattr)
@@ -41,29 +41,40 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
41 if (!buf) 41 if (!buf)
42 return -ENOMEM; 42 return -ENOMEM;
43 43
44 error = -ENOMEM;
45 value = kmalloc(XATTR_SIZE_MAX, GFP_KERNEL);
46 if (!value)
47 goto out;
48
49 list_size = vfs_listxattr(old, buf, list_size); 44 list_size = vfs_listxattr(old, buf, list_size);
50 if (list_size <= 0) { 45 if (list_size <= 0) {
51 error = list_size; 46 error = list_size;
52 goto out_free_value; 47 goto out;
53 } 48 }
54 49
55 for (name = buf; name < (buf + list_size); name += strlen(name) + 1) { 50 for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
56 size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX); 51retry:
57 if (size <= 0) { 52 size = vfs_getxattr(old, name, value, value_size);
53 if (size == -ERANGE)
54 size = vfs_getxattr(old, name, NULL, 0);
55
56 if (size < 0) {
58 error = size; 57 error = size;
59 goto out_free_value; 58 break;
59 }
60
61 if (size > value_size) {
62 void *new;
63
64 new = krealloc(value, size, GFP_KERNEL);
65 if (!new) {
66 error = -ENOMEM;
67 break;
68 }
69 value = new;
70 value_size = size;
71 goto retry;
60 } 72 }
73
61 error = vfs_setxattr(new, name, value, size, 0); 74 error = vfs_setxattr(new, name, value, size, 0);
62 if (error) 75 if (error)
63 goto out_free_value; 76 break;
64 } 77 }
65
66out_free_value:
67 kfree(value); 78 kfree(value);
68out: 79out:
69 kfree(buf); 80 kfree(buf);
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 964a60fa7afc..bf996e574f3d 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -42,6 +42,19 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
42 int err; 42 int err;
43 struct dentry *upperdentry; 43 struct dentry *upperdentry;
44 44
45 /*
46 * Check for permissions before trying to copy-up. This is redundant
47 * since it will be rechecked later by ->setattr() on upper dentry. But
48 * without this, copy-up can be triggered by just about anybody.
49 *
50 * We don't initialize inode->size, which just means that
51 * inode_newsize_ok() will always check against MAX_LFS_FILESIZE and not
52 * check for a swapfile (which this won't be anyway).
53 */
54 err = inode_change_ok(dentry->d_inode, attr);
55 if (err)
56 return err;
57
45 err = ovl_want_write(dentry); 58 err = ovl_want_write(dentry);
46 if (err) 59 if (err)
47 goto out; 60 goto out;
@@ -95,6 +108,29 @@ int ovl_permission(struct inode *inode, int mask)
95 108
96 realdentry = ovl_entry_real(oe, &is_upper); 109 realdentry = ovl_entry_real(oe, &is_upper);
97 110
111 if (ovl_is_default_permissions(inode)) {
112 struct kstat stat;
113 struct path realpath = { .dentry = realdentry };
114
115 if (mask & MAY_NOT_BLOCK)
116 return -ECHILD;
117
118 realpath.mnt = ovl_entry_mnt_real(oe, inode, is_upper);
119
120 err = vfs_getattr(&realpath, &stat);
121 if (err)
122 return err;
123
124 if ((stat.mode ^ inode->i_mode) & S_IFMT)
125 return -ESTALE;
126
127 inode->i_mode = stat.mode;
128 inode->i_uid = stat.uid;
129 inode->i_gid = stat.gid;
130
131 return generic_permission(inode, mask);
132 }
133
98 /* Careful in RCU walk mode */ 134 /* Careful in RCU walk mode */
99 realinode = ACCESS_ONCE(realdentry->d_inode); 135 realinode = ACCESS_ONCE(realdentry->d_inode);
100 if (!realinode) { 136 if (!realinode) {
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index e17154aeaae4..99b4168c36ff 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -142,7 +142,10 @@ struct dentry *ovl_dentry_upper(struct dentry *dentry);
142struct dentry *ovl_dentry_lower(struct dentry *dentry); 142struct dentry *ovl_dentry_lower(struct dentry *dentry);
143struct dentry *ovl_dentry_real(struct dentry *dentry); 143struct dentry *ovl_dentry_real(struct dentry *dentry);
144struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper); 144struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper);
145struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode,
146 bool is_upper);
145struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry); 147struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
148bool ovl_is_default_permissions(struct inode *inode);
146void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache); 149void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache);
147struct dentry *ovl_workdir(struct dentry *dentry); 150struct dentry *ovl_workdir(struct dentry *dentry);
148int ovl_want_write(struct dentry *dentry); 151int ovl_want_write(struct dentry *dentry);
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 70e9af551600..adcb1398c481 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -571,7 +571,8 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
571 (int) PTR_ERR(dentry)); 571 (int) PTR_ERR(dentry));
572 continue; 572 continue;
573 } 573 }
574 ovl_cleanup(upper->d_inode, dentry); 574 if (dentry->d_inode)
575 ovl_cleanup(upper->d_inode, dentry);
575 dput(dentry); 576 dput(dentry);
576 } 577 }
577 mutex_unlock(&upper->d_inode->i_mutex); 578 mutex_unlock(&upper->d_inode->i_mutex);
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index e38ee0fed24a..a4cbdf9824c7 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -9,6 +9,7 @@
9 9
10#include <linux/fs.h> 10#include <linux/fs.h>
11#include <linux/namei.h> 11#include <linux/namei.h>
12#include <linux/pagemap.h>
12#include <linux/xattr.h> 13#include <linux/xattr.h>
13#include <linux/security.h> 14#include <linux/security.h>
14#include <linux/mount.h> 15#include <linux/mount.h>
@@ -24,12 +25,11 @@ MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
24MODULE_DESCRIPTION("Overlay filesystem"); 25MODULE_DESCRIPTION("Overlay filesystem");
25MODULE_LICENSE("GPL"); 26MODULE_LICENSE("GPL");
26 27
27#define OVERLAYFS_SUPER_MAGIC 0x794c7630
28
29struct ovl_config { 28struct ovl_config {
30 char *lowerdir; 29 char *lowerdir;
31 char *upperdir; 30 char *upperdir;
32 char *workdir; 31 char *workdir;
32 bool default_permissions;
33}; 33};
34 34
35/* private information held for overlayfs's superblock */ 35/* private information held for overlayfs's superblock */
@@ -154,6 +154,18 @@ struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper)
154 return realdentry; 154 return realdentry;
155} 155}
156 156
157struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode,
158 bool is_upper)
159{
160 if (is_upper) {
161 struct ovl_fs *ofs = inode->i_sb->s_fs_info;
162
163 return ofs->upper_mnt;
164 } else {
165 return oe->numlower ? oe->lowerstack[0].mnt : NULL;
166 }
167}
168
157struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry) 169struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry)
158{ 170{
159 struct ovl_entry *oe = dentry->d_fsdata; 171 struct ovl_entry *oe = dentry->d_fsdata;
@@ -161,6 +173,13 @@ struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry)
161 return oe->cache; 173 return oe->cache;
162} 174}
163 175
176bool ovl_is_default_permissions(struct inode *inode)
177{
178 struct ovl_fs *ofs = inode->i_sb->s_fs_info;
179
180 return ofs->config.default_permissions;
181}
182
164void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache) 183void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache)
165{ 184{
166 struct ovl_entry *oe = dentry->d_fsdata; 185 struct ovl_entry *oe = dentry->d_fsdata;
@@ -594,6 +613,8 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry)
594 seq_show_option(m, "upperdir", ufs->config.upperdir); 613 seq_show_option(m, "upperdir", ufs->config.upperdir);
595 seq_show_option(m, "workdir", ufs->config.workdir); 614 seq_show_option(m, "workdir", ufs->config.workdir);
596 } 615 }
616 if (ufs->config.default_permissions)
617 seq_puts(m, ",default_permissions");
597 return 0; 618 return 0;
598} 619}
599 620
@@ -618,6 +639,7 @@ enum {
618 OPT_LOWERDIR, 639 OPT_LOWERDIR,
619 OPT_UPPERDIR, 640 OPT_UPPERDIR,
620 OPT_WORKDIR, 641 OPT_WORKDIR,
642 OPT_DEFAULT_PERMISSIONS,
621 OPT_ERR, 643 OPT_ERR,
622}; 644};
623 645
@@ -625,6 +647,7 @@ static const match_table_t ovl_tokens = {
625 {OPT_LOWERDIR, "lowerdir=%s"}, 647 {OPT_LOWERDIR, "lowerdir=%s"},
626 {OPT_UPPERDIR, "upperdir=%s"}, 648 {OPT_UPPERDIR, "upperdir=%s"},
627 {OPT_WORKDIR, "workdir=%s"}, 649 {OPT_WORKDIR, "workdir=%s"},
650 {OPT_DEFAULT_PERMISSIONS, "default_permissions"},
628 {OPT_ERR, NULL} 651 {OPT_ERR, NULL}
629}; 652};
630 653
@@ -685,6 +708,10 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
685 return -ENOMEM; 708 return -ENOMEM;
686 break; 709 break;
687 710
711 case OPT_DEFAULT_PERMISSIONS:
712 config->default_permissions = true;
713 break;
714
688 default: 715 default:
689 pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p); 716 pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p);
690 return -EINVAL; 717 return -EINVAL;
@@ -910,6 +937,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
910 } 937 }
911 938
912 sb->s_stack_depth = 0; 939 sb->s_stack_depth = 0;
940 sb->s_maxbytes = MAX_LFS_FILESIZE;
913 if (ufs->config.upperdir) { 941 if (ufs->config.upperdir) {
914 if (!ufs->config.workdir) { 942 if (!ufs->config.workdir) {
915 pr_err("overlayfs: missing 'workdir'\n"); 943 pr_err("overlayfs: missing 'workdir'\n");
@@ -1053,6 +1081,9 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1053 1081
1054 root_dentry->d_fsdata = oe; 1082 root_dentry->d_fsdata = oe;
1055 1083
1084 ovl_copyattr(ovl_dentry_real(root_dentry)->d_inode,
1085 root_dentry->d_inode);
1086
1056 sb->s_magic = OVERLAYFS_SUPER_MAGIC; 1087 sb->s_magic = OVERLAYFS_SUPER_MAGIC;
1057 sb->s_op = &ovl_super_operations; 1088 sb->s_op = &ovl_super_operations;
1058 sb->s_root = root_dentry; 1089 sb->s_root = root_dentry;