Patchwork [2/2,v3] EXT4: Secure Delete: Zero out files directory entry

login
register
mail settings
Submitter Allison Henderson
Date June 30, 2011, 9:22 p.m.
Message ID <1309468923-5677-3-git-send-email-achender@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/102838/
State Changes Requested
Headers show

Comments

Allison Henderson - June 30, 2011, 9:22 p.m.
This patch zeros out a files directory entry when a file
with the EXT4_SECRM_FL attribute flag is deleted.  A new flag
parameter has been added to the ext4_delete_entry routine,
that will force the entry to be zeroed out and flushed to the disk.

Signed-off-by: Allison Henderson <achender@linux.vnet.ibm.com>
---
v1->v2
Removed new inode parameter in ext4_delete_entry and replaced
with a new flag for ext4_delete_entry

:100644 100644 38a4d75... 1e50f78... M	fs/ext4/ext4.h
:100644 100644 b754b77... 9af19f4... M	fs/ext4/namei.c
 fs/ext4/ext4.h  |    5 +++++
 fs/ext4/namei.c |   52 +++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 46 insertions(+), 11 deletions(-)

Patch

diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 38a4d75..1e50f78 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -529,6 +529,11 @@  struct ext4_new_group_data {
 #define EXT4_FREE_BLOCKS_ZERO		0x0008
 
 /*
+ * Flags used by ext4_delete_entry
+ */
+#define EXT4_DEL_ENTRY_ZERO		0x0001
+
+/*
  * ioctl commands
  */
 #define	EXT4_IOC_GETFLAGS		FS_IOC_GETFLAGS
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index b754b77..9af19f4 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1643,10 +1643,12 @@  cleanup:
 static int ext4_delete_entry(handle_t *handle,
 			     struct inode *dir,
 			     struct ext4_dir_entry_2 *de_del,
-			     struct buffer_head *bh)
+			     struct buffer_head *bh,
+			     int flags)
 {
 	struct ext4_dir_entry_2 *de, *pde;
 	unsigned int blocksize = dir->i_sb->s_blocksize;
+	struct ext4_super_block *es = EXT4_SB(dir->i_sb)->s_es;
 	int i, err;
 
 	i = 0;
@@ -1673,10 +1675,34 @@  static int ext4_delete_entry(handle_t *handle,
 				de->inode = 0;
 			dir->i_version++;
 			BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
-			err = ext4_handle_dirty_metadata(handle, dir, bh);
-			if (unlikely(err)) {
-				ext4_std_error(dir->i_sb, err);
-				return err;
+
+			/*
+			 * If the secure remove flag is on, zero
+			 * out the entry and write it out to the
+			 * disk
+			 */
+			if (flags & EXT4_DEL_ENTRY_ZERO) {
+				memset(de->name, 0x00, de->name_len);
+				de->file_type = 0;
+
+				set_buffer_dirty(bh);
+				sync_dirty_buffer(bh);
+				if (buffer_req(bh) && !buffer_uptodate(bh)) {
+					es->s_last_error_block =
+						cpu_to_le64(bh->b_blocknr);
+					ext4_error_inode(dir,
+					__func__, __LINE__, bh->b_blocknr,
+					"IO error syncing itable block");
+					return -EIO;
+				}
+			} else {
+				err = ext4_handle_dirty_metadata(handle,
+					dir, bh);
+
+				if (unlikely(err)) {
+					ext4_std_error(dir->i_sb, err);
+					return err;
+				}
 			}
 			return 0;
 		}
@@ -2162,7 +2188,7 @@  static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
 	if (!empty_dir(inode))
 		goto end_rmdir;
 
-	retval = ext4_delete_entry(handle, dir, de, bh);
+	retval = ext4_delete_entry(handle, dir, de, bh, 0);
 	if (retval)
 		goto end_rmdir;
 	if (!EXT4_DIR_LINK_EMPTY(inode))
@@ -2190,7 +2216,7 @@  end_rmdir:
 
 static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 {
-	int retval;
+	int retval, del_entry_flags;
 	struct inode *inode;
 	struct buffer_head *bh;
 	struct ext4_dir_entry_2 *de;
@@ -2215,6 +2241,8 @@  static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 		goto end_unlink;
 
 	inode = dentry->d_inode;
+	del_entry_flags = EXT4_I(inode)->i_flags & EXT4_SECRM_FL ?
+		EXT4_DEL_ENTRY_ZERO : 0;
 
 	retval = -EIO;
 	if (le32_to_cpu(de->inode) != inode->i_ino)
@@ -2226,7 +2254,7 @@  static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 			     inode->i_ino, inode->i_nlink);
 		inode->i_nlink = 1;
 	}
-	retval = ext4_delete_entry(handle, dir, de, bh);
+	retval = ext4_delete_entry(handle, dir, de, bh, del_entry_flags);
 	if (retval)
 		goto end_unlink;
 	dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
@@ -2404,7 +2432,7 @@  static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 	struct inode *old_inode, *new_inode;
 	struct buffer_head *old_bh, *new_bh, *dir_bh;
 	struct ext4_dir_entry_2 *old_de, *new_de;
-	int retval, force_da_alloc = 0;
+	int retval, del_entry_flags, force_da_alloc = 0;
 
 	dquot_initialize(old_dir);
 	dquot_initialize(new_dir);
@@ -2503,11 +2531,13 @@  static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 	/*
 	 * ok, that's it
 	 */
+	del_entry_flags = EXT4_I(old_inode)->i_flags & EXT4_SECRM_FL ?
+			EXT4_DEL_ENTRY_ZERO : 0;
 	if (le32_to_cpu(old_de->inode) != old_inode->i_ino ||
 	    old_de->name_len != old_dentry->d_name.len ||
 	    strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) ||
 	    (retval = ext4_delete_entry(handle, old_dir,
-					old_de, old_bh)) == -ENOENT) {
+			old_de, old_bh, del_entry_flags)) == -ENOENT) {
 		/* old_de could have moved from under us during htree split, so
 		 * make sure that we are deleting the right entry.  We might
 		 * also be pointing to a stale entry in the unused part of
@@ -2518,7 +2548,7 @@  static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 		old_bh2 = ext4_find_entry(old_dir, &old_dentry->d_name, &old_de2);
 		if (old_bh2) {
 			retval = ext4_delete_entry(handle, old_dir,
-						   old_de2, old_bh2);
+				old_de2, old_bh2, del_entry_flags);
 			brelse(old_bh2);
 		}
 	}