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