aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2017-04-30 07:46:31 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2017-05-05 05:38:58 -0400
commita9d019573e881472aa62f093fa599ad68cd0fc1e (patch)
tree8778da1cdb000fe74a5c8f03584ff5f2d40008e3
parentc22205d0584bc65cfc9a65db0e15a9b69f5cdf64 (diff)
ovl: lookup non-dir copy-up-origin by file handle
If overlay.origin xattr is found on a non-dir upper inode try to get lower dentry by calling exportfs_decode_fh(). On failure to lookup by file handle to lower layer, do not lookup the copy up origin by name, because the lower found by name could be another file in case the upper file was renamed. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/namei.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index d0a3e4ad3042..bad0f665a635 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -12,6 +12,8 @@
12#include <linux/namei.h> 12#include <linux/namei.h>
13#include <linux/xattr.h> 13#include <linux/xattr.h>
14#include <linux/ratelimit.h> 14#include <linux/ratelimit.h>
15#include <linux/mount.h>
16#include <linux/exportfs.h>
15#include "overlayfs.h" 17#include "overlayfs.h"
16#include "ovl_entry.h" 18#include "ovl_entry.h"
17 19
@@ -81,6 +83,90 @@ invalid:
81 goto err_free; 83 goto err_free;
82} 84}
83 85
86static int ovl_acceptable(void *ctx, struct dentry *dentry)
87{
88 return 1;
89}
90
91static struct dentry *ovl_get_origin(struct dentry *dentry,
92 struct vfsmount *mnt)
93{
94 int res;
95 struct ovl_fh *fh = NULL;
96 struct dentry *origin = NULL;
97 int bytes;
98
99 res = vfs_getxattr(dentry, OVL_XATTR_ORIGIN, NULL, 0);
100 if (res < 0) {
101 if (res == -ENODATA || res == -EOPNOTSUPP)
102 return NULL;
103 goto fail;
104 }
105 /* Zero size value means "copied up but origin unknown" */
106 if (res == 0)
107 return NULL;
108
109 fh = kzalloc(res, GFP_TEMPORARY);
110 if (!fh)
111 return ERR_PTR(-ENOMEM);
112
113 res = vfs_getxattr(dentry, OVL_XATTR_ORIGIN, fh, res);
114 if (res < 0)
115 goto fail;
116
117 if (res < sizeof(struct ovl_fh) || res < fh->len)
118 goto invalid;
119
120 if (fh->magic != OVL_FH_MAGIC)
121 goto invalid;
122
123 /* Treat larger version and unknown flags as "origin unknown" */
124 if (fh->version > OVL_FH_VERSION || fh->flags & ~OVL_FH_FLAG_ALL)
125 goto out;
126
127 /* Treat endianness mismatch as "origin unknown" */
128 if (!(fh->flags & OVL_FH_FLAG_ANY_ENDIAN) &&
129 (fh->flags & OVL_FH_FLAG_BIG_ENDIAN) != OVL_FH_FLAG_CPU_ENDIAN)
130 goto out;
131
132 bytes = (fh->len - offsetof(struct ovl_fh, fid));
133
134 /*
135 * Make sure that the stored uuid matches the uuid of the lower
136 * layer where file handle will be decoded.
137 */
138 if (uuid_be_cmp(fh->uuid, *(uuid_be *) &mnt->mnt_sb->s_uuid))
139 goto out;
140
141 origin = exportfs_decode_fh(mnt, (struct fid *)fh->fid,
142 bytes >> 2, (int)fh->type,
143 ovl_acceptable, NULL);
144 if (IS_ERR(origin)) {
145 /* Treat stale file handle as "origin unknown" */
146 if (origin == ERR_PTR(-ESTALE))
147 origin = NULL;
148 goto out;
149 }
150
151 if (ovl_dentry_weird(origin) ||
152 ((d_inode(origin)->i_mode ^ d_inode(dentry)->i_mode) & S_IFMT)) {
153 dput(origin);
154 origin = NULL;
155 goto invalid;
156 }
157
158out:
159 kfree(fh);
160 return origin;
161
162fail:
163 pr_warn_ratelimited("overlayfs: failed to get origin (%i)\n", res);
164 goto out;
165invalid:
166 pr_warn_ratelimited("overlayfs: invalid origin (%*phN)\n", res, fh);
167 goto out;
168}
169
84static bool ovl_is_opaquedir(struct dentry *dentry) 170static bool ovl_is_opaquedir(struct dentry *dentry)
85{ 171{
86 int res; 172 int res;
@@ -192,6 +278,45 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
192 return 0; 278 return 0;
193} 279}
194 280
281
282static int ovl_check_origin(struct dentry *dentry, struct dentry *upperdentry,
283 struct path **stackp, unsigned int *ctrp)
284{
285 struct super_block *same_sb = ovl_same_sb(dentry->d_sb);
286 struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata;
287 struct vfsmount *mnt;
288 struct dentry *origin;
289
290 if (!same_sb || !roe->numlower)
291 return 0;
292
293 /*
294 * Since all layers are on the same fs, we use the first layer for
295 * decoding the file handle. We may get a disconnected dentry,
296 * which is fine, because we only need to hold the origin inode in
297 * cache and use its inode number. We may even get a connected dentry,
298 * that is not under the first layer's root. That is also fine for
299 * using it's inode number - it's the same as if we held a reference
300 * to a dentry in first layer that was moved under us.
301 */
302 mnt = roe->lowerstack[0].mnt;
303
304 origin = ovl_get_origin(upperdentry, mnt);
305 if (IS_ERR_OR_NULL(origin))
306 return PTR_ERR(origin);
307
308 BUG_ON(*stackp || *ctrp);
309 *stackp = kmalloc(sizeof(struct path), GFP_TEMPORARY);
310 if (!*stackp) {
311 dput(origin);
312 return -ENOMEM;
313 }
314 **stackp = (struct path) { .dentry = origin, .mnt = mnt };
315 *ctrp = 1;
316
317 return 0;
318}
319
195/* 320/*
196 * Returns next layer in stack starting from top. 321 * Returns next layer in stack starting from top.
197 * Returns -1 if this is the last layer. 322 * Returns -1 if this is the last layer.
@@ -254,6 +379,13 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
254 err = -EREMOTE; 379 err = -EREMOTE;
255 goto out; 380 goto out;
256 } 381 }
382 if (upperdentry && !d.is_dir) {
383 BUG_ON(!d.stop || d.redirect);
384 err = ovl_check_origin(dentry, upperdentry,
385 &stack, &ctr);
386 if (err)
387 goto out;
388 }
257 389
258 if (d.redirect) { 390 if (d.redirect) {
259 upperredirect = kstrdup(d.redirect, GFP_KERNEL); 391 upperredirect = kstrdup(d.redirect, GFP_KERNEL);