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