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