aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLino Sanfilippo <linosanfilippo@gmx.de>2010-07-15 09:11:55 -0400
committerTyler Hicks <tyhicks@linux.vnet.ibm.com>2010-08-09 14:42:12 -0400
commit21edad32205e97dc7ccb81a85234c77e760364c8 (patch)
treed68f20aa288a6fe98547fe348d3c300020ad8daf
parentceeab92971e8af05c1e81a4ff2c271124b55bb9b (diff)
ecryptfs: dont call lookup_one_len to avoid NULL nameidata
I have encountered the same problem that Eric Sandeen described in this post http://lkml.org/lkml/fancy/2010/4/23/467 while experimenting with stackable filesystems. The reason seems to be that ecryptfs calls lookup_one_len() to get the lower dentry, which in turn calls the lower parent dirs d_revalidate() with a NULL nameidata object. If ecryptfs is the underlaying filesystem, the NULL pointer dereference occurs, since ecryptfs is not prepared to handle a NULL nameidata. I know that this cant happen any more, since it is no longer allowed to mount ecryptfs upon itself. But maybe this patch it useful nevertheless, since the problem would still apply for an underlaying filesystem that implements d_revalidate() and is not prepared to handle a NULL nameidata (I dont know if there actually is such a fs). With this patch (against 2.6.35-rc5) ecryptfs uses the vfs_lookup_path() function instead of lookup_one_len() which ensures that the nameidata passed to the lower filesystems d_revalidate(). Signed-off-by: Lino Sanfilippo <LinoSanfilippo@gmx.de> Signed-off-by: Tyler Hicks <tyhicks@linux.vnet.ibm.com>
-rw-r--r--fs/ecryptfs/inode.c89
1 files changed, 77 insertions, 12 deletions
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 8cd617b66baa..a8acfc5d3476 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -348,6 +348,76 @@ out:
348} 348}
349 349
350/** 350/**
351 * ecryptfs_new_lower_dentry
352 * @ename: The name of the new dentry.
353 * @lower_dir_dentry: Parent directory of the new dentry.
354 * @nd: nameidata from last lookup.
355 *
356 * Create a new dentry or get it from lower parent dir.
357 */
358static struct dentry *
359ecryptfs_new_lower_dentry(struct qstr *name, struct dentry *lower_dir_dentry,
360 struct nameidata *nd)
361{
362 struct dentry *new_dentry;
363 struct dentry *tmp;
364 struct inode *lower_dir_inode;
365
366 lower_dir_inode = lower_dir_dentry->d_inode;
367
368 tmp = d_alloc(lower_dir_dentry, name);
369 if (!tmp)
370 return ERR_PTR(-ENOMEM);
371
372 mutex_lock(&lower_dir_inode->i_mutex);
373 new_dentry = lower_dir_inode->i_op->lookup(lower_dir_inode, tmp, nd);
374 mutex_unlock(&lower_dir_inode->i_mutex);
375
376 if (!new_dentry)
377 new_dentry = tmp;
378 else
379 dput(tmp);
380
381 return new_dentry;
382}
383
384
385/**
386 * ecryptfs_lookup_one_lower
387 * @ecryptfs_dentry: The eCryptfs dentry that we are looking up
388 * @lower_dir_dentry: lower parent directory
389 *
390 * Get the lower dentry from vfs. If lower dentry does not exist yet,
391 * create it.
392 */
393static struct dentry *
394ecryptfs_lookup_one_lower(struct dentry *ecryptfs_dentry,
395 struct dentry *lower_dir_dentry)
396{
397 struct nameidata nd;
398 struct vfsmount *lower_mnt;
399 struct qstr *name;
400 int err;
401
402 name = &ecryptfs_dentry->d_name;
403 lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(
404 ecryptfs_dentry->d_parent));
405 err = vfs_path_lookup(lower_dir_dentry, lower_mnt, name->name , 0, &nd);
406 mntput(lower_mnt);
407
408 if (!err) {
409 /* we dont need the mount */
410 mntput(nd.path.mnt);
411 return nd.path.dentry;
412 }
413 if (err != -ENOENT)
414 return ERR_PTR(err);
415
416 /* create a new lower dentry */
417 return ecryptfs_new_lower_dentry(name, lower_dir_dentry, &nd);
418}
419
420/**
351 * ecryptfs_lookup 421 * ecryptfs_lookup
352 * @ecryptfs_dir_inode: The eCryptfs directory inode 422 * @ecryptfs_dir_inode: The eCryptfs directory inode
353 * @ecryptfs_dentry: The eCryptfs dentry that we are looking up 423 * @ecryptfs_dentry: The eCryptfs dentry that we are looking up
@@ -374,14 +444,12 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
374 goto out_d_drop; 444 goto out_d_drop;
375 } 445 }
376 lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); 446 lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent);
377 mutex_lock(&lower_dir_dentry->d_inode->i_mutex); 447
378 lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name, 448 lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry,
379 lower_dir_dentry, 449 lower_dir_dentry);
380 ecryptfs_dentry->d_name.len);
381 mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
382 if (IS_ERR(lower_dentry)) { 450 if (IS_ERR(lower_dentry)) {
383 rc = PTR_ERR(lower_dentry); 451 rc = PTR_ERR(lower_dentry);
384 ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " 452 ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned "
385 "[%d] on lower_dentry = [%s]\n", __func__, rc, 453 "[%d] on lower_dentry = [%s]\n", __func__, rc,
386 encrypted_and_encoded_name); 454 encrypted_and_encoded_name);
387 goto out_d_drop; 455 goto out_d_drop;
@@ -403,14 +471,11 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
403 "filename; rc = [%d]\n", __func__, rc); 471 "filename; rc = [%d]\n", __func__, rc);
404 goto out_d_drop; 472 goto out_d_drop;
405 } 473 }
406 mutex_lock(&lower_dir_dentry->d_inode->i_mutex); 474 lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry,
407 lower_dentry = lookup_one_len(encrypted_and_encoded_name, 475 lower_dir_dentry);
408 lower_dir_dentry,
409 encrypted_and_encoded_name_size - 1);
410 mutex_unlock(&lower_dir_dentry->d_inode->i_mutex);
411 if (IS_ERR(lower_dentry)) { 476 if (IS_ERR(lower_dentry)) {
412 rc = PTR_ERR(lower_dentry); 477 rc = PTR_ERR(lower_dentry);
413 ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " 478 ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned "
414 "[%d] on lower_dentry = [%s]\n", __func__, rc, 479 "[%d] on lower_dentry = [%s]\n", __func__, rc,
415 encrypted_and_encoded_name); 480 encrypted_and_encoded_name);
416 goto out_d_drop; 481 goto out_d_drop;