at v2.6.32-rc7 378 lines 9.7 kB view raw
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 <jmorris@intercode.com.au> 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#include <linux/slab.h> 33 34#include <crypto/internal/compress.h> 35 36#include <net/netlink.h> 37 38 39struct zlib_ctx { 40 struct z_stream_s comp_stream; 41 struct z_stream_s decomp_stream; 42 int decomp_windowBits; 43}; 44 45 46static void zlib_comp_exit(struct zlib_ctx *ctx) 47{ 48 struct z_stream_s *stream = &ctx->comp_stream; 49 50 if (stream->workspace) { 51 zlib_deflateEnd(stream); 52 vfree(stream->workspace); 53 stream->workspace = NULL; 54 } 55} 56 57static void zlib_decomp_exit(struct zlib_ctx *ctx) 58{ 59 struct z_stream_s *stream = &ctx->decomp_stream; 60 61 if (stream->workspace) { 62 zlib_inflateEnd(stream); 63 kfree(stream->workspace); 64 stream->workspace = NULL; 65 } 66} 67 68static int zlib_init(struct crypto_tfm *tfm) 69{ 70 return 0; 71} 72 73static void zlib_exit(struct crypto_tfm *tfm) 74{ 75 struct zlib_ctx *ctx = crypto_tfm_ctx(tfm); 76 77 zlib_comp_exit(ctx); 78 zlib_decomp_exit(ctx); 79} 80 81 82static int zlib_compress_setup(struct crypto_pcomp *tfm, void *params, 83 unsigned int len) 84{ 85 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 86 struct z_stream_s *stream = &ctx->comp_stream; 87 struct nlattr *tb[ZLIB_COMP_MAX + 1]; 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 workspacesize = zlib_deflate_workspacesize(); 98 stream->workspace = vmalloc(workspacesize); 99 if (!stream->workspace) 100 return -ENOMEM; 101 102 memset(stream->workspace, 0, workspacesize); 103 ret = zlib_deflateInit2(stream, 104 tb[ZLIB_COMP_LEVEL] 105 ? nla_get_u32(tb[ZLIB_COMP_LEVEL]) 106 : Z_DEFAULT_COMPRESSION, 107 tb[ZLIB_COMP_METHOD] 108 ? nla_get_u32(tb[ZLIB_COMP_METHOD]) 109 : Z_DEFLATED, 110 tb[ZLIB_COMP_WINDOWBITS] 111 ? nla_get_u32(tb[ZLIB_COMP_WINDOWBITS]) 112 : MAX_WBITS, 113 tb[ZLIB_COMP_MEMLEVEL] 114 ? nla_get_u32(tb[ZLIB_COMP_MEMLEVEL]) 115 : DEF_MEM_LEVEL, 116 tb[ZLIB_COMP_STRATEGY] 117 ? nla_get_u32(tb[ZLIB_COMP_STRATEGY]) 118 : Z_DEFAULT_STRATEGY); 119 if (ret != Z_OK) { 120 vfree(stream->workspace); 121 stream->workspace = NULL; 122 return -EINVAL; 123 } 124 125 return 0; 126} 127 128static int zlib_compress_init(struct crypto_pcomp *tfm) 129{ 130 int ret; 131 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 132 struct z_stream_s *stream = &dctx->comp_stream; 133 134 ret = zlib_deflateReset(stream); 135 if (ret != Z_OK) 136 return -EINVAL; 137 138 return 0; 139} 140 141static int zlib_compress_update(struct crypto_pcomp *tfm, 142 struct comp_request *req) 143{ 144 int ret; 145 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 146 struct z_stream_s *stream = &dctx->comp_stream; 147 148 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out); 149 stream->next_in = req->next_in; 150 stream->avail_in = req->avail_in; 151 stream->next_out = req->next_out; 152 stream->avail_out = req->avail_out; 153 154 ret = zlib_deflate(stream, Z_NO_FLUSH); 155 switch (ret) { 156 case Z_OK: 157 break; 158 159 case Z_BUF_ERROR: 160 pr_debug("zlib_deflate could not make progress\n"); 161 return -EAGAIN; 162 163 default: 164 pr_debug("zlib_deflate failed %d\n", ret); 165 return -EINVAL; 166 } 167 168 ret = req->avail_out - stream->avail_out; 169 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n", 170 stream->avail_in, stream->avail_out, 171 req->avail_in - stream->avail_in, ret); 172 req->next_in = stream->next_in; 173 req->avail_in = stream->avail_in; 174 req->next_out = stream->next_out; 175 req->avail_out = stream->avail_out; 176 return ret; 177} 178 179static int zlib_compress_final(struct crypto_pcomp *tfm, 180 struct comp_request *req) 181{ 182 int ret; 183 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 184 struct z_stream_s *stream = &dctx->comp_stream; 185 186 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out); 187 stream->next_in = req->next_in; 188 stream->avail_in = req->avail_in; 189 stream->next_out = req->next_out; 190 stream->avail_out = req->avail_out; 191 192 ret = zlib_deflate(stream, Z_FINISH); 193 if (ret != Z_STREAM_END) { 194 pr_debug("zlib_deflate failed %d\n", ret); 195 return -EINVAL; 196 } 197 198 ret = req->avail_out - stream->avail_out; 199 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n", 200 stream->avail_in, stream->avail_out, 201 req->avail_in - stream->avail_in, ret); 202 req->next_in = stream->next_in; 203 req->avail_in = stream->avail_in; 204 req->next_out = stream->next_out; 205 req->avail_out = stream->avail_out; 206 return ret; 207} 208 209 210static int zlib_decompress_setup(struct crypto_pcomp *tfm, void *params, 211 unsigned int len) 212{ 213 struct zlib_ctx *ctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 214 struct z_stream_s *stream = &ctx->decomp_stream; 215 struct nlattr *tb[ZLIB_DECOMP_MAX + 1]; 216 int ret = 0; 217 218 ret = nla_parse(tb, ZLIB_DECOMP_MAX, params, len, NULL); 219 if (ret) 220 return ret; 221 222 zlib_decomp_exit(ctx); 223 224 ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS] 225 ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS]) 226 : DEF_WBITS; 227 228 stream->workspace = kzalloc(zlib_inflate_workspacesize(), GFP_KERNEL); 229 if (!stream->workspace) 230 return -ENOMEM; 231 232 ret = zlib_inflateInit2(stream, ctx->decomp_windowBits); 233 if (ret != Z_OK) { 234 kfree(stream->workspace); 235 stream->workspace = NULL; 236 return -EINVAL; 237 } 238 239 return 0; 240} 241 242static int zlib_decompress_init(struct crypto_pcomp *tfm) 243{ 244 int ret; 245 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 246 struct z_stream_s *stream = &dctx->decomp_stream; 247 248 ret = zlib_inflateReset(stream); 249 if (ret != Z_OK) 250 return -EINVAL; 251 252 return 0; 253} 254 255static int zlib_decompress_update(struct crypto_pcomp *tfm, 256 struct comp_request *req) 257{ 258 int ret; 259 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 260 struct z_stream_s *stream = &dctx->decomp_stream; 261 262 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out); 263 stream->next_in = req->next_in; 264 stream->avail_in = req->avail_in; 265 stream->next_out = req->next_out; 266 stream->avail_out = req->avail_out; 267 268 ret = zlib_inflate(stream, Z_SYNC_FLUSH); 269 switch (ret) { 270 case Z_OK: 271 case Z_STREAM_END: 272 break; 273 274 case Z_BUF_ERROR: 275 pr_debug("zlib_inflate could not make progress\n"); 276 return -EAGAIN; 277 278 default: 279 pr_debug("zlib_inflate failed %d\n", ret); 280 return -EINVAL; 281 } 282 283 ret = req->avail_out - stream->avail_out; 284 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n", 285 stream->avail_in, stream->avail_out, 286 req->avail_in - stream->avail_in, ret); 287 req->next_in = stream->next_in; 288 req->avail_in = stream->avail_in; 289 req->next_out = stream->next_out; 290 req->avail_out = stream->avail_out; 291 return ret; 292} 293 294static int zlib_decompress_final(struct crypto_pcomp *tfm, 295 struct comp_request *req) 296{ 297 int ret; 298 struct zlib_ctx *dctx = crypto_tfm_ctx(crypto_pcomp_tfm(tfm)); 299 struct z_stream_s *stream = &dctx->decomp_stream; 300 301 pr_debug("avail_in %u, avail_out %u\n", req->avail_in, req->avail_out); 302 stream->next_in = req->next_in; 303 stream->avail_in = req->avail_in; 304 stream->next_out = req->next_out; 305 stream->avail_out = req->avail_out; 306 307 if (dctx->decomp_windowBits < 0) { 308 ret = zlib_inflate(stream, Z_SYNC_FLUSH); 309 /* 310 * Work around a bug in zlib, which sometimes wants to taste an 311 * extra byte when being used in the (undocumented) raw deflate 312 * mode. (From USAGI). 313 */ 314 if (ret == Z_OK && !stream->avail_in && stream->avail_out) { 315 const void *saved_next_in = stream->next_in; 316 u8 zerostuff = 0; 317 318 stream->next_in = &zerostuff; 319 stream->avail_in = 1; 320 ret = zlib_inflate(stream, Z_FINISH); 321 stream->next_in = saved_next_in; 322 stream->avail_in = 0; 323 } 324 } else 325 ret = zlib_inflate(stream, Z_FINISH); 326 if (ret != Z_STREAM_END) { 327 pr_debug("zlib_inflate failed %d\n", ret); 328 return -EINVAL; 329 } 330 331 ret = req->avail_out - stream->avail_out; 332 pr_debug("avail_in %u, avail_out %u (consumed %u, produced %u)\n", 333 stream->avail_in, stream->avail_out, 334 req->avail_in - stream->avail_in, ret); 335 req->next_in = stream->next_in; 336 req->avail_in = stream->avail_in; 337 req->next_out = stream->next_out; 338 req->avail_out = stream->avail_out; 339 return ret; 340} 341 342 343static struct pcomp_alg zlib_alg = { 344 .compress_setup = zlib_compress_setup, 345 .compress_init = zlib_compress_init, 346 .compress_update = zlib_compress_update, 347 .compress_final = zlib_compress_final, 348 .decompress_setup = zlib_decompress_setup, 349 .decompress_init = zlib_decompress_init, 350 .decompress_update = zlib_decompress_update, 351 .decompress_final = zlib_decompress_final, 352 353 .base = { 354 .cra_name = "zlib", 355 .cra_flags = CRYPTO_ALG_TYPE_PCOMPRESS, 356 .cra_ctxsize = sizeof(struct zlib_ctx), 357 .cra_module = THIS_MODULE, 358 .cra_init = zlib_init, 359 .cra_exit = zlib_exit, 360 } 361}; 362 363static int __init zlib_mod_init(void) 364{ 365 return crypto_register_pcomp(&zlib_alg); 366} 367 368static void __exit zlib_mod_fini(void) 369{ 370 crypto_unregister_pcomp(&zlib_alg); 371} 372 373module_init(zlib_mod_init); 374module_exit(zlib_mod_fini); 375 376MODULE_LICENSE("GPL"); 377MODULE_DESCRIPTION("Zlib Compression Algorithm"); 378MODULE_AUTHOR("Sony Corporation");