aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-10-04 08:40:45 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-10-14 05:16:47 -0400
commit7764235becf3b72bd124400fbffe670531322135 (patch)
tree9377570db6422ab76c10617bea548a1f4e41311e
parentd60874cd58fcb21372f2df698c20f8cf2f78fdcb (diff)
ovl: use vfs_get_link()
Resulting in a complete removal of a function basically implementing the inverse of vfs_readlink(). As a bonus, now the proper security hook is also called. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/copy_up.c46
-rw-r--r--fs/overlayfs/inode.c10
2 files changed, 7 insertions, 49 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 796d06fafd09..e9d4013ed3c6 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -177,40 +177,6 @@ out_fput:
177 return error; 177 return error;
178} 178}
179 179
180static char *ovl_read_symlink(struct dentry *realdentry)
181{
182 int res;
183 char *buf;
184 struct inode *inode = realdentry->d_inode;
185 mm_segment_t old_fs;
186
187 res = -EINVAL;
188 if (!inode->i_op->readlink)
189 goto err;
190
191 res = -ENOMEM;
192 buf = (char *) __get_free_page(GFP_KERNEL);
193 if (!buf)
194 goto err;
195
196 old_fs = get_fs();
197 set_fs(get_ds());
198 /* The cast to a user pointer is valid due to the set_fs() */
199 res = inode->i_op->readlink(realdentry,
200 (char __user *)buf, PAGE_SIZE - 1);
201 set_fs(old_fs);
202 if (res < 0) {
203 free_page((unsigned long) buf);
204 goto err;
205 }
206 buf[res] = '\0';
207
208 return buf;
209
210err:
211 return ERR_PTR(res);
212}
213
214static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat) 180static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat)
215{ 181{
216 struct iattr attr = { 182 struct iattr attr = {
@@ -342,18 +308,20 @@ out_cleanup:
342int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, 308int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
343 struct path *lowerpath, struct kstat *stat) 309 struct path *lowerpath, struct kstat *stat)
344{ 310{
311 DEFINE_DELAYED_CALL(done);
345 struct dentry *workdir = ovl_workdir(dentry); 312 struct dentry *workdir = ovl_workdir(dentry);
346 int err; 313 int err;
347 struct kstat pstat; 314 struct kstat pstat;
348 struct path parentpath; 315 struct path parentpath;
316 struct dentry *lowerdentry = lowerpath->dentry;
349 struct dentry *upperdir; 317 struct dentry *upperdir;
350 struct dentry *upperdentry; 318 struct dentry *upperdentry;
351 char *link = NULL; 319 const char *link = NULL;
352 320
353 if (WARN_ON(!workdir)) 321 if (WARN_ON(!workdir))
354 return -EROFS; 322 return -EROFS;
355 323
356 ovl_do_check_copy_up(lowerpath->dentry); 324 ovl_do_check_copy_up(lowerdentry);
357 325
358 ovl_path_upper(parent, &parentpath); 326 ovl_path_upper(parent, &parentpath);
359 upperdir = parentpath.dentry; 327 upperdir = parentpath.dentry;
@@ -363,7 +331,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
363 return err; 331 return err;
364 332
365 if (S_ISLNK(stat->mode)) { 333 if (S_ISLNK(stat->mode)) {
366 link = ovl_read_symlink(lowerpath->dentry); 334 link = vfs_get_link(lowerdentry, &done);
367 if (IS_ERR(link)) 335 if (IS_ERR(link))
368 return PTR_ERR(link); 336 return PTR_ERR(link);
369 } 337 }
@@ -388,9 +356,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
388 } 356 }
389out_unlock: 357out_unlock:
390 unlock_rename(workdir, upperdir); 358 unlock_rename(workdir, upperdir);
391 359 do_delayed_call(&done);
392 if (link)
393 free_page((unsigned long) link);
394 360
395 return err; 361 return err;
396} 362}
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 50dc214c44f2..bc6d261db669 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -156,22 +156,14 @@ static const char *ovl_get_link(struct dentry *dentry,
156 struct inode *inode, 156 struct inode *inode,
157 struct delayed_call *done) 157 struct delayed_call *done)
158{ 158{
159 struct dentry *realdentry;
160 struct inode *realinode;
161 const struct cred *old_cred; 159 const struct cred *old_cred;
162 const char *p; 160 const char *p;
163 161
164 if (!dentry) 162 if (!dentry)
165 return ERR_PTR(-ECHILD); 163 return ERR_PTR(-ECHILD);
166 164
167 realdentry = ovl_dentry_real(dentry);
168 realinode = realdentry->d_inode;
169
170 if (WARN_ON(!realinode->i_op->get_link))
171 return ERR_PTR(-EPERM);
172
173 old_cred = ovl_override_creds(dentry->d_sb); 165 old_cred = ovl_override_creds(dentry->d_sb);
174 p = realinode->i_op->get_link(realdentry, realinode, done); 166 p = vfs_get_link(ovl_dentry_real(dentry), done);
175 revert_creds(old_cred); 167 revert_creds(old_cred);
176 return p; 168 return p;
177} 169}