add patch handle-transient-enospc-properly-for-DAX
[ext4-patch-queue.git] / crypto-add-ciphertext_access-mount-option
blobc60a87d5a3e48dcaaddf382ad9eeac4809d71848
1 ext4 crypto: add ciphertext_access mount option
3 Add a mount option which allows root to be able to access the
4 ciphertext of a file by reading it using O_DIRECT.
6 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
7 ---
8  fs/ext4/ext4.h     |  1 +
9  fs/ext4/file.c     |  5 ++++-
10  fs/ext4/indirect.c |  5 ++---
11  fs/ext4/inode.c    | 17 ++++++++++-------
12  fs/ext4/super.c    |  5 +++++
13  5 files changed, 22 insertions(+), 11 deletions(-)
15 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
16 index 1e20fa9..44278aa7 100644
17 --- a/fs/ext4/ext4.h
18 +++ b/fs/ext4/ext4.h
19 @@ -1052,6 +1052,7 @@ struct ext4_inode_info {
20  #define EXT4_MOUNT_DIOREAD_NOLOCK      0x400000 /* Enable support for dio read nolocking */
21  #define EXT4_MOUNT_JOURNAL_CHECKSUM    0x800000 /* Journal checksums */
22  #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT        0x1000000 /* Journal Async Commit */
23 +#define EXT4_MOUNT_CIPHERTEXT_ACCESS   0x2000000 /* Direct I/O to ciphertext */
24  #define EXT4_MOUNT_DELALLOC            0x8000000 /* Delalloc support */
25  #define EXT4_MOUNT_DATA_ERR_ABORT      0x10000000 /* Abort on file data write */
26  #define EXT4_MOUNT_BLOCK_VALIDITY      0x20000000 /* Block validity checking */
27 diff --git a/fs/ext4/file.c b/fs/ext4/file.c
28 index 749b222..60683ab 100644
29 --- a/fs/ext4/file.c
30 +++ b/fs/ext4/file.c
31 @@ -388,7 +388,10 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
32                 ret = ext4_get_encryption_info(inode);
33                 if (ret)
34                         return -EACCES;
35 -               if (ext4_encryption_info(inode) == NULL)
36 +               if ((ext4_encryption_info(inode) == NULL) &&
37 +                   !(test_opt(inode->i_sb, CIPHERTEXT_ACCESS) &&
38 +                     ((filp->f_flags & O_ACCMODE) == O_RDONLY) &&
39 +                     capable(CAP_SYS_ADMIN)))
40                         return -ENOKEY;
41         }
42         /*
43 diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
44 index 355ef9c..bd9d89e 100644
45 --- a/fs/ext4/indirect.c
46 +++ b/fs/ext4/indirect.c
47 @@ -655,11 +655,10 @@ ssize_t ext4_ind_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
48         int orphan = 0;
49         size_t count = iov_iter_count(iter);
50         int retries = 0;
51 +       loff_t final_size = offset + count;
53         if (iov_iter_rw(iter) == WRITE) {
54 -               loff_t final_size = offset + count;
56 -               if (final_size > inode->i_size) {
57 +               if (final_size > i_size_read(inode)) {
58                         /* Credits for sb + inode write */
59                         handle = ext4_journal_start(inode, EXT4_HT_INODE, 2);
60                         if (IS_ERR(handle)) {
61 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
62 index ff2f3cd..16f6537 100644
63 --- a/fs/ext4/inode.c
64 +++ b/fs/ext4/inode.c
65 @@ -3279,9 +3279,6 @@ static ssize_t ext4_ext_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
66                 get_block_func = ext4_get_block_write;
67                 dio_flags = DIO_LOCKING;
68         }
69 -#ifdef CONFIG_EXT4_FS_ENCRYPTION
70 -       BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode));
71 -#endif
72         if (IS_DAX(inode))
73                 ret = dax_do_io(iocb, inode, iter, offset, get_block_func,
74                                 ext4_end_io_dio, dio_flags);
75 @@ -3344,10 +3341,16 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
76         size_t count = iov_iter_count(iter);
77         ssize_t ret;
79 -#ifdef CONFIG_EXT4_FS_ENCRYPTION
80 -       if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode))
81 -               return 0;
82 -#endif
83 +       if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) {
84 +               if (iov_iter_rw(iter) == WRITE)
85 +                       return 0;
86 +               if (test_opt(inode->i_sb, CIPHERTEXT_ACCESS) &&
87 +                   capable(CAP_SYS_ADMIN)) {
88 +                       if (iov_iter_rw(iter) == WRITE)
89 +                               return -EPERM;
90 +               } else
91 +                       return 0;
92 +       }
94         /*
95          * If we are doing data journalling we don't support O_DIRECT
96 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
97 index 486e869..de875b4 100644
98 --- a/fs/ext4/super.c
99 +++ b/fs/ext4/super.c
100 @@ -1182,6 +1182,7 @@ enum {
101         Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit,
102         Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
103         Opt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption,
104 +       Opt_ciphertext_access, Opt_nociphertext_access,
105         Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
106         Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
107         Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
108 @@ -1273,6 +1274,8 @@ static const match_table_t tokens = {
109         {Opt_noinit_itable, "noinit_itable"},
110         {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
111         {Opt_test_dummy_encryption, "test_dummy_encryption"},
112 +       {Opt_ciphertext_access, "ciphertext_access"},
113 +       {Opt_nociphertext_access, "nociphertext_access"},
114         {Opt_removed, "check=none"},    /* mount option from ext2/3 */
115         {Opt_removed, "nocheck"},       /* mount option from ext2/3 */
116         {Opt_removed, "reservation"},   /* mount option from ext2/3 */
117 @@ -1475,6 +1478,8 @@ static const struct mount_opts {
118         {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
119         {Opt_max_dir_size_kb, 0, MOPT_GTE0},
120         {Opt_test_dummy_encryption, 0, MOPT_GTE0},
121 +       {Opt_ciphertext_access, EXT4_MOUNT_CIPHERTEXT_ACCESS, MOPT_SET},
122 +       {Opt_nociphertext_access, EXT4_MOUNT_CIPHERTEXT_ACCESS, MOPT_CLEAR},
123         {Opt_err, 0, 0}
124  };