public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: the grugq <grugq@hcunix.net>
To: linux-kernel@vger.kernel.org
Subject: PATCH - ext2fs privacy (i.e. secure deletion) patch
Date: Wed, 28 Jan 2004 16:30:49 +0000	[thread overview]
Message-ID: <4017E3B9.3090605@hcunix.net> (raw)

[-- Attachment #1: Type: text/plain, Size: 3453 bytes --]

Hi,

I've written a quick patch to the ext2fs which ensures that inodes, data 
  blocks, and directory entries are overwritten with null bytes when 
they are deleted. The patch adds a couple of inline functions to 
overwrite the appropriate data with zeroes. Its quite simple and 
self-explanitory. Both attached patches are to a vanilla 2.4.24 kernel.

inodes: ext2_delete_inode() now uses the inline function delete_inode() 
to mark the on-disk inode as 'deleted'. If the privacy option is not 
enabled, then the i_dtime is set as per usual operation, otherwise the 
meta-data are all set to 0. After the inode has been truncated, the 
i_data is set to 0 by delete_blocks() and the inode is written to disk 
again.

Splitting the delete_inode() and delete_blocks() functions is not ideal, 
I would prefer that one function remove the meta-data and the inode be 
written out just once. The problem is that ext2_truncate() needs the 
i_data information from the struct inode, and we want to remove this 
information from the inode on the disk. To ensure that the i_data is 0 
by the time it hits the disk, I write the inode to disk twice, which is 
not optimal.

directory entries: ext2_delete_entry() now uses the inline function 
mark_delete_dir() to indicate that the directory entry is no longer 
valid. If the privacy patch is not enabled, then the dir->inode is set 
to  0 as per normal operation, otherwise the entry is memset 0. Very 
straightforward.

blocks: ext2_free_blocks() now uses the inline function destroy_block() 
before it updates the group meta-data. The destroy_block() function 
overwrites the block with zeroes. I'm not sure that it is implemented 
correctly, I don't know anything about buffer_heads. The block is only 
overwritten with a single pass of zeroes. It is, of course, possible to 
have a full 37 pass overwriter with full bit toggling maps and all that, 
but I think it might make more sense to add a new option for that, 
something like: CONFIG_EXT2_FS_PRIVACY_EXTREME_PARANOIA. For preventing 
simple forensic analysis (that is, what the police, employers and even 
most government agencies do) a single pass with zeroes is sufficient. 
Users can use userland tools like wipe or srm for more thorough overwriting.

There is also a patch to ext3fs, which adds the same functionality (in 
the same way) as the ext2fs privacy patch. However, the main problem 
with privacy on the ext3fs is the journal. I am not familiar enough with 
how the journal transactions are handled to implement what seems to me 
the obvious solution: when a transaction is complete (i.e. doesn't need 
to be replayed by fsck) overwrite it with null bytes. If done correctly, 
it is possible to leave sufficient information for fsck to find the 
right transaction to begin replaying, without leaving any data which 
would be of use to a forensic analyst.

Given the existing global political climate, privacy control over a file 
system seems like a no-brainer to me. Full privacy options would include 
things like mounting disks with noatime, and possibly normalizing the 
mtime and ctime of all inodes (setting everthing to an arbitrary date, 
e.g. 0). Certainly this will break tools like make which require atime, 
but it would provide even less information to a forensic analyst 
examining the file system.



peace,

--gq

ps. apologies for posting to the kernel mailing list, but I'm not sure 
who is the maintainer for ext2/3.





[-- Attachment #2: privacy_patch_ext2 --]
[-- Type: text/plain, Size: 3509 bytes --]

--- linux-2.4.24/fs/Config.in	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.24/fs/Config.in-ext2-privacy	2004-01-27 21:56:58.000000000 +0000
@@ -92,6 +92,7 @@
 tristate 'ROM file system support' CONFIG_ROMFS_FS
 
 tristate 'Second extended fs support' CONFIG_EXT2_FS
+dep_mbool '  ext2 privacy support' CONFIG_EXT2_FS_PRIVACY $CONFIG_EXT2_FS
 
 tristate 'System V/Xenix/V7/Coherent file system support' CONFIG_SYSV_FS
 
--- linux-2.4.24/fs/ext2/balloc.c	2003-06-13 15:51:37.000000000 +0100
+++ linux-2.4.24/fs/ext2-privacy/balloc.c	2004-01-28 00:52:59.000000000 +0000
@@ -247,6 +247,23 @@
 	return slot;
 }
 
+static inline void destroy_block(struct inode *inode, unsigned long block)
+{
+#ifdef CONFIG_EXT2_FS_PRIVACY
+	struct buffer_head	* bh;
+
+	bh = sb_getblk(inode->i_sb, block);
+
+	memset(bh->b_data, 0x00, bh->b_size);
+
+	mark_buffer_dirty(bh);
+	wait_on_buffer(bh);
+	brelse(bh);
+
+	return;
+#endif
+}
+
 /* Free given blocks, update quota and i_blocks field */
 void ext2_free_blocks (struct inode * inode, unsigned long block,
 		       unsigned long count)
@@ -319,6 +336,8 @@
 				   "bit already cleared for block %lu", block);
 		else {
 			DQUOT_FREE_BLOCK(inode, 1);
+
+			destroy_block(sb, block);
 			gdp->bg_free_blocks_count =
 				cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1);
 			es->s_free_blocks_count =
--- linux-2.4.24/fs/ext2/dir.c	2002-11-28 23:53:15.000000000 +0000
+++ linux-2.4.24/fs/ext2-privacy/dir.c	2004-01-25 17:15:27.000000000 +0000
@@ -468,6 +468,15 @@
 	return err;
 }
 
+static inline mark_deleted_dir(struct ext2_dir_entry_2 *dir)
+{
+#ifndef CONFIG_EXT2_FS_PRIVACY
+	dir->inode = 0;
+#else
+	memset(dir, 0, dir->rec_len);
+#endif
+}
+
 /*
  * ext2_delete_entry deletes a directory entry by merging it with the
  * previous entry. Page is up-to-date. Releases the page.
@@ -495,7 +504,7 @@
 		BUG();
 	if (pde)
 		pde->rec_len = cpu_to_le16(to-from);
-	dir->inode = 0;
+	mark_deleted_dir(dir);
 	err = ext2_commit_chunk(page, from, to);
 	UnlockPage(page);
 	ext2_put_page(page);
--- linux-2.4.24/fs/ext2/inode.c	2003-06-13 15:51:37.000000000 +0100
+++ linux-2.4.24/fs/ext2-privacy/inode.c	2004-01-27 21:33:59.000000000 +0000
@@ -46,6 +46,36 @@
 	ext2_discard_prealloc (inode);
 }
 
+static inline void delete_inode(struct inode *inode)
+{
+#ifndef CONFIG_EXT2_FS_PRIVACY
+	inode->u.ext2_i.i_dtime	= CURRENT_TIME;
+#else
+	inode->i_mode	= 0;
+	inode->i_uid	= 0;
+	inode->i_gid	= 0;
+	inode->i_nlink	= 0;
+	inode->i_atime	= 0;
+	inode->i_ctime	= 0;
+	inode->i_mtime	= 0;
+	inode->u.ext2_i.i_dtime	= 0;
+	inode->u.ext2_i.i_flags	= 0;
+	inode->u.ext2_i.i_faddr	= 0;
+	inode->u.ext2_i.i_frag_no	= 0;
+	inode->u.ext2_i.i_frag_size	= 0;
+	inode->u.ext2_i.i_file_acl	= 0;
+	inode->i_generation	= 0;
+#endif
+}
+
+static inline void delete_blocks(struct inode *inode)
+{
+#ifdef CONFIG_EXT2_FS_PRIVACY
+	inode->i_blocks	= 0;
+	memset(&inode->u.ext2_i.i_data, 0x00, sizeof(inode->u.ext2_i.i_data));
+#endif
+}
+
 /*
  * Called at the last iput() if i_nlink is zero.
  */
@@ -57,12 +87,18 @@
 	    inode->i_ino == EXT2_ACL_IDX_INO ||
 	    inode->i_ino == EXT2_ACL_DATA_INO)
 		goto no_delete;
-	inode->u.ext2_i.i_dtime	= CURRENT_TIME;
+
+	delete_inode(inode);
 	mark_inode_dirty(inode);
 	ext2_update_inode(inode, IS_SYNC(inode));
+
 	inode->i_size = 0;
 	if (inode->i_blocks)
 		ext2_truncate (inode);
+	delete_blocks(inode);
+       mark_inode_dirty(inode);
+       ext2_update_inode(inode, IS_SYNC(inode));
+
 	ext2_free_inode (inode);
 
 	unlock_kernel();

[-- Attachment #3: privacy_patch_ext3 --]
[-- Type: text/plain, Size: 2505 bytes --]

--- linux-2.4.24/fs/Config.in	2003-11-28 18:26:21.000000000 +0000
+++ linux-2.4.24/fs/Config.in-ext3-privacy	2004-01-27 21:57:22.000000000 +0000
@@ -34,6 +34,7 @@
 # dep_tristate '  Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS
 define_bool CONFIG_JBD $CONFIG_EXT3_FS
 dep_mbool '  JBD (ext3) debugging support' CONFIG_JBD_DEBUG $CONFIG_JBD
+dep_mbool '  ext3 privacy support' CONFIG_EXT3_FS_PRIVACY $CONFIG_EXT3_FS
 
 # msdos file systems
 tristate 'DOS FAT fs support' CONFIG_FAT_FS
--- linux-2.4.24/fs/ext3/balloc.c	2003-06-13 15:51:37.000000000 +0100
+++ linux-2.4.24/fs/ext3-privacy/balloc.c	2004-01-28 00:44:56.000000000 +0000
@@ -252,6 +252,23 @@
 	return slot;
 }
 
+static inline void destroy_block(struct inode *inode, unsigned long block)
+{
+#ifdef CONFIG_EXT3_FS_PRIVACY
+	struct buffer_head	* bh;
+
+	bh = sb_getblk(inode->i_sb, block);
+
+	memset(bh->b_data, 0x00, bh->b_size);
+
+	mark_buffer_dirty(bh);
+	wait_on_buffer(bh);
+	brelse(bh);
+
+	return;
+#endif
+}
+
 /* Free given blocks, update quota and i_blocks field */
 void ext3_free_blocks (handle_t *handle, struct inode * inode,
 			unsigned long block, unsigned long count)
@@ -370,6 +387,7 @@
 			BUFFER_TRACE(bitmap_bh, "bit already cleared");
 		} else {
 			dquot_freed_blocks++;
+			destroy_block(sb, block);
 			gdp->bg_free_blocks_count =
 			  cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1);
 			es->s_free_blocks_count =
--- linux-2.4.24/fs/ext3/inode.c	2003-08-25 12:44:43.000000000 +0100
+++ linux-2.4.24/fs/ext3-privacy/inode.c	2004-01-27 21:48:54.000000000 +0000
@@ -172,6 +172,28 @@
 	ext3_discard_prealloc (inode);
 }
 
+static inline void delete_inode(struct inode *inode)
+{
+#ifndef CONFIG_EXT3_FS_PRIVACY
+	inode->u.ext3_i.i_dtime	= CURRENT_TIME;
+#else
+	inode->i_mode	= 0;
+	inode->i_uid	= 0;
+	inode->i_gid	= 0;
+	inode->i_nlink	= 0;
+	inode->i_size	= 0;
+	inode->i_blocks	= 0;
+	inode->i_atime	= 0;
+	inode->i_ctime	= 0;
+	inode->i_mtime	= 0;
+	inode->u.ext3_i.i_dtime	= 0;
+	inode->u.ext3_i.i_flags	= 0;
+	inode->u.ext3_i.i_file_acl	= 0;
+	inode->i_generation	= 0;
+	memset(&inode->u.ext3_i.i_data, 0x00, sizeof(inode->u.ext3_i.i_data));
+#endif
+}
+
 /*
  * Called at the last iput() if i_nlink is zero.
  */
@@ -211,7 +233,7 @@
 	 * (Well, we could do this if we need to, but heck - it works)
 	 */
 	ext3_orphan_del(handle, inode);
-	inode->u.ext3_i.i_dtime	= CURRENT_TIME;
+	delete_inode(inode);
 
 	/* 
 	 * One subtle ordering requirement: if anything has gone wrong

             reply	other threads:[~2004-01-28 16:33 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-01-28 16:30 the grugq [this message]
2004-02-03 22:20 ` PATCH - ext2fs privacy (i.e. secure deletion) patch Pavel Machek
2004-02-04  0:33   ` the grugq
2004-02-04  0:43     ` Pavel Machek
2004-02-04  0:48       ` the grugq
2004-02-04  0:55         ` Pavel Machek
2004-02-04  0:58           ` the grugq
2004-02-04  1:10             ` Mike Fedyk
2004-02-04  6:29       ` Theodore Ts'o
2004-02-04 13:08         ` the grugq
2004-02-04 17:05           ` Bill Davidsen
2004-02-04 17:14             ` Valdis.Kletnieks
2004-02-04 23:47               ` Bill Davidsen
2004-02-04 23:51                 ` the grugq
2004-02-05  1:48                 ` the grugq
2004-02-05  4:38                 ` Valdis.Kletnieks
2004-02-07  3:30                   ` Bill Davidsen
2004-02-05  3:35               ` Theodore Ts'o
2004-02-06  0:00                 ` the grugq
2004-02-12 22:59         ` Robert White
2004-02-13  3:41           ` Jamie Lokier
2004-02-13 21:30             ` Robert White
2004-02-18  3:48             ` Bill Davidsen
2004-02-18  9:48               ` Jamie Lokier
2004-02-17 12:00           ` Pavel Machek
2004-02-04  3:20     ` Valdis.Kletnieks
2004-02-07  0:20       ` Jamie Lokier
2004-02-07  1:15         ` Hans Reiser
2004-02-07  1:29           ` the grugq
2004-02-07  5:40             ` Hans Reiser
2004-02-07  9:55               ` the grugq
2004-02-07 10:47                 ` Jamie Lokier
2004-02-07 11:02                   ` the grugq
2004-02-07 11:09                     ` Jamie Lokier
2004-02-07 11:46                       ` the grugq
2004-02-07 12:01                         ` Jamie Lokier
2004-02-07 16:52                           ` Hans Reiser
2004-02-07 17:22                           ` Pavel Machek
2004-02-08  0:04                             ` Jamie Lokier
2004-02-07 16:50                         ` Hans Reiser
2004-02-07 16:44                   ` Hans Reiser
2004-02-09 12:07                     ` Edward Shishkin
2004-02-10  7:18                       ` Hans Reiser
2004-02-07  2:17           ` Jamie Lokier
  -- strict thread matches above, loose matches on Subject: below --
2004-02-07  9:55 Albert Cahalan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4017E3B9.3090605@hcunix.net \
    --to=grugq@hcunix.net \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox