Sync ext4 encryption as of commit dffd334e4d7134
[ext4-patch-queue.git] / add-symlink-encryption
blobdedf4a4eeb4939a5e5fea8a9c6f1068b388a0442
1 ext4 crypto: Add symlink encryption
3 Change-Id: Ic92ebe4c615721650ccaf16b3175c2f4e931af2d
4 Signed-off-by: Uday Savagaonkar <savagaon@google.com>
5 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
6 ---
7  fs/ext4/ext4.h        |  1 +
8  fs/ext4/ext4_crypto.h | 20 ++++++++++++++++++++
9  fs/ext4/inode.c       |  5 +++--
10  fs/ext4/namei.c       | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
11  fs/ext4/symlink.c     | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
12  5 files changed, 179 insertions(+), 19 deletions(-)
14 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
15 index 98a5617..c79db59 100644
16 --- a/fs/ext4/ext4.h
17 +++ b/fs/ext4/ext4.h
18 @@ -2221,6 +2221,7 @@ extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
19  extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
21  /* inode.c */
22 +int ext4_inode_is_fast_symlink(struct inode *inode);
23  struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int);
24  struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int);
25  int ext4_get_block_write(struct inode *inode, sector_t iblock,
26 diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h
27 index f7d46e8..c2ba35a 100644
28 --- a/fs/ext4/ext4_crypto.h
29 +++ b/fs/ext4/ext4_crypto.h
30 @@ -124,4 +124,24 @@ struct ext4_fname_crypto_ctx {
31         unsigned ctfm_key_is_ready : 1;
32  };
34 +/**
35 + * For encrypted symlinks, the ciphertext length is stored at the beginning
36 + * of the string in little-endian format.
37 + */
38 +struct ext4_encrypted_symlink_data {
39 +       __le16 len;
40 +       char encrypted_path[1];
41 +} __attribute__((__packed__));
43 +/**
44 + * This function is used to calculate the disk space required to
45 + * store a filename of length l in encrypted symlink format.
46 + */
47 +static inline u32 encrypted_symlink_data_len(u32 l)
49 +       if (l < EXT4_CRYPTO_BLOCK_SIZE)
50 +               l = EXT4_CRYPTO_BLOCK_SIZE;
51 +       return (l + sizeof(struct ext4_encrypted_symlink_data) - 1);
54  #endif /* _EXT4_CRYPTO_H */
55 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
56 index 5b6b7b6..c87bb7a 100644
57 --- a/fs/ext4/inode.c
58 +++ b/fs/ext4/inode.c
59 @@ -143,7 +143,7 @@ static int ext4_meta_trans_blocks(struct inode *inode, int lblocks,
60  /*
61   * Test whether an inode is a fast symlink.
62   */
63 -static int ext4_inode_is_fast_symlink(struct inode *inode)
64 +int ext4_inode_is_fast_symlink(struct inode *inode)
65  {
66          int ea_blocks = EXT4_I(inode)->i_file_acl ?
67                 EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0;
68 @@ -4177,7 +4177,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
69                 inode->i_op = &ext4_dir_inode_operations;
70                 inode->i_fop = &ext4_dir_operations;
71         } else if (S_ISLNK(inode->i_mode)) {
72 -               if (ext4_inode_is_fast_symlink(inode)) {
73 +               if (ext4_inode_is_fast_symlink(inode) &&
74 +                   !ext4_encrypted_inode(inode)) {
75                         inode->i_op = &ext4_fast_symlink_inode_operations;
76                         nd_terminate_link(ei->i_data, inode->i_size,
77                                 sizeof(ei->i_data) - 1);
78 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
79 index e8f82b2..ba4f4fd 100644
80 --- a/fs/ext4/namei.c
81 +++ b/fs/ext4/namei.c
82 @@ -3183,16 +3183,24 @@ static int ext4_symlink(struct inode *dir,
83  {
84         handle_t *handle;
85         struct inode *inode;
86 -       int l, err, retries = 0;
87 +       int err, len = strlen(symname);
88         int credits;
89 +       bool encryption_required;
90 +       struct ext4_str disk_link;
91 +       struct ext4_encrypted_symlink_data *sd = NULL;
93 -       l = strlen(symname)+1;
94 -       if (l > dir->i_sb->s_blocksize)
95 +       disk_link.len = len + 1;
96 +       disk_link.name = (char *) symname;
98 +       encryption_required = ext4_encrypted_inode(dir);
99 +       if (encryption_required)
100 +               disk_link.len = encrypted_symlink_data_len(len) + 1;
101 +       if (disk_link.len > dir->i_sb->s_blocksize)
102                 return -ENAMETOOLONG;
104         dquot_initialize(dir);
106 -       if (l > EXT4_N_BLOCKS * 4) {
107 +       if ((disk_link.len > EXT4_N_BLOCKS * 4) || encryption_required) {
108                 /*
109                  * For non-fast symlinks, we just allocate inode and put it on
110                  * orphan list in the first transaction => we need bitmap,
111 @@ -3211,16 +3219,49 @@ static int ext4_symlink(struct inode *dir,
112                 credits = EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
113                           EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3;
114         }
115 -retry:
117         inode = ext4_new_inode_start_handle(dir, S_IFLNK|S_IRWXUGO,
118                                             &dentry->d_name, 0, NULL,
119                                             EXT4_HT_DIR, credits);
120         handle = ext4_journal_current_handle();
121 -       err = PTR_ERR(inode);
122 -       if (IS_ERR(inode))
123 -               goto out_stop;
124 +       if (IS_ERR(inode)) {
125 +               ext4_journal_stop(handle);
126 +               return PTR_ERR(inode);
127 +       }
129 +       if (encryption_required) {
130 +               struct ext4_fname_crypto_ctx *ctx = NULL;
131 +               struct qstr istr;
132 +               struct ext4_str ostr;
134 +               sd = kmalloc(disk_link.len, GFP_NOFS);
135 +               if (!sd) {
136 +                       err = -ENOMEM;
137 +                       goto err_drop_inode;
138 +               }
139 +               sd->encrypted_path[disk_link.len - 1] = '\0';
140 +               err = ext4_inherit_context(dir, inode);
141 +               if (err)
142 +                       goto err_drop_inode;
143 +               ctx = ext4_get_fname_crypto_ctx(inode,
144 +                                               inode->i_sb->s_blocksize);
145 +               if (IS_ERR_OR_NULL(ctx)) {
146 +                       /* We just set the policy, so ctx should not be NULL */
147 +                       err = (ctx == NULL) ? -EIO : PTR_ERR(ctx);
148 +                       goto err_drop_inode;
149 +               }
150 +               istr.name = (const unsigned char *) symname;
151 +               istr.len = len;
152 +               ostr.name = sd->encrypted_path;
153 +               err = ext4_fname_usr_to_disk(ctx, &istr, &ostr);
154 +               ext4_put_fname_crypto_ctx(&ctx);
155 +               if (err < 0)
156 +                       goto err_drop_inode;
157 +               sd->len = cpu_to_le32(ostr.len);
158 +               disk_link.name = (char *) sd;
159 +       }
161 -       if (l > EXT4_N_BLOCKS * 4) {
162 +       if ((disk_link.len > EXT4_N_BLOCKS * 4) /* || encryption_required */) {
163                 inode->i_op = &ext4_symlink_inode_operations;
164                 ext4_set_aops(inode);
165                 /*
166 @@ -3238,7 +3279,7 @@ retry:
167                 ext4_journal_stop(handle);
168                 if (err)
169                         goto err_drop_inode;
170 -               err = __page_symlink(inode, symname, l, 1);
171 +               err = __page_symlink(inode, disk_link.name, disk_link.len, 1);
172                 if (err)
173                         goto err_drop_inode;
174                 /*
175 @@ -3262,22 +3303,24 @@ retry:
176         } else {
177                 /* clear the extent format for fast symlink */
178                 ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
179 -               inode->i_op = &ext4_fast_symlink_inode_operations;
180 -               memcpy((char *)&EXT4_I(inode)->i_data, symname, l);
181 -               inode->i_size = l-1;
182 +               inode->i_op = encryption_required ?
183 +                       &ext4_symlink_inode_operations :
184 +                       &ext4_fast_symlink_inode_operations;
185 +               memcpy((char *)&EXT4_I(inode)->i_data, disk_link.name,
186 +                      disk_link.len);
187 +               inode->i_size = disk_link.len - 1;
188         }
189         EXT4_I(inode)->i_disksize = inode->i_size;
190         err = ext4_add_nondir(handle, dentry, inode);
191         if (!err && IS_DIRSYNC(dir))
192                 ext4_handle_sync(handle);
194 -out_stop:
195         if (handle)
196                 ext4_journal_stop(handle);
197 -       if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
198 -               goto retry;
199 +       kfree(sd);
200         return err;
201  err_drop_inode:
202 +       kfree(sd);
203         unlock_new_inode(inode);
204         iput(inode);
205         return err;
206 diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
207 index ff37119..6f71c2c 100644
208 --- a/fs/ext4/symlink.c
209 +++ b/fs/ext4/symlink.c
210 @@ -22,9 +22,99 @@
211  #include <linux/namei.h>
212  #include "ext4.h"
213  #include "xattr.h"
214 +#include "ext4_crypto.h"
216 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
217  static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
219 +       struct page *cpage = NULL;
220 +       char *caddr, *paddr = NULL;
221 +       struct ext4_str cstr, pstr;
222 +       struct inode *inode = dentry->d_inode;
223 +       struct ext4_fname_crypto_ctx *ctx = NULL;
224 +       struct ext4_encrypted_symlink_data *sd;
225 +       loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
226 +       int res;
227 +       u32 plen, max_size = inode->i_sb->s_blocksize;
229 +       if (!ext4_encrypted_inode(inode))
230 +               return page_follow_link_light(dentry, nd);
232 +       ctx = ext4_get_fname_crypto_ctx(inode, inode->i_sb->s_blocksize);
233 +       if (IS_ERR(ctx))
234 +               return ctx;
236 +       if (ext4_inode_is_fast_symlink(inode)) {
237 +               caddr = (char *) EXT4_I(dentry->d_inode)->i_data;
238 +               max_size = sizeof(EXT4_I(dentry->d_inode)->i_data);
239 +       } else {
240 +               cpage = read_mapping_page(inode->i_mapping, 0, NULL);
241 +               if (IS_ERR(cpage)) {
242 +                       ext4_put_fname_crypto_ctx(&ctx);
243 +                       return cpage;
244 +               }
245 +               caddr = kmap(cpage);
246 +               caddr[size] = 0;
247 +       }
249 +       /* Symlink is encrypted */
250 +       sd = (struct ext4_encrypted_symlink_data *)caddr;
251 +       cstr.name = sd->encrypted_path;
252 +       cstr.len  = le32_to_cpu(sd->len);
253 +       if ((cstr.len +
254 +            sizeof(struct ext4_encrypted_symlink_data) - 1) >
255 +           max_size) {
256 +               /* Symlink data on the disk is corrupted */
257 +               res = -EIO;
258 +               goto errout;
259 +       }
260 +       plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ?
261 +               EXT4_FNAME_CRYPTO_DIGEST_SIZE*2 : cstr.len;
262 +       paddr = kmalloc(plen + 1, GFP_NOFS);
263 +       if (!paddr) {
264 +               res = -ENOMEM;
265 +               goto errout;
266 +       }
267 +       pstr.name = paddr;
268 +       res = _ext4_fname_disk_to_usr(ctx, &cstr, &pstr);
269 +       if (res < 0)
270 +               goto errout;
271 +       /* Null-terminate the name */
272 +       if (res <= plen)
273 +               paddr[res] = '\0';
274 +       nd_set_link(nd, paddr);
275 +       ext4_put_fname_crypto_ctx(&ctx);
276 +       if (cpage) {
277 +               kunmap(cpage);
278 +               page_cache_release(cpage);
279 +       }
280 +       return NULL;
281 +errout:
282 +       ext4_put_fname_crypto_ctx(&ctx);
283 +       if (cpage) {
284 +               kunmap(cpage);
285 +               page_cache_release(cpage);
286 +       }
287 +       kfree(paddr);
288 +       return ERR_PTR(res);
291 +static void ext4_put_link(struct dentry *dentry, struct nameidata *nd,
292 +                         void *cookie)
294 +       struct page *page = cookie;
296 +       if (!page) {
297 +               kfree(nd_get_link(nd));
298 +       } else {
299 +               kunmap(page);
300 +               page_cache_release(page);
301 +       }
303 +#endif
305 +static void *ext4_follow_fast_link(struct dentry *dentry, struct nameidata *nd)
307         struct ext4_inode_info *ei = EXT4_I(dentry->d_inode);
308         nd_set_link(nd, (char *) ei->i_data);
309         return NULL;
310 @@ -32,8 +122,13 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
312  const struct inode_operations ext4_symlink_inode_operations = {
313         .readlink       = generic_readlink,
314 +#ifdef CONFIG_EXT4_FS_ENCRYPTION
315 +       .follow_link    = ext4_follow_link,
316 +       .put_link       = ext4_put_link,
317 +#else
318         .follow_link    = page_follow_link_light,
319         .put_link       = page_put_link,
320 +#endif
321         .setattr        = ext4_setattr,
322         .setxattr       = generic_setxattr,
323         .getxattr       = generic_getxattr,
324 @@ -43,7 +138,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
326  const struct inode_operations ext4_fast_symlink_inode_operations = {
327         .readlink       = generic_readlink,
328 -       .follow_link    = ext4_follow_link,
329 +       .follow_link    = ext4_follow_fast_link,
330         .setattr        = ext4_setattr,
331         .setxattr       = generic_setxattr,
332         .getxattr       = generic_getxattr,