summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeah Rumancik <leah.rumancik@gmail.com>2021-04-22 18:08:34 +0000
committerTheodore Ts'o <tytso@mit.edu>2021-04-22 16:51:23 -0400
commit6c0912739699d8e4b6a87086401bf3ad3c59502d (patch)
tree3c418e18dc009422a2c63e4b244da2afdd58f36a
parent5899593f51e63dde2f07c67358bd65a641585abb (diff)
downloadlinux-6c0912739699d8e4b6a87086401bf3ad3c59502d.tar.bz2
ext4: wipe ext4_dir_entry2 upon file deletion
Upon file deletion, zero out all fields in ext4_dir_entry2 besides rec_len. In case sensitive data is stored in filenames, this ensures no potentially sensitive data is left in the directory entry upon deletion. Also, wipe these fields upon moving a directory entry during the conversion to an htree and when splitting htree nodes. The data wiped may still exist in the journal, but there are future commits planned to address this. Signed-off-by: Leah Rumancik <leah.rumancik@gmail.com> Link: https://lore.kernel.org/r/20210422180834.2242353-1-leah.rumancik@gmail.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--fs/ext4/namei.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 680fc3211cbf..8b46a17a85c1 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1854,7 +1854,14 @@ dx_move_dirents(struct inode *dir, char *from, char *to,
memcpy (to, de, rec_len);
((struct ext4_dir_entry_2 *) to)->rec_len =
ext4_rec_len_to_disk(rec_len, blocksize);
+
+ /* wipe dir_entry excluding the rec_len field */
de->inode = 0;
+ memset(&de->name_len, 0, ext4_rec_len_from_disk(de->rec_len,
+ blocksize) -
+ offsetof(struct ext4_dir_entry_2,
+ name_len));
+
map++;
to += rec_len;
}
@@ -2188,6 +2195,7 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname,
data2 = bh2->b_data;
memcpy(data2, de, len);
+ memset(de, 0, len); /* wipe old data */
de = (struct ext4_dir_entry_2 *) data2;
top = data2 + len;
while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top)
@@ -2577,15 +2585,27 @@ int ext4_generic_delete_entry(struct inode *dir,
entry_buf, buf_size, i))
return -EFSCORRUPTED;
if (de == de_del) {
- if (pde)
+ if (pde) {
pde->rec_len = ext4_rec_len_to_disk(
ext4_rec_len_from_disk(pde->rec_len,
blocksize) +
ext4_rec_len_from_disk(de->rec_len,
blocksize),
blocksize);
- else
+
+ /* wipe entire dir_entry */
+ memset(de, 0, ext4_rec_len_from_disk(de->rec_len,
+ blocksize));
+ } else {
+ /* wipe dir_entry excluding the rec_len field */
de->inode = 0;
+ memset(&de->name_len, 0,
+ ext4_rec_len_from_disk(de->rec_len,
+ blocksize) -
+ offsetof(struct ext4_dir_entry_2,
+ name_len));
+ }
+
inode_inc_iversion(dir);
return 0;
}