Skip to content

Commit e9f57eb

Browse files
committed
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
2 parents 5c89e9e + 84889d4 commit e9f57eb

File tree

6 files changed

+101
-18
lines changed

6 files changed

+101
-18
lines changed

fs/overlayfs/copy_up.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@
2222

2323
int ovl_copy_xattr(struct dentry *old, struct dentry *new)
2424
{
25-
ssize_t list_size, size;
26-
char *buf, *name, *value;
27-
int error;
25+
ssize_t list_size, size, value_size = 0;
26+
char *buf, *name, *value = NULL;
27+
int uninitialized_var(error);
2828

2929
if (!old->d_inode->i_op->getxattr ||
3030
!new->d_inode->i_op->getxattr)
@@ -41,29 +41,40 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
4141
if (!buf)
4242
return -ENOMEM;
4343

44-
error = -ENOMEM;
45-
value = kmalloc(XATTR_SIZE_MAX, GFP_KERNEL);
46-
if (!value)
47-
goto out;
48-
4944
list_size = vfs_listxattr(old, buf, list_size);
5045
if (list_size <= 0) {
5146
error = list_size;
52-
goto out_free_value;
47+
goto out;
5348
}
5449

5550
for (name = buf; name < (buf + list_size); name += strlen(name) + 1) {
56-
size = vfs_getxattr(old, name, value, XATTR_SIZE_MAX);
57-
if (size <= 0) {
51+
retry:
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) {
5857
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;
6072
}
73+
6174
error = vfs_setxattr(new, name, value, size, 0);
6275
if (error)
63-
goto out_free_value;
76+
break;
6477
}
65-
66-
out_free_value:
6778
kfree(value);
6879
out:
6980
kfree(buf);

fs/overlayfs/inode.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,19 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
4242
int err;
4343
struct dentry *upperdentry;
4444

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+
4558
err = ovl_want_write(dentry);
4659
if (err)
4760
goto out;
@@ -95,6 +108,29 @@ int ovl_permission(struct inode *inode, int mask)
95108

96109
realdentry = ovl_entry_real(oe, &is_upper);
97110

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+
98134
/* Careful in RCU walk mode */
99135
realinode = ACCESS_ONCE(realdentry->d_inode);
100136
if (!realinode) {

fs/overlayfs/overlayfs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,10 @@ struct dentry *ovl_dentry_upper(struct dentry *dentry);
142142
struct dentry *ovl_dentry_lower(struct dentry *dentry);
143143
struct dentry *ovl_dentry_real(struct dentry *dentry);
144144
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);
145147
struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
148+
bool ovl_is_default_permissions(struct inode *inode);
146149
void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache);
147150
struct dentry *ovl_workdir(struct dentry *dentry);
148151
int ovl_want_write(struct dentry *dentry);

fs/overlayfs/readdir.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,8 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
571571
(int) PTR_ERR(dentry));
572572
continue;
573573
}
574-
ovl_cleanup(upper->d_inode, dentry);
574+
if (dentry->d_inode)
575+
ovl_cleanup(upper->d_inode, dentry);
575576
dput(dentry);
576577
}
577578
mutex_unlock(&upper->d_inode->i_mutex);

fs/overlayfs/super.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <linux/fs.h>
1111
#include <linux/namei.h>
12+
#include <linux/pagemap.h>
1213
#include <linux/xattr.h>
1314
#include <linux/security.h>
1415
#include <linux/mount.h>
@@ -24,12 +25,11 @@ MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
2425
MODULE_DESCRIPTION("Overlay filesystem");
2526
MODULE_LICENSE("GPL");
2627

27-
#define OVERLAYFS_SUPER_MAGIC 0x794c7630
28-
2928
struct ovl_config {
3029
char *lowerdir;
3130
char *upperdir;
3231
char *workdir;
32+
bool default_permissions;
3333
};
3434

3535
/* private information held for overlayfs's superblock */
@@ -154,13 +154,32 @@ struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper)
154154
return realdentry;
155155
}
156156

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+
157169
struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry)
158170
{
159171
struct ovl_entry *oe = dentry->d_fsdata;
160172

161173
return oe->cache;
162174
}
163175

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+
164183
void ovl_set_dir_cache(struct dentry *dentry, struct ovl_dir_cache *cache)
165184
{
166185
struct ovl_entry *oe = dentry->d_fsdata;
@@ -594,6 +613,8 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry)
594613
seq_show_option(m, "upperdir", ufs->config.upperdir);
595614
seq_show_option(m, "workdir", ufs->config.workdir);
596615
}
616+
if (ufs->config.default_permissions)
617+
seq_puts(m, ",default_permissions");
597618
return 0;
598619
}
599620

@@ -618,13 +639,15 @@ enum {
618639
OPT_LOWERDIR,
619640
OPT_UPPERDIR,
620641
OPT_WORKDIR,
642+
OPT_DEFAULT_PERMISSIONS,
621643
OPT_ERR,
622644
};
623645

624646
static const match_table_t ovl_tokens = {
625647
{OPT_LOWERDIR, "lowerdir=%s"},
626648
{OPT_UPPERDIR, "upperdir=%s"},
627649
{OPT_WORKDIR, "workdir=%s"},
650+
{OPT_DEFAULT_PERMISSIONS, "default_permissions"},
628651
{OPT_ERR, NULL}
629652
};
630653

@@ -685,6 +708,10 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
685708
return -ENOMEM;
686709
break;
687710

711+
case OPT_DEFAULT_PERMISSIONS:
712+
config->default_permissions = true;
713+
break;
714+
688715
default:
689716
pr_err("overlayfs: unrecognized mount option \"%s\" or missing value\n", p);
690717
return -EINVAL;
@@ -910,6 +937,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
910937
}
911938

912939
sb->s_stack_depth = 0;
940+
sb->s_maxbytes = MAX_LFS_FILESIZE;
913941
if (ufs->config.upperdir) {
914942
if (!ufs->config.workdir) {
915943
pr_err("overlayfs: missing 'workdir'\n");
@@ -1053,6 +1081,9 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
10531081

10541082
root_dentry->d_fsdata = oe;
10551083

1084+
ovl_copyattr(ovl_dentry_real(root_dentry)->d_inode,
1085+
root_dentry->d_inode);
1086+
10561087
sb->s_magic = OVERLAYFS_SUPER_MAGIC;
10571088
sb->s_op = &ovl_super_operations;
10581089
sb->s_root = root_dentry;

include/uapi/linux/magic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#define PSTOREFS_MAGIC 0x6165676C
3232
#define EFIVARFS_MAGIC 0xde5e81e4
3333
#define HOSTFS_SUPER_MAGIC 0x00c0ffee
34+
#define OVERLAYFS_SUPER_MAGIC 0x794c7630
3435

3536
#define MINIX_SUPER_MAGIC 0x137F /* minix v1 fs, 14 char names */
3637
#define MINIX_SUPER_MAGIC2 0x138F /* minix v1 fs, 30 char names */

0 commit comments

Comments
 (0)