linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement
@ 2016-12-19 22:20 Eric Biggers
  2016-12-19 22:20 ` [PATCH v2 2/5] fscrypt: fix renaming and linking special files Eric Biggers
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Eric Biggers @ 2016-12-19 22:20 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Theodore Y . Ts'o, Jaegeuk Kim, Richard Weinberger, Eric Biggers

From: Eric Biggers <ebiggers@google.com>

Filesystem encryption is designed to enforce that all files in an
encrypted directory tree use the same encryption policy.  Operations
that violate this constraint are supposed to fail with EPERM.  There was
one case that was missed, however: the cross-rename operation (i.e.
renameat2 with RENAME_EXCHANGE) allowed two files with different
encryption policies to be exchanged, provided that neither encryption
key was available.

To fix this, when we can't compare the fscrypt_info structs because the
key is unavailable, compare the fscrypt_context structs instead.

This will be covered by a test in my encryption xfstests patchset.

Fixes: b7236e21d55f ("ext4 crypto: reorganize how we store keys in the inode")
Signed-off-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Richard Weinberger <richard@nod.at>
Cc: stable@vger.kernel.org
---
 fs/crypto/policy.c | 76 ++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 57 insertions(+), 19 deletions(-)

diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index 6ed7c2e..5de0633 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -169,22 +169,46 @@ int fscrypt_ioctl_get_policy(struct file *filp, void __user *arg)
 }
 EXPORT_SYMBOL(fscrypt_ioctl_get_policy);
 
+/**
+ * fscrypt_has_permitted_context() - is a file's encryption policy permitted
+ *				     within its parent directory?
+ *
+ * @parent: inode for parent directory
+ * @child: inode for file being looked up or linked into the directory
+ *
+ * Filesystems must call this function during lookup in an encrypted directory
+ * and before any operation that involves linking a file into an encrypted
+ * directory, including link, rename, and cross rename.  It enforces the
+ * constraint that within a given encrypted directory tree, all files use the
+ * same encryption policy.  The lookup check is needed to detect offline
+ * violations of this constraint, whereas the other checks are needed to prevent
+ * online violations of this constraint.
+ *
+ * Return: 1 if permitted, 0 if forbidden.  If forbidden, the caller must fail
+ * the filesystem operation with EPERM.
+ */
 int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
 {
-	struct fscrypt_info *parent_ci, *child_ci;
+	const struct fscrypt_operations *cops = parent->i_sb->s_cop;
+	const struct fscrypt_info *parent_ci, *child_ci;
+	struct fscrypt_context parent_ctx, child_ctx;
 	int res;
 
-	if ((parent == NULL) || (child == NULL)) {
-		printk(KERN_ERR	"parent %p child %p\n", parent, child);
-		BUG_ON(1);
-	}
-
-	/* no restrictions if the parent directory is not encrypted */
-	if (!parent->i_sb->s_cop->is_encrypted(parent))
+	/* No restrictions if the parent directory is unencrypted */
+	if (!cops->is_encrypted(parent))
 		return 1;
-	/* if the child directory is not encrypted, this is always a problem */
-	if (!parent->i_sb->s_cop->is_encrypted(child))
+
+	/* Encrypted directories must not contain unencrypted files */
+	if (!cops->is_encrypted(child))
 		return 0;
+
+	/*
+	 * Both parent and child are encrypted, so verify they use the same
+	 * encryption policy.  Compare the fscrypt_info structs if the keys are
+	 * available, otherwise compare the fscrypt_context structs directly.
+	 * In any case, if an unexpected error occurs, fall back to "forbidden".
+	 */
+
 	res = fscrypt_get_encryption_info(parent);
 	if (res)
 		return 0;
@@ -193,17 +217,31 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
 		return 0;
 	parent_ci = parent->i_crypt_info;
 	child_ci = child->i_crypt_info;
-	if (!parent_ci && !child_ci)
-		return 1;
-	if (!parent_ci || !child_ci)
+	if (parent_ci && child_ci) {
+		return memcmp(parent_ci->ci_master_key, child_ci->ci_master_key,
+			      FS_KEY_DESCRIPTOR_SIZE) == 0 &&
+			(parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
+			(parent_ci->ci_filename_mode ==
+			 child_ci->ci_filename_mode) &&
+			(parent_ci->ci_flags == child_ci->ci_flags);
+	}
+
+	res = cops->get_context(parent, &parent_ctx, sizeof(parent_ctx));
+	if (res != sizeof(parent_ctx))
 		return 0;
 
-	return (memcmp(parent_ci->ci_master_key,
-			child_ci->ci_master_key,
-			FS_KEY_DESCRIPTOR_SIZE) == 0 &&
-		(parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
-		(parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
-		(parent_ci->ci_flags == child_ci->ci_flags));
+	res = cops->get_context(child, &child_ctx, sizeof(child_ctx));
+	if (res != sizeof(child_ctx))
+		return 0;
+
+	return memcmp(parent_ctx.master_key_descriptor,
+		      child_ctx.master_key_descriptor,
+		      FS_KEY_DESCRIPTOR_SIZE) == 0 &&
+		(parent_ctx.contents_encryption_mode ==
+		 child_ctx.contents_encryption_mode) &&
+		(parent_ctx.filenames_encryption_mode ==
+		 child_ctx.filenames_encryption_mode) &&
+		(parent_ctx.flags == child_ctx.flags);
 }
 EXPORT_SYMBOL(fscrypt_has_permitted_context);
 
-- 
2.8.0.rc3.226.g39d4020


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

* [PATCH v2 2/5] fscrypt: fix renaming and linking special files
  2016-12-19 22:20 [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Eric Biggers
@ 2016-12-19 22:20 ` Eric Biggers
  2016-12-31  5:49   ` Theodore Ts'o
  2016-12-19 22:20 ` [PATCH v2 3/5] ext4: consolidate fscrypt_has_permitted_context() checks Eric Biggers
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Eric Biggers @ 2016-12-19 22:20 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Theodore Y . Ts'o, Jaegeuk Kim, Richard Weinberger, Eric Biggers

From: Eric Biggers <ebiggers@google.com>

Attempting to link a device node, named pipe, or socket file into an
encrypted directory through rename(2) or link(2) always failed with
EPERM.  This happened because fscrypt_has_permitted_context() saw that
the file was unencrypted and forbid creating the link.  This behavior
was unexpected because such files are never encrypted; only regular
files, directories, and symlinks can be encrypted.

To fix this, make fscrypt_has_permitted_context() always return true on
special files.

This will be covered by a test in my encryption xfstests patchset.

Fixes: 9bd8212f981e ("ext4 crypto: add encryption policy and password salt support")
Signed-off-by: Eric Biggers <ebiggers@google.com>
Reviewed-by: Richard Weinberger <richard@nod.at>
Cc: stable@vger.kernel.org
---
 fs/crypto/policy.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/fs/crypto/policy.c b/fs/crypto/policy.c
index 5de0633..2e50cbc 100644
--- a/fs/crypto/policy.c
+++ b/fs/crypto/policy.c
@@ -198,6 +198,11 @@ int fscrypt_has_permitted_context(struct inode *parent, struct inode *child)
 	if (!cops->is_encrypted(parent))
 		return 1;
 
+	/* No restrictions on file types which are never encrypted */
+	if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
+	    !S_ISLNK(child->i_mode))
+		return 1;
+
 	/* Encrypted directories must not contain unencrypted files */
 	if (!cops->is_encrypted(child))
 		return 0;
-- 
2.8.0.rc3.226.g39d4020


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

* [PATCH v2 3/5] ext4: consolidate fscrypt_has_permitted_context() checks
  2016-12-19 22:20 [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Eric Biggers
  2016-12-19 22:20 ` [PATCH v2 2/5] fscrypt: fix renaming and linking special files Eric Biggers
@ 2016-12-19 22:20 ` Eric Biggers
  2016-12-28  5:41   ` Theodore Ts'o
  2016-12-19 22:20 ` [PATCH v2 4/5] f2fs: " Eric Biggers
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Eric Biggers @ 2016-12-19 22:20 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Theodore Y . Ts'o, Jaegeuk Kim, Richard Weinberger, Eric Biggers

From: Eric Biggers <ebiggers@google.com>

Now that fscrypt_has_permitted_context() compares the fscrypt_context
rather than the fscrypt_info when needed, it is no longer necessary to
delay fscrypt_has_permitted_context() from ->lookup() to ->open() for
regular files, as introduced in commit ff978b09f973 ("ext4 crypto: move
context consistency check to ext4_file_open()").  Therefore the check in
->open(), along with the dget_parent() hack, can be removed.  It's also
no longer necessary to check the file type before calling
fscrypt_has_permitted_context().

This patch should not be applied before my other two patches:

    fscrypt: fix loophole in one-encryption-policy-per-tree enforcement
    fscrypt: fix renaming and linking special files

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 fs/ext4/file.c  | 12 ------------
 fs/ext4/namei.c | 10 ++--------
 2 files changed, 2 insertions(+), 20 deletions(-)

diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index b5f1844..2123cd8 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -398,7 +398,6 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
 	struct super_block *sb = inode->i_sb;
 	struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
 	struct vfsmount *mnt = filp->f_path.mnt;
-	struct dentry *dir;
 	struct path path;
 	char buf[64], *cp;
 	int ret;
@@ -443,17 +442,6 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
 			return -ENOKEY;
 	}
 
-	dir = dget_parent(file_dentry(filp));
-	if (ext4_encrypted_inode(d_inode(dir)) &&
-			!fscrypt_has_permitted_context(d_inode(dir), inode)) {
-		ext4_warning(inode->i_sb,
-			     "Inconsistent encryption contexts: %lu/%lu",
-			     (unsigned long) d_inode(dir)->i_ino,
-			     (unsigned long) inode->i_ino);
-		dput(dir);
-		return -EPERM;
-	}
-	dput(dir);
 	/*
 	 * Set up the jbd2_inode if we are opening the inode for
 	 * writing and the journal is present
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index eadba91..eb8b064 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1612,17 +1612,11 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
 			return ERR_PTR(-EFSCORRUPTED);
 		}
 		if (!IS_ERR(inode) && ext4_encrypted_inode(dir) &&
-		    (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
 		    !fscrypt_has_permitted_context(dir, inode)) {
-			int nokey = ext4_encrypted_inode(inode) &&
-				!fscrypt_has_encryption_key(inode);
-			iput(inode);
-			if (nokey)
-				return ERR_PTR(-ENOKEY);
 			ext4_warning(inode->i_sb,
 				     "Inconsistent encryption contexts: %lu/%lu",
-				     (unsigned long) dir->i_ino,
-				     (unsigned long) inode->i_ino);
+				     dir->i_ino, inode->i_ino);
+			iput(inode);
 			return ERR_PTR(-EPERM);
 		}
 	}
-- 
2.8.0.rc3.226.g39d4020


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

* [PATCH v2 4/5] f2fs: consolidate fscrypt_has_permitted_context() checks
  2016-12-19 22:20 [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Eric Biggers
  2016-12-19 22:20 ` [PATCH v2 2/5] fscrypt: fix renaming and linking special files Eric Biggers
  2016-12-19 22:20 ` [PATCH v2 3/5] ext4: consolidate fscrypt_has_permitted_context() checks Eric Biggers
@ 2016-12-19 22:20 ` Eric Biggers
  2016-12-19 22:20 ` [PATCH v2 5/5] ubifs: " Eric Biggers
  2016-12-28  3:48 ` [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Theodore Ts'o
  4 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2016-12-19 22:20 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Theodore Y . Ts'o, Jaegeuk Kim, Richard Weinberger, Eric Biggers

From: Eric Biggers <ebiggers@google.com>

This ports the changes from the corresponding ext4 patch to f2fs.

This patch should not be applied before my other two patches:

    fscrypt: fix loophole in one-encryption-policy-per-tree enforcement
    fscrypt: fix renaming and linking special files

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 fs/f2fs/file.c  | 15 +++++----------
 fs/f2fs/namei.c |  7 ++-----
 2 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 49f10dc..381d39b 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -443,23 +443,18 @@ static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
 static int f2fs_file_open(struct inode *inode, struct file *filp)
 {
 	int ret = generic_file_open(inode, filp);
-	struct dentry *dir;
 
-	if (!ret && f2fs_encrypted_inode(inode)) {
+	if (ret)
+		return ret;
+
+	if (f2fs_encrypted_inode(inode)) {
 		ret = fscrypt_get_encryption_info(inode);
 		if (ret)
 			return -EACCES;
 		if (!fscrypt_has_encryption_key(inode))
 			return -ENOKEY;
 	}
-	dir = dget_parent(file_dentry(filp));
-	if (f2fs_encrypted_inode(d_inode(dir)) &&
-			!fscrypt_has_permitted_context(d_inode(dir), inode)) {
-		dput(dir);
-		return -EPERM;
-	}
-	dput(dir);
-	return ret;
+	return 0;
 }
 
 int truncate_data_blocks_range(struct dnode_of_data *dn, int count)
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 56c19b0..53ff18f 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -322,11 +322,8 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
 			goto err_out;
 	}
 	if (!IS_ERR(inode) && f2fs_encrypted_inode(dir) &&
-			(S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
-			!fscrypt_has_permitted_context(dir, inode)) {
-		bool nokey = f2fs_encrypted_inode(inode) &&
-			!fscrypt_has_encryption_key(inode);
-		err = nokey ? -ENOKEY : -EPERM;
+	    !fscrypt_has_permitted_context(dir, inode)) {
+		err = -EPERM;
 		goto err_out;
 	}
 	return d_splice_alias(inode, dentry);
-- 
2.8.0.rc3.226.g39d4020


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

* [PATCH v2 5/5] ubifs: consolidate fscrypt_has_permitted_context() checks
  2016-12-19 22:20 [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Eric Biggers
                   ` (2 preceding siblings ...)
  2016-12-19 22:20 ` [PATCH v2 4/5] f2fs: " Eric Biggers
@ 2016-12-19 22:20 ` Eric Biggers
  2016-12-28  3:48 ` [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Theodore Ts'o
  4 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2016-12-19 22:20 UTC (permalink / raw)
  To: linux-fsdevel
  Cc: Theodore Y . Ts'o, Jaegeuk Kim, Richard Weinberger, Eric Biggers

From: Eric Biggers <ebiggers@google.com>

This ports the changes from the corresponding ext4 patch to ubifs.
ubifs was also missing the fscrypt_has_permitted_context() check in
ubifs_lookup(), so add it.

This patch should not be applied before my other two patches:

    fscrypt: fix loophole in one-encryption-policy-per-tree enforcement
    fscrypt: fix renaming and linking special files

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 fs/ubifs/dir.c  | 10 ++++++++++
 fs/ubifs/file.c | 20 +-------------------
 2 files changed, 11 insertions(+), 19 deletions(-)

diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 528369f..d346f1e 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -285,6 +285,14 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 		goto out_dent;
 	}
 
+	if (ubifs_crypt_is_encrypted(dir) &&
+	    !fscrypt_has_permitted_context(dir, inode)) {
+		ubifs_err(c, "Inconsistent encryption contexts: %lu/%lu",
+			  dir->i_ino, inode->i_ino);
+		err = -EPERM;
+		goto out_inode;
+	}
+
 done:
 	kfree(dent);
 	fscrypt_free_filename(&nm);
@@ -295,6 +303,8 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
 	d_add(dentry, inode);
 	return NULL;
 
+out_inode:
+	iput(inode);
 out_dent:
 	kfree(dent);
 out_fname:
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index b0d7837..465a47f 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1630,30 +1630,12 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
 
 static int ubifs_file_open(struct inode *inode, struct file *filp)
 {
-	int ret;
-	struct dentry *dir;
-	struct ubifs_info *c = inode->i_sb->s_fs_info;
-
 	if (ubifs_crypt_is_encrypted(inode)) {
-		ret = fscrypt_get_encryption_info(inode);
-		if (ret)
+		if (fscrypt_get_encryption_info(inode))
 			return -EACCES;
 		if (!fscrypt_has_encryption_key(inode))
 			return -ENOKEY;
 	}
-
-	dir = dget_parent(file_dentry(filp));
-	if (ubifs_crypt_is_encrypted(d_inode(dir)) &&
-			!fscrypt_has_permitted_context(d_inode(dir), inode)) {
-		ubifs_err(c, "Inconsistent encryption contexts: %lu/%lu",
-			  (unsigned long) d_inode(dir)->i_ino,
-			  (unsigned long) inode->i_ino);
-		dput(dir);
-		ubifs_ro_mode(c, -EPERM);
-		return -EPERM;
-	}
-	dput(dir);
-
 	return 0;
 }
 
-- 
2.8.0.rc3.226.g39d4020


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

* Re: [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement
  2016-12-19 22:20 [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Eric Biggers
                   ` (3 preceding siblings ...)
  2016-12-19 22:20 ` [PATCH v2 5/5] ubifs: " Eric Biggers
@ 2016-12-28  3:48 ` Theodore Ts'o
  2016-12-28  5:22   ` [PATCH] ext4: don't allow encrypted operations without keys Theodore Ts'o
  4 siblings, 1 reply; 14+ messages in thread
From: Theodore Ts'o @ 2016-12-28  3:48 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-fsdevel, Jaegeuk Kim, Richard Weinberger, Eric Biggers

On Mon, Dec 19, 2016 at 02:20:12PM -0800, Eric Biggers wrote:
> From: Eric Biggers <ebiggers@google.com>
> 
> Filesystem encryption is designed to enforce that all files in an
> encrypted directory tree use the same encryption policy.  Operations
> that violate this constraint are supposed to fail with EPERM.  There was
> one case that was missed, however: the cross-rename operation (i.e.
> renameat2 with RENAME_EXCHANGE) allowed two files with different
> encryption policies to be exchanged, provided that neither encryption
> key was available.

I'm actually not sure this is the best way to address this issue.

What I think is better would be to forbid any renames if we are
missing the encryption key for the directory.  I had actually noticed
a problem here early when this worked:

root@kvm-xfstests:/# mount -o test_dummy_encryption /dev/vdc /vdc
root@kvm-xfstests:/# mkdir /vdc/test
root@kvm-xfstests:/# cp /etc/motd /vdc/test
root@kvm-xfstests:/# touch /vdc/test/empty
root@kvm-xfstests:/# umount /vdc
root@kvm-xfstests:/# mount /dev/vdc /vdc
root@kvm-xfstests:/# cd /vdc/test
root@kvm-xfstests:/vdc/test# ls -l
total 4
-rw-r--r-- 1 root root   0 Dec 27 22:35 6,LKNRJsp209FbXoSvJWzB
-rw-r--r-- 1 root root 286 Dec 27 22:35 uRJ5vJh9gE7vcomYMqTAyD
root@kvm-xfstests:/vdc/test# mv uRJ5vJh9gE7vcomYMqTAyD  6,LKNRJsp209FbXoSvJWzB
root@kvm-xfstests:/vdc/test# ls -l
total 4
-rw-r--r-- 1 root root 286 Dec 27 22:35 6,LKNRJsp209FbXoSvJWzB
root@kvm-xfstests:/vdc/test#

While there's no cryptographic reason why this can't be done
(obviously), and while a bad guy can always do something like this via
debugfs, I can't see any legitimate reason why we should allow this to
work.

It's one thing to allow a process without the encryption key
(generally with root privileges) to delete a file, but to rename two
files in an encrypted directory?  Or as you pointed out, allowing an
exchange of two files via RENAME_EXCHANGE?  Even if encryption
policies match, I don't think we should be allowing this at all.

	 	 	  	      	 - Ted

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

* [PATCH] ext4: don't allow encrypted operations without keys
  2016-12-28  3:48 ` [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Theodore Ts'o
@ 2016-12-28  5:22   ` Theodore Ts'o
  2017-01-05 19:26     ` Eric Biggers
  2017-02-04 21:44     ` Eric Biggers
  0 siblings, 2 replies; 14+ messages in thread
From: Theodore Ts'o @ 2016-12-28  5:22 UTC (permalink / raw)
  To: Ext4 Developers List
  Cc: Linux Filesystem Development List, jaegeuk, richard, ebiggers,
	Theodore Ts'o

While we allow deletes without the key, the following should not be
permitted:

# cd /vdc/encrypted-dir-without-key
# ls -l
total 4
-rw-r--r-- 1 root root   0 Dec 27 22:35 6,LKNRJsp209FbXoSvJWzB
-rw-r--r-- 1 root root 286 Dec 27 22:35 uRJ5vJh9gE7vcomYMqTAyD
# mv uRJ5vJh9gE7vcomYMqTAyD  6,LKNRJsp209FbXoSvJWzB

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
 fs/ext4/namei.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index eadba919f26b..45a5ba558074 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3525,6 +3525,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
 			EXT4_I(old_dentry->d_inode)->i_projid)))
 		return -EXDEV;
 
+	if ((ext4_encrypted_inode(old_dir) &&
+	     !fscrypt_has_encryption_key(old_dir)) ||
+	    (ext4_encrypted_inode(new_dir) &&
+	     !fscrypt_has_encryption_key(new_dir)))
+		return -ENOKEY;
+
 	retval = dquot_initialize(old.dir);
 	if (retval)
 		return retval;
@@ -3725,6 +3731,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
 	int retval;
 	struct timespec ctime;
 
+	if ((ext4_encrypted_inode(old_dir) &&
+	     !fscrypt_has_encryption_key(old_dir)) ||
+	    (ext4_encrypted_inode(new_dir) &&
+	     !fscrypt_has_encryption_key(new_dir)))
+		return -ENOKEY;
+
 	if ((ext4_encrypted_inode(old_dir) ||
 	     ext4_encrypted_inode(new_dir)) &&
 	    (old_dir != new_dir) &&
-- 
2.11.0.rc0.7.gbe5a750


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

* Re: [PATCH v2 3/5] ext4: consolidate fscrypt_has_permitted_context() checks
  2016-12-19 22:20 ` [PATCH v2 3/5] ext4: consolidate fscrypt_has_permitted_context() checks Eric Biggers
@ 2016-12-28  5:41   ` Theodore Ts'o
  2017-01-05 19:03     ` Eric Biggers
  0 siblings, 1 reply; 14+ messages in thread
From: Theodore Ts'o @ 2016-12-28  5:41 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-fsdevel, Jaegeuk Kim, Richard Weinberger, Eric Biggers

On Mon, Dec 19, 2016 at 02:20:14PM -0800, Eric Biggers wrote:
> From: Eric Biggers <ebiggers@google.com>
> 
> Now that fscrypt_has_permitted_context() compares the fscrypt_context
> rather than the fscrypt_info when needed, it is no longer necessary to
> delay fscrypt_has_permitted_context() from ->lookup() to ->open() for
> regular files, as introduced in commit ff978b09f973 ("ext4 crypto: move
> context consistency check to ext4_file_open()").  Therefore the check in
> ->open(), along with the dget_parent() hack, can be removed.  It's also
> no longer necessary to check the file type before calling
> fscrypt_has_permitted_context().

There's a downside to this change.  The change in the earlier commit
of this series teaches fscrypt_has_permitted_context() can fall back
to comparing the fscrypt_context.  That's all very well and good, but
it means that if you do a ls -l of an encrypted directory, and the key
is not present, we will have to do an xattr lookup for every file in
that directory.  Even if the key is present, it will force the
derivation of the per-file key of every file in that directory,
regardless of whether the file is opened or not.

	      	      	       	  	    - Ted

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

* Re: [PATCH v2 2/5] fscrypt: fix renaming and linking special files
  2016-12-19 22:20 ` [PATCH v2 2/5] fscrypt: fix renaming and linking special files Eric Biggers
@ 2016-12-31  5:49   ` Theodore Ts'o
  0 siblings, 0 replies; 14+ messages in thread
From: Theodore Ts'o @ 2016-12-31  5:49 UTC (permalink / raw)
  To: Eric Biggers; +Cc: linux-fsdevel, Jaegeuk Kim, Richard Weinberger, Eric Biggers

On Mon, Dec 19, 2016 at 02:20:13PM -0800, Eric Biggers wrote:
> From: Eric Biggers <ebiggers@google.com>
> 
> Attempting to link a device node, named pipe, or socket file into an
> encrypted directory through rename(2) or link(2) always failed with
> EPERM.  This happened because fscrypt_has_permitted_context() saw that
> the file was unencrypted and forbid creating the link.  This behavior
> was unexpected because such files are never encrypted; only regular
> files, directories, and symlinks can be encrypted.
> 
> To fix this, make fscrypt_has_permitted_context() always return true on
> special files.
> 
> This will be covered by a test in my encryption xfstests patchset.
> 
> Fixes: 9bd8212f981e ("ext4 crypto: add encryption policy and password salt support")
> Signed-off-by: Eric Biggers <ebiggers@google.com>
> Reviewed-by: Richard Weinberger <richard@nod.at>
> Cc: stable@vger.kernel.org

Thanks, applied.

						- Ted

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

* Re: [PATCH v2 3/5] ext4: consolidate fscrypt_has_permitted_context() checks
  2016-12-28  5:41   ` Theodore Ts'o
@ 2017-01-05 19:03     ` Eric Biggers
  0 siblings, 0 replies; 14+ messages in thread
From: Eric Biggers @ 2017-01-05 19:03 UTC (permalink / raw)
  To: Theodore Ts'o
  Cc: linux-fsdevel, Jaegeuk Kim, Richard Weinberger, Eric Biggers

On Wed, Dec 28, 2016 at 12:41:02AM -0500, Theodore Ts'o wrote:
> On Mon, Dec 19, 2016 at 02:20:14PM -0800, Eric Biggers wrote:
> > From: Eric Biggers <ebiggers@google.com>
> > 
> > Now that fscrypt_has_permitted_context() compares the fscrypt_context
> > rather than the fscrypt_info when needed, it is no longer necessary to
> > delay fscrypt_has_permitted_context() from ->lookup() to ->open() for
> > regular files, as introduced in commit ff978b09f973 ("ext4 crypto: move
> > context consistency check to ext4_file_open()").  Therefore the check in
> > ->open(), along with the dget_parent() hack, can be removed.  It's also
> > no longer necessary to check the file type before calling
> > fscrypt_has_permitted_context().
> 
> There's a downside to this change.  The change in the earlier commit
> of this series teaches fscrypt_has_permitted_context() can fall back
> to comparing the fscrypt_context.  That's all very well and good, but
> it means that if you do a ls -l of an encrypted directory, and the key
> is not present, we will have to do an xattr lookup for every file in
> that directory.  Even if the key is present, it will force the
> derivation of the per-file key of every file in that directory,
> regardless of whether the file is opened or not.
> 
> 	      	      	       	  	    - Ted

Hmm, I didn't know that was an intentional optimization.  It would be nice to
have a comment explaining it.  It's not done on directories and symlinks --- is
that because regular files require opening them to do anything with them,
whereas without opening a directory you can create/mkdir/mknod/rmdir/etc., or
without opening a symlink you can follow it?  I wonder how sys_truncate()
behaves; that doesn't require opening the file...

Eric

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

* Re: [PATCH] ext4: don't allow encrypted operations without keys
  2016-12-28  5:22   ` [PATCH] ext4: don't allow encrypted operations without keys Theodore Ts'o
@ 2017-01-05 19:26     ` Eric Biggers
  2017-01-05 20:15       ` Theodore Ts'o
  2017-02-04 21:44     ` Eric Biggers
  1 sibling, 1 reply; 14+ messages in thread
From: Eric Biggers @ 2017-01-05 19:26 UTC (permalink / raw)
  To: Theodore Ts'o
  Cc: Ext4 Developers List, Linux Filesystem Development List, jaegeuk,
	richard, ebiggers

Hi Ted,

On Wed, Dec 28, 2016 at 12:22:52AM -0500, Theodore Ts'o wrote:
> While we allow deletes without the key, the following should not be
> permitted:
> 
> # cd /vdc/encrypted-dir-without-key
> # ls -l
> total 4
> -rw-r--r-- 1 root root   0 Dec 27 22:35 6,LKNRJsp209FbXoSvJWzB
> -rw-r--r-- 1 root root 286 Dec 27 22:35 uRJ5vJh9gE7vcomYMqTAyD
> # mv uRJ5vJh9gE7vcomYMqTAyD  6,LKNRJsp209FbXoSvJWzB
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> ---
>  fs/ext4/namei.c | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
> index eadba919f26b..45a5ba558074 100644
> --- a/fs/ext4/namei.c
> +++ b/fs/ext4/namei.c
> @@ -3525,6 +3525,12 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
>  			EXT4_I(old_dentry->d_inode)->i_projid)))
>  		return -EXDEV;
>  
> +	if ((ext4_encrypted_inode(old_dir) &&
> +	     !fscrypt_has_encryption_key(old_dir)) ||
> +	    (ext4_encrypted_inode(new_dir) &&
> +	     !fscrypt_has_encryption_key(new_dir)))
> +		return -ENOKEY;
> +
>  	retval = dquot_initialize(old.dir);
>  	if (retval)
>  		return retval;
> @@ -3725,6 +3731,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
>  	int retval;
>  	struct timespec ctime;
>  
> +	if ((ext4_encrypted_inode(old_dir) &&
> +	     !fscrypt_has_encryption_key(old_dir)) ||
> +	    (ext4_encrypted_inode(new_dir) &&
> +	     !fscrypt_has_encryption_key(new_dir)))
> +		return -ENOKEY;
> +
>  	if ((ext4_encrypted_inode(old_dir) ||
>  	     ext4_encrypted_inode(new_dir)) &&
>  	    (old_dir != new_dir) &&

I'm fine with this, with the understanding that it relies on ext4_lookup()
calling fscrypt_get_encryption_info() (via fscrypt_has_permitted_context()) when
looking up the directory.  I also suggest moving the fscrypt_permitted_context()
check in ext4_rename() up to be next to the new check, so that the fscrypt hooks
are grouped together and are consistent with ext4_cross_rename().

I can also write/update an xfstest to test this.

Something I'm thinking about is making things easier for filesystems by having
functions like "fscrypt_rename_hook()" which would handle all these needed
checks.  It would be easy to do with out-of-line functions in fs/crypto/, but we
don't want to be making ->is_encrypted() calls through the fscrypt_operations
all the time, when an inlined call to ext4_encrypted_inode() (or f2fs or
ubifs_encrypted_inode()) is much faster.  I think it could be implemented as
efficiently as now if the hooks were defined in a header and called a macro like
"fs_encrypted_inode()" which filesystems would have to #define first.  It would
be a little ugly, but at least it would be less error-prone than having multiple
filesystems replicate these increasingly complex checks.

Eric

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

* Re: [PATCH] ext4: don't allow encrypted operations without keys
  2017-01-05 19:26     ` Eric Biggers
@ 2017-01-05 20:15       ` Theodore Ts'o
  0 siblings, 0 replies; 14+ messages in thread
From: Theodore Ts'o @ 2017-01-05 20:15 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Ext4 Developers List, Linux Filesystem Development List, jaegeuk,
	richard, ebiggers

On Thu, Jan 05, 2017 at 11:26:19AM -0800, Eric Biggers wrote:
> Something I'm thinking about is making things easier for filesystems by having
> functions like "fscrypt_rename_hook()" which would handle all these needed
> checks.  It would be easy to do with out-of-line functions in fs/crypto/, but we
> don't want to be making ->is_encrypted() calls through the fscrypt_operations
> all the time, when an inlined call to ext4_encrypted_inode() (or f2fs or
> ubifs_encrypted_inode()) is much faster.  I think it could be implemented as
> efficiently as now if the hooks were defined in a header and called a macro like
> "fs_encrypted_inode()" which filesystems would have to #define first.  It would
> be a little ugly, but at least it would be less error-prone than having multiple
> filesystems replicate these increasingly complex checks.

We could make things a lot simpler and a lot more efficient by adding
make flags at the VFS level in struct super and struct inode meaning
"file systems has fscrypt enabled", and "the inode is encrypted using
fscrypt".  That way, we wouldn't need to go through through
fscrypt_operations to do these tests.  We could just set the flags
appropriately when the struct inode or struct super is instantiated.

   	      	    	    		       	  - Ted

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

* Re: [PATCH] ext4: don't allow encrypted operations without keys
  2016-12-28  5:22   ` [PATCH] ext4: don't allow encrypted operations without keys Theodore Ts'o
  2017-01-05 19:26     ` Eric Biggers
@ 2017-02-04 21:44     ` Eric Biggers
  2017-02-06  1:13       ` Theodore Ts'o
  1 sibling, 1 reply; 14+ messages in thread
From: Eric Biggers @ 2017-02-04 21:44 UTC (permalink / raw)
  To: Theodore Ts'o
  Cc: Ext4 Developers List, Linux Filesystem Development List, jaegeuk,
	richard, ebiggers

On Wed, Dec 28, 2016 at 12:22:52AM -0500, Theodore Ts'o wrote:
> While we allow deletes without the key, the following should not be
> permitted:
> 
> # cd /vdc/encrypted-dir-without-key
> # ls -l
> total 4
> -rw-r--r-- 1 root root   0 Dec 27 22:35 6,LKNRJsp209FbXoSvJWzB
> -rw-r--r-- 1 root root 286 Dec 27 22:35 uRJ5vJh9gE7vcomYMqTAyD
> # mv uRJ5vJh9gE7vcomYMqTAyD  6,LKNRJsp209FbXoSvJWzB
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>

Hi Ted, this commit shows up twice in the ext4 tree, as 173b8439e1ba3 and
a7ede371cb821, but the second actually adds the check two *more* times to
ext4_cross_rename(), such that there are now a total of three checks in that
function, all the same.  Do you want to revert the second, unnecessary, commit?

Thanks,

Eric

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

* Re: [PATCH] ext4: don't allow encrypted operations without keys
  2017-02-04 21:44     ` Eric Biggers
@ 2017-02-06  1:13       ` Theodore Ts'o
  0 siblings, 0 replies; 14+ messages in thread
From: Theodore Ts'o @ 2017-02-06  1:13 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Ext4 Developers List, Linux Filesystem Development List, jaegeuk,
	richard, ebiggers

On Sat, Feb 04, 2017 at 01:44:28PM -0800, Eric Biggers wrote:
> 
> Hi Ted, this commit shows up twice in the ext4 tree, as 173b8439e1ba3 and
> a7ede371cb821, but the second actually adds the check two *more* times to
> ext4_cross_rename(), such that there are now a total of three checks in that
> function, all the same.  Do you want to revert the second, unnecessary, commit?

Yeah, it (and a few other fixes) was on the dev branch, and then when
they were cherry picked to the stable branch, and then I rebased the
dev branch on top of 4.10-rc3 to pick up a few other commits, I forgot
drop it.

Thanks for pointing it out; I've dropped it.

						- Ted

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

end of thread, other threads:[~2017-02-06  1:14 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-19 22:20 [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Eric Biggers
2016-12-19 22:20 ` [PATCH v2 2/5] fscrypt: fix renaming and linking special files Eric Biggers
2016-12-31  5:49   ` Theodore Ts'o
2016-12-19 22:20 ` [PATCH v2 3/5] ext4: consolidate fscrypt_has_permitted_context() checks Eric Biggers
2016-12-28  5:41   ` Theodore Ts'o
2017-01-05 19:03     ` Eric Biggers
2016-12-19 22:20 ` [PATCH v2 4/5] f2fs: " Eric Biggers
2016-12-19 22:20 ` [PATCH v2 5/5] ubifs: " Eric Biggers
2016-12-28  3:48 ` [PATCH v2 1/5] fscrypt: fix loophole in one-encryption-policy-per-tree enforcement Theodore Ts'o
2016-12-28  5:22   ` [PATCH] ext4: don't allow encrypted operations without keys Theodore Ts'o
2017-01-05 19:26     ` Eric Biggers
2017-01-05 20:15       ` Theodore Ts'o
2017-02-04 21:44     ` Eric Biggers
2017-02-06  1:13       ` 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).