Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
zlib.c
Go to the documentation of this file.
1 /*
2  * Cryptographic API.
3  *
4  * Zlib algorithm
5  *
6  * Copyright 2008 Sony Corporation
7  *
8  * Based on deflate.c, which is
9  * Copyright (c) 2003 James Morris <[email protected]>
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License as published by the Free
13  * Software Foundation; either version 2 of the License, or (at your option)
14  * any later version.
15  *
16  * FIXME: deflate transforms will require up to a total of about 436k of kernel
17  * memory on i386 (390k for compression, the rest for decompression), as the
18  * current zlib kernel code uses a worst case pre-allocation system by default.
19  * This needs to be fixed so that the amount of memory required is properly
20  * related to the winbits and memlevel parameters.
21  */
22 
23 #define pr_fmt(fmt) "%s: " fmt, __func__
24 
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/zlib.h>
28 #include <linux/vmalloc.h>
29 #include <linux/interrupt.h>
30 #include <linux/mm.h>
31 #include <linux/net.h>
32 
34 
35 #include <net/netlink.h>
36 
37 
38 struct zlib_ctx {
42 };
43 
44 
45 static void zlib_comp_exit(struct zlib_ctx *ctx)
46 {
47  struct z_stream_s *stream = &ctx->comp_stream;
48 
49  if (stream->workspace) {
50  zlib_deflateEnd(stream);
51  vfree(stream->workspace);
52  stream->workspace = NULL;
53  }
54 }
55 
56 static void zlib_decomp_exit(struct zlib_ctx *ctx)
57 {
58  struct z_stream_s *stream = &ctx->decomp_stream;
59 
60  if (stream->workspace) {
61  zlib_inflateEnd(stream);
62  vfree(stream->workspace);
63  stream->workspace = NULL;
64  }
65 }
66 
67 static int zlib_init(struct crypto_tfm *tfm)
68 {
69  return 0;
70 }
71 
72 static void zlib_exit(struct crypto_tfm *tfm)
73 {
74  struct zlib_ctx *ctx = crypto_tfm_ctx(tfm);
75 
76  zlib_comp_exit(ctx);
77  zlib_decomp_exit(ctx);
78 }
79 
80 
81 static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params,
82  unsigned int len)
83 {
84  struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
85  struct z_stream_s *stream = &ctx->comp_stream;
86  struct nlattr *tb[ZLIB_COMP_MAX + 1];
87  int window_bits, mem_level;
88  size_t workspacesize;
89  int ret;
90 
91  ret = nla_parse(tb, ZLIB_COMP_MAX, params, len, NULL);
92  if (ret)
93  return ret;
94 
95  zlib_comp_exit(ctx);
96 
97  window_bits = tb[ZLIB_COMP_WINDOWBITS]
98  ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS])
99  : MAX_WBITS;
100  mem_level = tb[ZLIB_COMP_MEMLEVEL]
101  ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL])
102  : DEF_MEM_LEVEL;
103 
104  workspacesize = zlib_deflate_workspacesize(window_bits, mem_level);
105  stream->workspace = vzalloc(workspacesize);
106  if (!stream->workspace)
107  return -ENOMEM;
108 
109  ret = zlib_deflateInit2(stream,
110  tb[ZLIB_COMP_LEVEL]
111  ? nla_get_u32(tb[ZLIB_COMP_LEVEL])
113  tb[ZLIB_COMP_METHOD]
114  ? nla_get_u32(tb[ZLIB_COMP_METHOD])
115  : Z_DEFLATED,
116  window_bits,
117  mem_level,
119  ? nla_get_u32(tb[ZLIB_COMP_STRATEGY])
121  if (ret != Z_OK) {
122  vfree(stream->workspace);
123  stream->workspace = NULL;
124  return -EINVAL;
125  }
126 
127  return 0;
128 }
129 
130 static int zlib_compress_init(struct crypto_pcomp *tfm)
131 {
132  int ret;
133  struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
134  struct z_stream_s *stream = &dctx->comp_stream;
135 
136  ret = zlib_deflateReset(stream);
137  if (ret != Z_OK)
138  return -EINVAL;
139 
140  return 0;
141 }
142 
143 static int zlib_compress_update(struct crypto_pcomp *tfm,
144  struct comp_request *req)
145 {
146  int ret;
147  struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
148  struct z_stream_s *stream = &dctx->comp_stream;
149 
150  pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
151  stream->next_in = req->next_in;
152  stream->avail_in = req->avail_in;
153  stream->next_out = req->next_out;
154  stream->avail_out = req->avail_out;
155 
156  ret = zlib_deflate(stream, Z_NO_FLUSH);
157  switch (ret) {
158  case Z_OK:
159  break;
160 
161  case Z_BUF_ERROR:
162  pr_debug("zlib_deflate could not make progress\n");
163  return -EAGAIN;
164 
165  default:
166  pr_debug("zlib_deflate failed %d\n", ret);
167  return -EINVAL;
168  }
169 
170  ret = req->avail_out - stream->avail_out;
171  pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
172  stream->avail_in, stream->avail_out,
173  req->avail_in - stream->avail_in, ret);
174  req->next_in = stream->next_in;
175  req->avail_in = stream->avail_in;
176  req->next_out = stream->next_out;
177  req->avail_out = stream->avail_out;
178  return ret;
179 }
180 
181 static int zlib_compress_final(struct crypto_pcomp *tfm,
182  struct comp_request *req)
183 {
184  int ret;
185  struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
186  struct z_stream_s *stream = &dctx->comp_stream;
187 
188  pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
189  stream->next_in = req->next_in;
190  stream->avail_in = req->avail_in;
191  stream->next_out = req->next_out;
192  stream->avail_out = req->avail_out;
193 
194  ret = zlib_deflate(stream, Z_FINISH);
195  if (ret != Z_STREAM_END) {
196  pr_debug("zlib_deflate failed %d\n", ret);
197  return -EINVAL;
198  }
199 
200  ret = req->avail_out - stream->avail_out;
201  pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
202  stream->avail_in, stream->avail_out,
203  req->avail_in - stream->avail_in, ret);
204  req->next_in = stream->next_in;
205  req->avail_in = stream->avail_in;
206  req->next_out = stream->next_out;
207  req->avail_out = stream->avail_out;
208  return ret;
209 }
210 
211 
212 static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params,
213  unsigned int len)
214 {
215  struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
216  struct z_stream_s *stream = &ctx->decomp_stream;
217  struct nlattr *tb[ZLIB_DECOMP_MAX + 1];
218  int ret = 0;
219 
220  ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL);
221  if (ret)
222  return ret;
223 
224  zlib_decomp_exit(ctx);
225 
227  ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS])
228  : DEF_WBITS;
229 
231  if (!stream->workspace)
232  return -ENOMEM;
233 
234  ret = zlib_inflateInit2(stream, ctx->decomp_windowBits);
235  if (ret != Z_OK) {
236  vfree(stream->workspace);
237  stream->workspace = NULL;
238  return -EINVAL;
239  }
240 
241  return 0;
242 }
243 
244 static int zlib_decompress_init(struct crypto_pcomp *tfm)
245 {
246  int ret;
247  struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
248  struct z_stream_s *stream = &dctx->decomp_stream;
249 
250  ret = zlib_inflateReset(stream);
251  if (ret != Z_OK)
252  return -EINVAL;
253 
254  return 0;
255 }
256 
257 static int zlib_decompress_update(struct crypto_pcomp *tfm,
258  struct comp_request *req)
259 {
260  int ret;
261  struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
262  struct z_stream_s *stream = &dctx->decomp_stream;
263 
264  pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
265  stream->next_in = req->next_in;
266  stream->avail_in = req->avail_in;
267  stream->next_out = req->next_out;
268  stream->avail_out = req->avail_out;
269 
270  ret = zlib_inflate(stream, Z_SYNC_FLUSH);
271  switch (ret) {
272  case Z_OK:
273  case Z_STREAM_END:
274  break;
275 
276  case Z_BUF_ERROR:
277  pr_debug("zlib_inflate could not make progress\n");
278  return -EAGAIN;
279 
280  default:
281  pr_debug("zlib_inflate failed %d\n", ret);
282  return -EINVAL;
283  }
284 
285  ret = req->avail_out - stream->avail_out;
286  pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
287  stream->avail_in, stream->avail_out,
288  req->avail_in - stream->avail_in, ret);
289  req->next_in = stream->next_in;
290  req->avail_in = stream->avail_in;
291  req->next_out = stream->next_out;
292  req->avail_out = stream->avail_out;
293  return ret;
294 }
295 
296 static int zlib_decompress_final(struct crypto_pcomp *tfm,
297  struct comp_request *req)
298 {
299  int ret;
300  struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm));
301  struct z_stream_s *stream = &dctx->decomp_stream;
302 
303  pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out);
304  stream->next_in = req->next_in;
305  stream->avail_in = req->avail_in;
306  stream->next_out = req->next_out;
307  stream->avail_out = req->avail_out;
308 
309  if (dctx->decomp_windowBits < 0) {
310  ret = zlib_inflate(stream, Z_SYNC_FLUSH);
311  /*
312  * Work around a bug in zlib, which sometimes wants to taste an
313  * extra byte when being used in the (undocumented) raw deflate
314  * mode. (From USAGI).
315  */
316  if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
317  const void *saved_next_in = stream->next_in;
318  u8 zerostuff = 0;
319 
320  stream->next_in = &zerostuff;
321  stream->avail_in = 1;
322  ret = zlib_inflate(stream, Z_FINISH);
323  stream->next_in = saved_next_in;
324  stream->avail_in = 0;
325  }
326  } else
327  ret = zlib_inflate(stream, Z_FINISH);
328  if (ret != Z_STREAM_END) {
329  pr_debug("zlib_inflate failed %d\n", ret);
330  return -EINVAL;
331  }
332 
333  ret = req->avail_out - stream->avail_out;
334  pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n",
335  stream->avail_in, stream->avail_out,
336  req->avail_in - stream->avail_in, ret);
337  req->next_in = stream->next_in;
338  req->avail_in = stream->avail_in;
339  req->next_out = stream->next_out;
340  req->avail_out = stream->avail_out;
341  return ret;
342 }
343 
344 
345 static struct pcomp_alg zlib_alg = {
346  .compress_setup = zlib_compress_setup,
347  .compress_init = zlib_compress_init,
348  .compress_update = zlib_compress_update,
349  .compress_final = zlib_compress_final,
350  .decompress_setup = zlib_decompress_setup,
351  .decompress_init = zlib_decompress_init,
352  .decompress_update = zlib_decompress_update,
353  .decompress_final = zlib_decompress_final,
354 
355  .base = {
356  .cra_name = "zlib",
357  .cra_flags = CRYPTO_ALG_TYPE_PCOMPRESS,
358  .cra_ctxsize = sizeof(struct zlib_ctx),
359  .cra_module = THIS_MODULE,
360  .cra_init = zlib_init,
361  .cra_exit = zlib_exit,
362  }
363 };
364 
365 static int __init zlib_mod_init(void)
366 {
367  return crypto_register_pcomp(&zlib_alg);
368 }
369 
370 static void __exit zlib_mod_fini(void)
371 {
372  crypto_unregister_pcomp(&zlib_alg);
373 }
374 
375 module_init(zlib_mod_init);
376 module_exit(zlib_mod_fini);
377 
378 MODULE_LICENSE("GPL");
379 MODULE_DESCRIPTION("Zlib Compression Algorithm");
380 MODULE_AUTHOR("Sony Corporation");