Skip to content

Commit 3aeb86e

Browse files
author
Tyler Hicks
committed
eCryptfs: Handle failed metadata read in lookup
When failing to read the lower file's crypto metadata during a lookup, eCryptfs must continue on without throwing an error. For example, there may be a plaintext file in the lower mount point that the user wants to delete through the eCryptfs mount. If an error is encountered while reading the metadata in lookup(), the eCryptfs inode's size could be incorrect. We must be sure to reread the plaintext inode size from the metadata when performing an open() or setattr(). The metadata is already being read in those paths, so this adds minimal performance overhead. This patch introduces a flag which will track whether or not the plaintext inode size has been read so that an incorrect i_size can be fixed in the open() or setattr() paths. https://bugs.launchpad.net/bugs/509180 Cc: <[email protected]> Signed-off-by: Tyler Hicks <[email protected]>
1 parent 332ab16 commit 3aeb86e

File tree

4 files changed

+28
-16
lines changed

4 files changed

+28
-16
lines changed

fs/ecryptfs/crypto.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,25 @@ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
14521452
crypt_stat->metadata_size = ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
14531453
}
14541454

1455+
void ecryptfs_i_size_init(const char *page_virt, struct inode *inode)
1456+
{
1457+
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
1458+
struct ecryptfs_crypt_stat *crypt_stat;
1459+
u64 file_size;
1460+
1461+
crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
1462+
mount_crypt_stat =
1463+
&ecryptfs_superblock_to_private(inode->i_sb)->mount_crypt_stat;
1464+
if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
1465+
file_size = i_size_read(ecryptfs_inode_to_lower(inode));
1466+
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
1467+
file_size += crypt_stat->metadata_size;
1468+
} else
1469+
file_size = get_unaligned_be64(page_virt);
1470+
i_size_write(inode, (loff_t)file_size);
1471+
crypt_stat->flags |= ECRYPTFS_I_SIZE_INITIALIZED;
1472+
}
1473+
14551474
/**
14561475
* ecryptfs_read_headers_virt
14571476
* @page_virt: The virtual address into which to read the headers
@@ -1482,6 +1501,8 @@ static int ecryptfs_read_headers_virt(char *page_virt,
14821501
rc = -EINVAL;
14831502
goto out;
14841503
}
1504+
if (!(crypt_stat->flags & ECRYPTFS_I_SIZE_INITIALIZED))
1505+
ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode);
14851506
offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
14861507
rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset),
14871508
&bytes_read);

fs/ecryptfs/ecryptfs_kernel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ struct ecryptfs_crypt_stat {
269269
#define ECRYPTFS_ENCFN_USE_MOUNT_FNEK 0x00000800
270270
#define ECRYPTFS_ENCFN_USE_FEK 0x00001000
271271
#define ECRYPTFS_UNLINK_SIGS 0x00002000
272+
#define ECRYPTFS_I_SIZE_INITIALIZED 0x00004000
272273
u32 flags;
273274
unsigned int file_version;
274275
size_t iv_bytes;
@@ -628,6 +629,7 @@ struct ecryptfs_open_req {
628629
int ecryptfs_interpose(struct dentry *hidden_dentry,
629630
struct dentry *this_dentry, struct super_block *sb,
630631
u32 flags);
632+
void ecryptfs_i_size_init(const char *page_virt, struct inode *inode);
631633
int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
632634
struct dentry *lower_dentry,
633635
struct inode *ecryptfs_dir_inode);

fs/ecryptfs/file.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
235235
goto out_put;
236236
}
237237
rc = 0;
238-
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
238+
crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
239+
| ECRYPTFS_ENCRYPTED);
239240
mutex_unlock(&crypt_stat->cs_mutex);
240241
goto out;
241242
}

fs/ecryptfs/inode.c

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,8 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
225225
struct dentry *lower_dir_dentry;
226226
struct vfsmount *lower_mnt;
227227
struct inode *lower_inode;
228-
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
229228
struct ecryptfs_crypt_stat *crypt_stat;
230229
char *page_virt = NULL;
231-
u64 file_size;
232230
int put_lower = 0, rc = 0;
233231

234232
lower_dir_dentry = lower_dentry->d_parent;
@@ -302,18 +300,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,
302300
}
303301
crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;
304302
}
305-
mount_crypt_stat = &ecryptfs_superblock_to_private(
306-
ecryptfs_dentry->d_sb)->mount_crypt_stat;
307-
if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {
308-
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
309-
file_size = (crypt_stat->metadata_size
310-
+ i_size_read(lower_dentry->d_inode));
311-
else
312-
file_size = i_size_read(lower_dentry->d_inode);
313-
} else {
314-
file_size = get_unaligned_be64(page_virt);
315-
}
316-
i_size_write(ecryptfs_dentry->d_inode, (loff_t)file_size);
303+
ecryptfs_i_size_init(page_virt, ecryptfs_dentry->d_inode);
317304
out_free_kmem:
318305
kmem_cache_free(ecryptfs_header_cache_2, page_virt);
319306
goto out;
@@ -937,7 +924,8 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
937924
goto out;
938925
}
939926
rc = 0;
940-
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
927+
crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
928+
| ECRYPTFS_ENCRYPTED);
941929
}
942930
}
943931
mutex_unlock(&crypt_stat->cs_mutex);

0 commit comments

Comments
 (0)