aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2018-01-17 15:32:44 -0500
committerMiklos Szeredi <mszeredi@redhat.com>2018-01-24 05:26:04 -0500
commit988925164f659bf74061d3036e14873753c937d2 (patch)
tree11df4a932966fa87834ad7f859f9aaffcdf509b0
parent3b0bfc6ed3c434800e5eacfb6cdbe45c07c270e1 (diff)
ovl: decode pure lower dir file handles
Similar to decoding a pure upper dir file handle, decoding a pure lower dir file handle is implemented by looking an overlay dentry of the same path as the pure lower path and verifying that the overlay dentry's real lower matches the decoded real lower file handle. Unlike the case of upper dir file handle, the lookup of overlay path by lower real path can fail or find a mismatched overlay dentry if any of the lower parents have been copied up and renamed. To address this case we will need to check if any of the lower parents are indexed. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/export.c43
1 files changed, 26 insertions, 17 deletions
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index 7a4b6a0fd527..361174810ce8 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -215,6 +215,23 @@ nomem:
215 return ERR_PTR(-ENOMEM); 215 return ERR_PTR(-ENOMEM);
216} 216}
217 217
218/* Get the upper or lower dentry in stach whose on layer @idx */
219static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx)
220{
221 struct ovl_entry *oe = dentry->d_fsdata;
222 int i;
223
224 if (!idx)
225 return ovl_dentry_upper(dentry);
226
227 for (i = 0; i < oe->numlower; i++) {
228 if (oe->lowerstack[i].layer->idx == idx)
229 return oe->lowerstack[i].dentry;
230 }
231
232 return NULL;
233}
234
218/* 235/*
219 * Lookup a child overlay dentry to get a connected overlay dentry whose real 236 * Lookup a child overlay dentry to get a connected overlay dentry whose real
220 * dentry is @real. If @real is on upper layer, we lookup a child overlay 237 * dentry is @real. If @real is on upper layer, we lookup a child overlay
@@ -230,10 +247,6 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
230 struct name_snapshot name; 247 struct name_snapshot name;
231 int err; 248 int err;
232 249
233 /* TODO: lookup by lower real dentry */
234 if (layer->idx)
235 return ERR_PTR(-EACCES);
236
237 /* 250 /*
238 * Lookup child overlay dentry by real name. The dir mutex protects us 251 * Lookup child overlay dentry by real name. The dir mutex protects us
239 * from racing with overlay rename. If the overlay dentry that is above 252 * from racing with overlay rename. If the overlay dentry that is above
@@ -244,7 +257,7 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
244 inode_lock_nested(dir, I_MUTEX_PARENT); 257 inode_lock_nested(dir, I_MUTEX_PARENT);
245 err = -ECHILD; 258 err = -ECHILD;
246 parent = dget_parent(real); 259 parent = dget_parent(real);
247 if (ovl_dentry_upper(connected) != parent) 260 if (ovl_dentry_real_at(connected, layer->idx) != parent)
248 goto fail; 261 goto fail;
249 262
250 /* 263 /*
@@ -262,7 +275,7 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
262 dput(this); 275 dput(this);
263 err = -ENOENT; 276 err = -ENOENT;
264 goto fail; 277 goto fail;
265 } else if (ovl_dentry_upper(this) != real) { 278 } else if (ovl_dentry_real_at(this, layer->idx) != real) {
266 dput(this); 279 dput(this);
267 err = -ESTALE; 280 err = -ESTALE;
268 goto fail; 281 goto fail;
@@ -294,14 +307,13 @@ static struct dentry *ovl_lookup_real(struct super_block *sb,
294 int err = 0; 307 int err = 0;
295 308
296 /* TODO: use index when looking up by lower real dentry */ 309 /* TODO: use index when looking up by lower real dentry */
297 if (layer->idx)
298 return ERR_PTR(-EACCES);
299 310
300 connected = dget(sb->s_root); 311 connected = dget(sb->s_root);
301 while (!err) { 312 while (!err) {
302 struct dentry *next, *this; 313 struct dentry *next, *this;
303 struct dentry *parent = NULL; 314 struct dentry *parent = NULL;
304 struct dentry *real_connected = ovl_dentry_upper(connected); 315 struct dentry *real_connected = ovl_dentry_real_at(connected,
316 layer->idx);
305 317
306 if (real_connected == real) 318 if (real_connected == real)
307 break; 319 break;
@@ -391,6 +403,7 @@ static struct dentry *ovl_get_dentry(struct super_block *sb,
391{ 403{
392 struct ovl_fs *ofs = sb->s_fs_info; 404 struct ovl_fs *ofs = sb->s_fs_info;
393 struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt }; 405 struct ovl_layer upper_layer = { .mnt = ofs->upper_mnt };
406 struct ovl_layer *layer = upper ? &upper_layer : lowerpath->layer;
394 struct dentry *real = upper ?: (index ?: lowerpath->dentry); 407 struct dentry *real = upper ?: (index ?: lowerpath->dentry);
395 408
396 /* 409 /*
@@ -400,19 +413,15 @@ static struct dentry *ovl_get_dentry(struct super_block *sb,
400 if (!d_is_dir(real)) 413 if (!d_is_dir(real))
401 return ovl_obtain_alias(sb, upper, lowerpath, index); 414 return ovl_obtain_alias(sb, upper, lowerpath, index);
402 415
403 /* TODO: lookup connected dir from real lower dir */
404 if (!upper)
405 return ERR_PTR(-EACCES);
406
407 /* Removed empty directory? */ 416 /* Removed empty directory? */
408 if ((upper->d_flags & DCACHE_DISCONNECTED) || d_unhashed(upper)) 417 if ((real->d_flags & DCACHE_DISCONNECTED) || d_unhashed(real))
409 return ERR_PTR(-ENOENT); 418 return ERR_PTR(-ENOENT);
410 419
411 /* 420 /*
412 * If real upper dentry is connected and hashed, get a connected 421 * If real dentry is connected and hashed, get a connected overlay
413 * overlay dentry with the same path as the real upper dentry. 422 * dentry whose real dentry is @real.
414 */ 423 */
415 return ovl_lookup_real(sb, upper, &upper_layer); 424 return ovl_lookup_real(sb, real, layer);
416} 425}
417 426
418static struct dentry *ovl_upper_fh_to_d(struct super_block *sb, 427static struct dentry *ovl_upper_fh_to_d(struct super_block *sb,