diff options
author | Theodore Ts'o <tytso@mit.edu> | 2015-04-12 00:55:08 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2015-04-12 00:55:08 -0400 |
commit | d9cdc903318171571f1cd1e5737fd0cab94186be (patch) | |
tree | 5baa3a2fbd4a544fcf7ac7e5546b4b6a2ea25587 /fs/ext4/namei.c | |
parent | 88bd6ccdcdd638faa11e9746affc21d5f2fe2acf (diff) |
ext4 crypto: enforce context consistency
Enforce the following inheritance policy:
1) An unencrypted directory may contain encrypted or unencrypted files
or directories.
2) All files or directories in a directory must be protected using the
same key as their containing directory.
As a result, assuming the following setup:
mke2fs -t ext4 -Fq -O encrypt /dev/vdc
mount -t ext4 /dev/vdc /vdc
mkdir /vdc/a /vdc/b /vdc/c
echo foo | e4crypt add_key /vdc/a
echo bar | e4crypt add_key /vdc/b
for i in a b c ; do cp /etc/motd /vdc/$i/motd-$i ; done
Then we will see the following results:
cd /vdc
mv a b # will fail; /vdc/a and /vdc/b have different keys
mv b/motd-b a # will fail, see above
ln a/motd-a b # will fail, see above
mv c a # will fail; all inodes in an encrypted directory
# must be encrypted
ln c/motd-c b # will fail, see above
mv a/motd-a c # will succeed
mv c/motd-a a # will succeed
Signed-off-by: Michael Halcrow <mhalcrow@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/namei.c')
-rw-r--r-- | fs/ext4/namei.c | 24 |
1 files changed, 23 insertions, 1 deletions
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 0dbd2d2937f7..acd79198b800 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -1416,6 +1416,18 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi | |||
1416 | ino); | 1416 | ino); |
1417 | return ERR_PTR(-EIO); | 1417 | return ERR_PTR(-EIO); |
1418 | } | 1418 | } |
1419 | if (!IS_ERR(inode) && ext4_encrypted_inode(dir) && | ||
1420 | (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | ||
1421 | S_ISLNK(inode->i_mode)) && | ||
1422 | !ext4_is_child_context_consistent_with_parent(dir, | ||
1423 | inode)) { | ||
1424 | iput(inode); | ||
1425 | ext4_warning(inode->i_sb, | ||
1426 | "Inconsistent encryption contexts: %lu/%lu\n", | ||
1427 | (unsigned long) dir->i_ino, | ||
1428 | (unsigned long) inode->i_ino); | ||
1429 | return ERR_PTR(-EPERM); | ||
1430 | } | ||
1419 | } | 1431 | } |
1420 | return d_splice_alias(inode, dentry); | 1432 | return d_splice_alias(inode, dentry); |
1421 | } | 1433 | } |
@@ -2944,7 +2956,9 @@ static int ext4_link(struct dentry *old_dentry, | |||
2944 | 2956 | ||
2945 | if (inode->i_nlink >= EXT4_LINK_MAX) | 2957 | if (inode->i_nlink >= EXT4_LINK_MAX) |
2946 | return -EMLINK; | 2958 | return -EMLINK; |
2947 | 2959 | if (ext4_encrypted_inode(dir) && | |
2960 | !ext4_is_child_context_consistent_with_parent(dir, inode)) | ||
2961 | return -EPERM; | ||
2948 | dquot_initialize(dir); | 2962 | dquot_initialize(dir); |
2949 | 2963 | ||
2950 | retry: | 2964 | retry: |
@@ -3245,6 +3259,14 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
3245 | if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino) | 3259 | if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino) |
3246 | goto end_rename; | 3260 | goto end_rename; |
3247 | 3261 | ||
3262 | if ((old.dir != new.dir) && | ||
3263 | ext4_encrypted_inode(new.dir) && | ||
3264 | !ext4_is_child_context_consistent_with_parent(new.dir, | ||
3265 | old.inode)) { | ||
3266 | retval = -EPERM; | ||
3267 | goto end_rename; | ||
3268 | } | ||
3269 | |||
3248 | new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, | 3270 | new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, |
3249 | &new.de, &new.inlined); | 3271 | &new.de, &new.inlined); |
3250 | if (IS_ERR(new.bh)) { | 3272 | if (IS_ERR(new.bh)) { |