add patch move-check-under-lock-scope-to-close-a-race
[ext4-patch-queue.git] / stop-allocating-pages
blobec4595ca25afed6b62c4e21c68c1bf15f7854ceb
1 ext4 crypto: don't allocate a page when encrypting/decrypting file names
3 Change-Id: I415e4e4c56ab6c7779576fc287b5c4c8d7cdb12b
4 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
5 ---
6  fs/ext4/crypto_fname.c | 72 ++++++++++++++++++++----------------------------------------------------
7  fs/ext4/dir.c          |  3 +++
8  fs/ext4/ext4_crypto.h  |  1 -
9  fs/ext4/namei.c        |  4 ++++
10  fs/ext4/symlink.c      |  1 +
11  5 files changed, 28 insertions(+), 53 deletions(-)
13 diff --git a/fs/ext4/crypto_fname.c b/fs/ext4/crypto_fname.c
14 index ad5e328..23d7f1d 100644
15 --- a/fs/ext4/crypto_fname.c
16 +++ b/fs/ext4/crypto_fname.c
17 @@ -65,9 +65,9 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
18         struct crypto_ablkcipher *tfm = ctx->ctfm;
19         int res = 0;
20         char iv[EXT4_CRYPTO_BLOCK_SIZE];
21 -       struct scatterlist sg[1];
22 +       struct scatterlist src_sg, dst_sg;
23         int padding = 4 << (ctx->flags & EXT4_POLICY_FLAGS_PAD_MASK);
24 -       char *workbuf;
25 +       char *workbuf, buf[32], *alloc_buf = NULL;
27         if (iname->len <= 0 || iname->len > ctx->lim)
28                 return -EIO;
29 @@ -78,20 +78,27 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
30         ciphertext_len = (ciphertext_len > ctx->lim)
31                         ? ctx->lim : ciphertext_len;
33 +       if (ciphertext_len <= sizeof(buf)) {
34 +               workbuf = buf;
35 +       } else {
36 +               alloc_buf = kmalloc(ciphertext_len, GFP_NOFS);
37 +               if (!alloc_buf)
38 +                       return -ENOMEM;
39 +               workbuf = alloc_buf;
40 +       }
42         /* Allocate request */
43         req = ablkcipher_request_alloc(tfm, GFP_NOFS);
44         if (!req) {
45                 printk_ratelimited(
46                     KERN_ERR "%s: crypto_request_alloc() failed\n", __func__);
47 +               kfree(alloc_buf);
48                 return -ENOMEM;
49         }
50         ablkcipher_request_set_callback(req,
51                 CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
52                 ext4_dir_crypt_complete, &ecr);
54 -       /* Map the workpage */
55 -       workbuf = kmap(ctx->workpage);
57         /* Copy the input */
58         memcpy(workbuf, iname->name, iname->len);
59         if (iname->len < ciphertext_len)
60 @@ -101,21 +108,16 @@ static int ext4_fname_encrypt(struct ext4_fname_crypto_ctx *ctx,
61         memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE);
63         /* Create encryption request */
64 -       sg_init_table(sg, 1);
65 -       sg_set_page(sg, ctx->workpage, PAGE_SIZE, 0);
66 -       ablkcipher_request_set_crypt(req, sg, sg, ciphertext_len, iv);
67 +       sg_init_one(&src_sg, workbuf, ciphertext_len);
68 +       sg_init_one(&dst_sg, oname->name, ciphertext_len);
69 +       ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv);
70         res = crypto_ablkcipher_encrypt(req);
71         if (res == -EINPROGRESS || res == -EBUSY) {
72                 BUG_ON(req->base.data != &ecr);
73                 wait_for_completion(&ecr.completion);
74                 res = ecr.res;
75         }
76 -       if (res >= 0) {
77 -               /* Copy the result to output */
78 -               memcpy(oname->name, workbuf, ciphertext_len);
79 -               res = ciphertext_len;
80 -       }
81 -       kunmap(ctx->workpage);
82 +       kfree(alloc_buf);
83         ablkcipher_request_free(req);
84         if (res < 0) {
85                 printk_ratelimited(
86 @@ -139,11 +141,10 @@ static int ext4_fname_decrypt(struct ext4_fname_crypto_ctx *ctx,
87         struct ext4_str tmp_in[2], tmp_out[1];
88         struct ablkcipher_request *req = NULL;
89         DECLARE_EXT4_COMPLETION_RESULT(ecr);
90 -       struct scatterlist sg[1];
91 +       struct scatterlist src_sg, dst_sg;
92         struct crypto_ablkcipher *tfm = ctx->ctfm;
93         int res = 0;
94         char iv[EXT4_CRYPTO_BLOCK_SIZE];
95 -       char *workbuf;
97         if (iname->len <= 0 || iname->len > ctx->lim)
98                 return -EIO;
99 @@ -163,31 +164,19 @@ static int ext4_fname_decrypt(struct ext4_fname_crypto_ctx *ctx,
100                 CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
101                 ext4_dir_crypt_complete, &ecr);
103 -       /* Map the workpage */
104 -       workbuf = kmap(ctx->workpage);
106 -       /* Copy the input */
107 -       memcpy(workbuf, iname->name, iname->len);
109         /* Initialize IV */
110         memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE);
112         /* Create encryption request */
113 -       sg_init_table(sg, 1);
114 -       sg_set_page(sg, ctx->workpage, PAGE_SIZE, 0);
115 -       ablkcipher_request_set_crypt(req, sg, sg, iname->len, iv);
116 +       sg_init_one(&src_sg, iname->name, iname->len);
117 +       sg_init_one(&dst_sg, oname->name, oname->len);
118 +       ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
119         res = crypto_ablkcipher_decrypt(req);
120         if (res == -EINPROGRESS || res == -EBUSY) {
121                 BUG_ON(req->base.data != &ecr);
122                 wait_for_completion(&ecr.completion);
123                 res = ecr.res;
124         }
125 -       if (res >= 0) {
126 -               /* Copy the result to output */
127 -               memcpy(oname->name, workbuf, iname->len);
128 -               res = iname->len;
129 -       }
130 -       kunmap(ctx->workpage);
131         ablkcipher_request_free(req);
132         if (res < 0) {
133                 printk_ratelimited(
134 @@ -267,8 +256,6 @@ void ext4_free_fname_crypto_ctx(struct ext4_fname_crypto_ctx *ctx)
135                 crypto_free_ablkcipher(ctx->ctfm);
136         if (ctx->htfm && !IS_ERR(ctx->htfm))
137                 crypto_free_hash(ctx->htfm);
138 -       if (ctx->workpage && !IS_ERR(ctx->workpage))
139 -               __free_page(ctx->workpage);
140         kfree(ctx);
143 @@ -322,7 +309,6 @@ struct ext4_fname_crypto_ctx *ext4_alloc_fname_crypto_ctx(
144         ctx->ctfm_key_is_ready = 0;
145         ctx->ctfm = NULL;
146         ctx->htfm = NULL;
147 -       ctx->workpage = NULL;
148         return ctx;
151 @@ -390,24 +376,6 @@ struct ext4_fname_crypto_ctx *ext4_get_fname_crypto_ctx(
152                         ext4_put_fname_crypto_ctx(&ctx);
153                         return ERR_PTR(-ENOMEM);
154                 }
155 -               if (ctx->workpage == NULL)
156 -                       ctx->workpage = alloc_page(GFP_NOFS);
157 -               if (IS_ERR(ctx->workpage)) {
158 -                       res = PTR_ERR(ctx->workpage);
159 -                       printk(
160 -                           KERN_DEBUG "%s: error (%d) allocating work page\n",
161 -                           __func__, res);
162 -                       ctx->workpage = NULL;
163 -                       ext4_put_fname_crypto_ctx(&ctx);
164 -                       return ERR_PTR(res);
165 -               }
166 -               if (ctx->workpage == NULL) {
167 -                       printk(
168 -                           KERN_DEBUG "%s: could not allocate work page\n",
169 -                           __func__);
170 -                       ext4_put_fname_crypto_ctx(&ctx);
171 -                       return ERR_PTR(-ENOMEM);
172 -               }
173                 ctx->lim = max_ciphertext_len;
174                 crypto_ablkcipher_clear_flags(ctx->ctfm, ~0);
175                 crypto_tfm_set_flags(crypto_ablkcipher_tfm(ctx->ctfm),
176 diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
177 index 5665d82..d799d5d 100644
178 --- a/fs/ext4/dir.c
179 +++ b/fs/ext4/dir.c
180 @@ -247,9 +247,12 @@ static int ext4_readdir(struct file *file, struct dir_context *ctx)
181                                             get_dtype(sb, de->file_type)))
182                                                 goto done;
183                                 } else {
184 +                                       int save_len = fname_crypto_str.len;
186                                         /* Directory is encrypted */
187                                         err = ext4_fname_disk_to_usr(enc_ctx,
188                                                 NULL, de, &fname_crypto_str);
189 +                                       fname_crypto_str.len = save_len;
190                                         if (err < 0)
191                                                 goto errout;
192                                         if (!dir_emit(ctx,
193 diff --git a/fs/ext4/ext4_crypto.h b/fs/ext4/ext4_crypto.h
194 index d75159c..e9e4365 100644
195 --- a/fs/ext4/ext4_crypto.h
196 +++ b/fs/ext4/ext4_crypto.h
197 @@ -126,7 +126,6 @@ struct ext4_fname_crypto_ctx {
198         char tmp_buf[EXT4_CRYPTO_BLOCK_SIZE];
199         struct crypto_ablkcipher *ctfm;
200         struct crypto_hash *htfm;
201 -       struct page *workpage;
202         struct ext4_encryption_key key;
203         unsigned flags : 8;
204         unsigned has_valid_key : 1;
205 diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
206 index 752d4af..bf66e56 100644
207 --- a/fs/ext4/namei.c
208 +++ b/fs/ext4/namei.c
209 @@ -998,6 +998,8 @@ static int htree_dirblock_to_tree(struct file *dir_file,
210                                    hinfo->hash, hinfo->minor_hash, de,
211                                    &tmp_str);
212                 } else {
213 +                       int save_len = fname_crypto_str.len;
215                         /* Directory is encrypted */
216                         err = ext4_fname_disk_to_usr(ctx, hinfo, de,
217                                                      &fname_crypto_str);
218 @@ -1008,6 +1010,7 @@ static int htree_dirblock_to_tree(struct file *dir_file,
219                         err = ext4_htree_store_dirent(dir_file,
220                                    hinfo->hash, hinfo->minor_hash, de,
221                                         &fname_crypto_str);
222 +                       fname_crypto_str.len = save_len;
223                 }
224                 if (err != 0) {
225                         count = err;
226 @@ -3132,6 +3135,7 @@ static int ext4_symlink(struct inode *dir,
227                 istr.name = (const unsigned char *) symname;
228                 istr.len = len;
229                 ostr.name = sd->encrypted_path;
230 +               ostr.len = disk_link.len;
231                 err = ext4_fname_usr_to_disk(ctx, &istr, &ostr);
232                 ext4_put_fname_crypto_ctx(&ctx);
233                 if (err < 0)
234 diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
235 index ce2ed28..3428c51 100644
236 --- a/fs/ext4/symlink.c
237 +++ b/fs/ext4/symlink.c
238 @@ -74,6 +74,7 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
239                 goto errout;
240         }
241         pstr.name = paddr;
242 +       pstr.len = plen;
243         res = _ext4_fname_disk_to_usr(ctx, NULL, &cstr, &pstr);
244         if (res < 0)
245                 goto errout;