diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-21 15:20:46 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-21 15:20:46 -0500 |
commit | e9f57ebcba563e0cd532926cab83c92bb4d79360 (patch) | |
tree | 6cf11baa7851129145cc35f9218583287f41dd64 /fs/overlayfs | |
parent | 5c89e9ea7ef1feaa147325b2ab47a89a147fb903 (diff) | |
parent | 84889d49335627bc770b32787c1ef9ebad1da232 (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.c | 41 | ||||
-rw-r--r-- | fs/overlayfs/inode.c | 36 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 3 | ||||
-rw-r--r-- | fs/overlayfs/readdir.c | 3 | ||||
-rw-r--r-- | fs/overlayfs/super.c | 35 |
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 | ||
23 | int ovl_copy_xattr(struct dentry *old, struct dentry *new) | 23 | int 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); | 51 | retry: |
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 | |||
66 | out_free_value: | ||
67 | kfree(value); | 78 | kfree(value); |
68 | out: | 79 | out: |
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); | |||
142 | struct dentry *ovl_dentry_lower(struct dentry *dentry); | 142 | struct dentry *ovl_dentry_lower(struct dentry *dentry); |
143 | struct dentry *ovl_dentry_real(struct dentry *dentry); | 143 | struct dentry *ovl_dentry_real(struct dentry *dentry); |
144 | struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper); | 144 | struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper); |
145 | struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode, | ||
146 | bool is_upper); | ||
145 | struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry); | 147 | struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry); |
148 | bool ovl_is_default_permissions(struct inode *inode); | ||
146 | void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache); | 149 | void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache); |
147 | struct dentry *ovl_workdir(struct dentry *dentry); | 150 | struct dentry *ovl_workdir(struct dentry *dentry); |
148 | int ovl_want_write(struct dentry *dentry); | 151 | int 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>"); | |||
24 | MODULE_DESCRIPTION("Overlay filesystem"); | 25 | MODULE_DESCRIPTION("Overlay filesystem"); |
25 | MODULE_LICENSE("GPL"); | 26 | MODULE_LICENSE("GPL"); |
26 | 27 | ||
27 | #define OVERLAYFS_SUPER_MAGIC 0x794c7630 | ||
28 | |||
29 | struct ovl_config { | 28 | struct 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 | ||
157 | struct 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 | |||
157 | struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry) | 169 | struct 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 | ||
176 | bool 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 | |||
164 | void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache) | 183 | void 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; |