linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/3] ext4 crypto: back up encrypted files
@ 2015-12-10 15:04 Theodore Ts'o
  2015-12-16 15:10 ` Jan Kara
  0 siblings, 1 reply; 4+ messages in thread
From: Theodore Ts'o @ 2015-12-10 15:04 UTC (permalink / raw)
  To: Ext4 Developers List; +Cc: mhalcrow, Theodore Ts'o

This patches allow backing up encrypted files without having access to
the key.  Unfortunately, the key *is* necessary to restore the files,
because establishing a link means that we have to manipulate the both
the encrypted directory and the encrypted file, and doing this through
the VFS interface is non-trivial.  So we have an ioctl which extracts
the encrypted file name, and that in combination with the encryption
metadata for the directory should be sufficient to restore the file
name assuming the restore is done with access to the user's master
key.

The other tricky bit is that if the file's i_size is not a multiple of
the AES block size, we need to be able to copy a handful of bytes
before i_size --- and O_DIRECT reads don't allow that.  There are two
ways of solving this.  One would be an new DIO_FLAG that rounds i_size
up to the file system blocksize, which we would pass when reading
encrypted files using O_DIRECT.  This would require changes to the
core direct I/O, and may be controversial.  It also may make it more
difficult to back port these patches to ancient BSP kernels.

So what we're doing for now is admittedly a hack.  Since encrypted
files are read-only without access to the key, it is safe to create a
shadow copy of the inode structure, and round up i_size in the shadow
structure.  We only do this when reading the last block in the file,
so the overhead shouldn't be too bad.

The process doing the store will need to truncate the file back down
to the original file when it has access to the key.  We can't do this
without the key because the kernel zero fills the block between i_size
and the end of the block.  (This is also why it's not a security issue
to round i_size up to the end of the block; there is no chance we will
be revealing stale data.)  So this means that for the purposes of
doing the encrypted backup, the backup will need to store the
encrypted file name, the directory's encrypted metadata, and the
original i_size in some convenient ouf-of-band backup metadata store.

Theodore Ts'o (3):
  ext4 crypto: add ciphertext_access mount option
  ext4 crypto: add ioctls to allow backup of encryption metadata
  ext4 crypto: add missing locking for keyring_key access

 fs/ext4/crypto_key.c  | 61 +++++++++++++++++++++++++++++++++++++++++++++++-
 fs/ext4/ext4.h        | 12 ++++++++++
 fs/ext4/ext4_crypto.h |  8 +++++++
 fs/ext4/file.c        |  5 +++-
 fs/ext4/indirect.c    | 24 +++++++++++++++----
 fs/ext4/inode.c       | 17 ++++++++------
 fs/ext4/ioctl.c       | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/ext4/namei.c       | 24 +++++++++++++++++++
 fs/ext4/super.c       | 48 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 249 insertions(+), 14 deletions(-)

-- 
2.5.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 0/3] ext4 crypto: back up encrypted files
@ 2015-12-10 16:31 Theodore Ts'o
  0 siblings, 0 replies; 4+ messages in thread
From: Theodore Ts'o @ 2015-12-10 16:31 UTC (permalink / raw)
  To: Ext4 Developers List; +Cc: mhalcrow

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

And here are some test programs / scripts that I've been using to test
these patches.  They also demonstrate how to use the ioctl's.

      		     	  	      	     - Ted

[-- Attachment #2: ext4-crypto-cp-md.c --]
[-- Type: text/x-csrc, Size: 1920 bytes --]

/*
 * Test program to trigger the precache ioctl
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>

typedef unsigned long u32;

struct ext4_encrypted_metadata {
	u32 len;
	char metadata[288];
};

#ifndef EXT4_IOC_GET_ENCRYPTION_METADATA
#define EXT4_IOC_GET_ENCRYPTION_METADATA _IOWR('f', 22, struct ext4_encrypted_metadata)
#endif
#ifndef EXT4_IOC_SET_ENCRYPTION_METADATA
#define EXT4_IOC_SET_ENCRYPTION_METADATA _IOR('f', 23, struct ext4_encrypted_metadata)
#endif
#ifndef EXT4_IOC_GET_ENCRYPTED_FILENAME
#define EXT4_IOC_GET_ENCRYPTED_FILENAME	_IOWR('f', 24, struct ext4_encrypted_metadata)
#endif

void print_mdata(const char *s, struct ext4_encrypted_metadata *mdata)
{
	int i;

	printf("%s len %d: \n", s, mdata->len);
	for (i = 0; i < mdata->len; i++)
		printf("%02x ", mdata->metadata[i] & 0xFF);
	printf("\n");
}

int main(int argc, char **argv)
{
	int	s_fd, d_fd = -1;
	int	oflags = O_RDONLY;
	struct ext4_encrypted_metadata f_mdata, fn_mdata;

	if (argc < 2 || argc > 3) {
		fprintf(stderr, "Usage: %s source [destination]\n",
			argv[0]);
		exit(1);
	}
	s_fd = open(argv[1], O_RDONLY);
	if (s_fd < 0) {
		perror(argv[1]);
		exit(1);
	}
	if (argc > 2) {
		d_fd = open(argv[2], O_RDONLY);
		if (d_fd < 0) {
			perror(argv[2]);
			exit(1);
		}
	}
	f_mdata.len = sizeof(f_mdata.metadata);
	if (ioctl(s_fd, EXT4_IOC_GET_ENCRYPTION_METADATA, &f_mdata)) {
		perror("EXT4_IOC_GET_ENCRYPTION_METADATA");
		f_mdata.len = 0;
	} else {
		print_mdata("file", &f_mdata);
	}
	fn_mdata.len = sizeof(fn_mdata.metadata);
	if (ioctl(s_fd, EXT4_IOC_GET_ENCRYPTED_FILENAME, &fn_mdata)) {
		perror("EXT4_IOC_GET_ENCRYPTED_FILENAME");
	} else {
		print_mdata("filename", &fn_mdata);
	}
	if (d_fd >= 0 && f_mdata.len > 0) {
		if (ioctl(d_fd, EXT4_IOC_SET_ENCRYPTION_METADATA, &f_mdata)) {
			perror("EXT4_IOC_SET_ENCRYPTION_METADATA");
		}
	}
	return 0;
}

[-- Attachment #3: test-cp-md --]
[-- Type: text/plain, Size: 1351 bytes --]

#!/bin/bash -vx
umount /vdc
dmesg -n 7
mke2fs -Fq -t ext4 -O encrypt /dev/vdc
debugfs -w -R "ssv encrypt_pw_salt deadbeef-dead-beef-1234-5678deadbeef" /dev/vdc
mount -t ext4 /dev/vdc /vdc
mkdir /vdc/a
echo foobar | e4crypt add_key /vdc/a
cat << EOF > /vdc/a/test_file
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In accumsan
mi ac magna vestibulum commodo. Cras facilisis posuere tellus in
efficitur. Sed mollis mi eget elit vulputate pellentesque. Ut vitae
laoreet diam. Aliquam sem leo, luctus eget leo eu, hendrerit egestas
risus. Nulla non nisi ut nisl suscipit dictum. Donec eleifend dapibus
mi eu porttitor. Nulla lacinia tellus nec porttitor tincidunt. Nam
lectus nibh, fringilla sit amet enim id, consequat tincidunt
mauris. Ut blandit orci vitae elit suscipit varius. Donec vel sem
tristique, efficitur felis sit amet, sagittis metus. In laoreet
ultricies interdum. Aliquam felis est, pharetra eget nisl vel,
fringilla aliquet velit. Etiam ut augue ut ante fringilla gravida quis
a arcu.
EOF
umount /vdc
keyctl purge logon
mount -t ext4 -o ciphertext_access /dev/vdc /vdc
F=/vdc/a/$(ls /vdc/a)
dd if=$F of=/vdc/out iflag=direct oflag=direct bs=4k
/vdb/ext4-crypto-cp-md $F /vdc/out
umount /vdc
mount -t ext4 /dev/vdc /vdc
echo foobar | e4crypt add_key
truncate --reference /vdc/a/test_file /vdc/out
diff /vdc/out /vdc/a/test_file

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 0/3] ext4 crypto: back up encrypted files
  2015-12-10 15:04 Theodore Ts'o
@ 2015-12-16 15:10 ` Jan Kara
  2015-12-18  0:49   ` Theodore Ts'o
  0 siblings, 1 reply; 4+ messages in thread
From: Jan Kara @ 2015-12-16 15:10 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Ext4 Developers List, mhalcrow

On Thu 10-12-15 10:04:36, Ted Tso wrote:
> This patches allow backing up encrypted files without having access to
> the key.  Unfortunately, the key *is* necessary to restore the files,
> because establishing a link means that we have to manipulate the both
> the encrypted directory and the encrypted file, and doing this through
> the VFS interface is non-trivial.  So we have an ioctl which extracts
> the encrypted file name, and that in combination with the encryption
> metadata for the directory should be sufficient to restore the file
> name assuming the restore is done with access to the user's master
> key.
> 
> The other tricky bit is that if the file's i_size is not a multiple of
> the AES block size, we need to be able to copy a handful of bytes
> before i_size --- and O_DIRECT reads don't allow that.  There are two

Umm, I don't quite follow. O_DIRECT reads will actually read final file
block in full even if i_size is somewhere in the middle of it. We then
report only data upto i_size as transferred but that's not really
important for you. That being said I agree that relying on this is hacky
but for direct IO it kind of makes sense and creating special shadow
inode is IMO even bigger hack...

> ways of solving this.  One would be an new DIO_FLAG that rounds i_size
> up to the file system blocksize, which we would pass when reading
> encrypted files using O_DIRECT.  This would require changes to the
> core direct I/O, and may be controversial.  It also may make it more
> difficult to back port these patches to ancient BSP kernels.
> 
> So what we're doing for now is admittedly a hack.  Since encrypted
> files are read-only without access to the key, it is safe to create a
> shadow copy of the inode structure, and round up i_size in the shadow
> structure.  We only do this when reading the last block in the file,
> so the overhead shouldn't be too bad.

I'm rather concerned about the locking implications of the shadow inode.
For example holding i_data_sem for reading in ext4_get_blocks() no longer
protects against changes of inode allocation information. Thus if e.g.
another process does mmaped write allocating more blocks, we can see
inconsistent extent tree from direct read. And that's just one example of
problems we can hit, I'm not sure there are not others.

								Honza
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3 0/3] ext4 crypto: back up encrypted files
  2015-12-16 15:10 ` Jan Kara
@ 2015-12-18  0:49   ` Theodore Ts'o
  0 siblings, 0 replies; 4+ messages in thread
From: Theodore Ts'o @ 2015-12-18  0:49 UTC (permalink / raw)
  To: Jan Kara; +Cc: Ext4 Developers List, mhalcrow

On Wed, Dec 16, 2015 at 04:10:10PM +0100, Jan Kara wrote:
> 
> Umm, I don't quite follow. O_DIRECT reads will actually read final file
> block in full even if i_size is somewhere in the middle of it. We then
> report only data upto i_size as transferred but that's not really
> important for you.

I had tried this approach first but it appeared that the data was
getting zero'ed between i_size and the end of the block.  It turns out
it was a bug in my test program, sigh.

I agree about the locking issues.  It isn't so much of an issue since
without the encryption key, you can't modify the file, so this
prevents most of the nasty races.  Of course, it could be the case
that user A (say, root) doesn't have access to the key, but user B
(say the user account) does have access.  So dropping the shadow inode
is the better way to go.

Thanks!!

						- Ted

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2015-12-18  0:49 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-10 16:31 [PATCH v3 0/3] ext4 crypto: back up encrypted files Theodore Ts'o
  -- strict thread matches above, loose matches on Subject: below --
2015-12-10 15:04 Theodore Ts'o
2015-12-16 15:10 ` Jan Kara
2015-12-18  0:49   ` Theodore Ts'o

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).