1 From 3fe6e52f062643676eb4518d68cee3bc1272091b Mon Sep 17 00:00:00 2001
2 From: Antonio Murdaca <amurdaca@redhat.com>
3 Date: Thu, 7 Apr 2016 15:48:25 +0200
4 Subject: [PATCH] ovl: override creds with the ones from the superblock mounter
6 In user namespace the whiteout creation fails with -EPERM because the
7 current process isn't capable(CAP_SYS_ADMIN) when setting xattr.
11 $ mkdir upper lower work merged lower/dir
12 $ sudo mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged
13 $ unshare -m -p -f -U -r bash
15 Now as root in the user namespace:
17 \# touch merged/dir/{1,2,3} # this will force a copy up of lower/dir
20 This ends up failing with -EPERM after the files in dir has been
23 unlinkat(4, "2", 0) = 0
24 unlinkat(4, "1", 0) = 0
25 unlinkat(4, "3", 0) = 0
27 unlinkat(AT_FDCWD, "merged/dir", AT_REMOVEDIR) = -1 EPERM (Operation not
30 Interestingly, if you don't place files in merged/dir you can remove it,
31 meaning if upper/dir does not exist, creating the char device file works
32 properly in that same location.
34 This patch uses ovl_sb_creator_cred() to get the cred struct from the
35 superblock mounter and override the old cred with these new ones so that
36 the whiteout creation is possible because overlay is wrong in assuming that
37 the creds it will get with prepare_creds will be in the initial user
38 namespace. The old cap_raise game is removed in favor of just overriding
41 This patch also drops from ovl_copy_up_one() the following two lines:
43 override_cred->fsuid = stat->uid;
44 override_cred->fsgid = stat->gid;
46 This is because the correct uid and gid are taken directly with the stat
47 struct and correctly set with ovl_set_attr().
49 Signed-off-by: Antonio Murdaca <runcom@redhat.com>
50 Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
52 fs/overlayfs/copy_up.c | 26 +------------------
53 fs/overlayfs/dir.c | 67 ++++--------------------------------------------
54 fs/overlayfs/overlayfs.h | 1 +
55 fs/overlayfs/readdir.c | 14 +++-------
56 fs/overlayfs/super.c | 18 ++++++++++++-
57 5 files changed, 27 insertions(+), 99 deletions(-)
59 --- a/fs/overlayfs/copy_up.c
60 +++ b/fs/overlayfs/copy_up.c
61 @@ -317,7 +317,6 @@ int ovl_copy_up_one(struct dentry *paren
62 struct dentry *upperdir;
63 struct dentry *upperdentry;
64 const struct cred *old_cred;
65 - struct cred *override_cred;
68 if (WARN_ON(!workdir))
69 @@ -336,28 +335,7 @@ int ovl_copy_up_one(struct dentry *paren
74 - override_cred = prepare_creds();
78 - override_cred->fsuid = stat->uid;
79 - override_cred->fsgid = stat->gid;
81 - * CAP_SYS_ADMIN for copying up extended attributes
82 - * CAP_DAC_OVERRIDE for create
83 - * CAP_FOWNER for chmod, timestamp update
84 - * CAP_FSETID for chmod
85 - * CAP_CHOWN for chown
86 - * CAP_MKNOD for mknod
88 - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
89 - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
90 - cap_raise(override_cred->cap_effective, CAP_FOWNER);
91 - cap_raise(override_cred->cap_effective, CAP_FSETID);
92 - cap_raise(override_cred->cap_effective, CAP_CHOWN);
93 - cap_raise(override_cred->cap_effective, CAP_MKNOD);
94 - old_cred = override_creds(override_cred);
95 + old_cred = ovl_override_creds(dentry->d_sb);
98 if (lock_rename(workdir, upperdir) != NULL) {
99 @@ -380,9 +358,7 @@ int ovl_copy_up_one(struct dentry *paren
101 unlock_rename(workdir, upperdir);
102 revert_creds(old_cred);
103 - put_cred(override_cred);
107 free_page((unsigned long) link);
109 --- a/fs/overlayfs/dir.c
110 +++ b/fs/overlayfs/dir.c
111 @@ -408,28 +408,13 @@ static int ovl_create_or_link(struct den
112 err = ovl_create_upper(dentry, inode, &stat, link, hardlink);
114 const struct cred *old_cred;
115 - struct cred *override_cred;
118 - override_cred = prepare_creds();
119 - if (!override_cred)
123 - * CAP_SYS_ADMIN for setting opaque xattr
124 - * CAP_DAC_OVERRIDE for create in workdir, rename
125 - * CAP_FOWNER for removing whiteout from sticky dir
127 - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
128 - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
129 - cap_raise(override_cred->cap_effective, CAP_FOWNER);
130 - old_cred = override_creds(override_cred);
131 + old_cred = ovl_override_creds(dentry->d_sb);
133 err = ovl_create_over_whiteout(dentry, inode, &stat, link,
136 revert_creds(old_cred);
137 - put_cred(override_cred);
141 @@ -659,32 +644,11 @@ static int ovl_do_remove(struct dentry *
142 if (OVL_TYPE_PURE_UPPER(type)) {
143 err = ovl_remove_upper(dentry, is_dir);
145 - const struct cred *old_cred;
146 - struct cred *override_cred;
149 - override_cred = prepare_creds();
150 - if (!override_cred)
151 - goto out_drop_write;
154 - * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
155 - * CAP_DAC_OVERRIDE for create in workdir, rename
156 - * CAP_FOWNER for removing whiteout from sticky dir
157 - * CAP_FSETID for chmod of opaque dir
158 - * CAP_CHOWN for chown of opaque dir
160 - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
161 - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
162 - cap_raise(override_cred->cap_effective, CAP_FOWNER);
163 - cap_raise(override_cred->cap_effective, CAP_FSETID);
164 - cap_raise(override_cred->cap_effective, CAP_CHOWN);
165 - old_cred = override_creds(override_cred);
166 + const struct cred *old_cred = ovl_override_creds(dentry->d_sb);
168 err = ovl_remove_and_whiteout(dentry, is_dir);
170 revert_creds(old_cred);
171 - put_cred(override_cred);
174 ovl_drop_write(dentry);
175 @@ -723,7 +687,6 @@ static int ovl_rename2(struct inode *old
176 bool new_is_dir = false;
177 struct dentry *opaquedir = NULL;
178 const struct cred *old_cred = NULL;
179 - struct cred *override_cred = NULL;
182 if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
183 @@ -792,26 +755,8 @@ static int ovl_rename2(struct inode *old
184 old_opaque = !OVL_TYPE_PURE_UPPER(old_type);
185 new_opaque = !OVL_TYPE_PURE_UPPER(new_type);
187 - if (old_opaque || new_opaque) {
189 - override_cred = prepare_creds();
190 - if (!override_cred)
191 - goto out_drop_write;
194 - * CAP_SYS_ADMIN for setting xattr on whiteout, opaque dir
195 - * CAP_DAC_OVERRIDE for create in workdir
196 - * CAP_FOWNER for removing whiteout from sticky dir
197 - * CAP_FSETID for chmod of opaque dir
198 - * CAP_CHOWN for chown of opaque dir
200 - cap_raise(override_cred->cap_effective, CAP_SYS_ADMIN);
201 - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
202 - cap_raise(override_cred->cap_effective, CAP_FOWNER);
203 - cap_raise(override_cred->cap_effective, CAP_FSETID);
204 - cap_raise(override_cred->cap_effective, CAP_CHOWN);
205 - old_cred = override_creds(override_cred);
207 + if (old_opaque || new_opaque)
208 + old_cred = ovl_override_creds(old->d_sb);
210 if (overwrite && OVL_TYPE_MERGE_OR_LOWER(new_type) && new_is_dir) {
211 opaquedir = ovl_check_empty_and_clear(new);
212 @@ -942,10 +887,8 @@ out_dput_old:
214 unlock_rename(new_upperdir, old_upperdir);
216 - if (old_opaque || new_opaque) {
217 + if (old_opaque || new_opaque)
218 revert_creds(old_cred);
219 - put_cred(override_cred);
224 --- a/fs/overlayfs/overlayfs.h
225 +++ b/fs/overlayfs/overlayfs.h
226 @@ -150,6 +150,7 @@ void ovl_drop_write(struct dentry *dentr
227 bool ovl_dentry_is_opaque(struct dentry *dentry);
228 void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
229 bool ovl_is_whiteout(struct dentry *dentry);
230 +const struct cred *ovl_override_creds(struct super_block *sb);
231 void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
232 struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
234 --- a/fs/overlayfs/readdir.c
235 +++ b/fs/overlayfs/readdir.c
236 @@ -36,6 +36,7 @@ struct ovl_dir_cache {
238 struct ovl_readdir_data {
239 struct dir_context ctx;
240 + struct dentry *dentry;
243 struct list_head *list;
244 @@ -205,17 +206,8 @@ static int ovl_check_whiteouts(struct de
245 struct ovl_cache_entry *p;
246 struct dentry *dentry;
247 const struct cred *old_cred;
248 - struct cred *override_cred;
250 - override_cred = prepare_creds();
251 - if (!override_cred)
255 - * CAP_DAC_OVERRIDE for lookup
257 - cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
258 - old_cred = override_creds(override_cred);
259 + old_cred = ovl_override_creds(rdd->dentry->d_sb);
261 err = mutex_lock_killable(&dir->d_inode->i_mutex);
263 @@ -231,7 +223,6 @@ static int ovl_check_whiteouts(struct de
264 mutex_unlock(&dir->d_inode->i_mutex);
266 revert_creds(old_cred);
267 - put_cred(override_cred);
271 @@ -287,6 +278,7 @@ static int ovl_dir_read_merged(struct de
272 struct path realpath;
273 struct ovl_readdir_data rdd = {
274 .ctx.actor = ovl_fill_merge,
279 --- a/fs/overlayfs/super.c
280 +++ b/fs/overlayfs/super.c
281 @@ -42,6 +42,8 @@ struct ovl_fs {
283 /* pathnames of lower and upper dirs, for show_options */
284 struct ovl_config config;
285 + /* creds of process who forced instantiation of super block */
286 + const struct cred *creator_cred;
289 struct ovl_dir_cache;
290 @@ -246,6 +248,13 @@ bool ovl_is_whiteout(struct dentry *dent
291 return inode && IS_WHITEOUT(inode);
294 +const struct cred *ovl_override_creds(struct super_block *sb)
296 + struct ovl_fs *ofs = sb->s_fs_info;
298 + return override_creds(ofs->creator_cred);
301 static bool ovl_is_opaquedir(struct dentry *dentry)
304 @@ -587,6 +596,7 @@ static void ovl_put_super(struct super_b
305 kfree(ufs->config.lowerdir);
306 kfree(ufs->config.upperdir);
307 kfree(ufs->config.workdir);
308 + put_cred(ufs->creator_cred);
312 @@ -1087,10 +1097,14 @@ static int ovl_fill_super(struct super_b
314 sb->s_d_op = &ovl_dentry_operations;
316 + ufs->creator_cred = prepare_creds();
317 + if (!ufs->creator_cred)
318 + goto out_put_lower_mnt;
321 oe = ovl_alloc_entry(numlower);
323 - goto out_put_lower_mnt;
326 root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));
328 @@ -1123,6 +1137,8 @@ static int ovl_fill_super(struct super_b
333 + put_cred(ufs->creator_cred);
335 for (i = 0; i < ufs->numlower; i++)
336 mntput(ufs->lower_mnt[i]);