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 33#include <crypto/internal/compress.h> 34 35#include <net/netlink.h> 36 37 38struct zlib_ctx { 39 struct z_stream_s comp_stream; 40 struct z_stream_s decomp_stream; 41 int decomp_windowBits; 42}; 43 44 45static 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 56static 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 67static int zlib_init(struct crypto_tfm *tfm) 68{ 69 return 0; 70} 71 72static 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 81static int zlib_compress_setup(struct crypto_pcomp *tfm, const 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]) 112 : Z_DEFAULT_COMPRESSION, 113 tb[ZLIB_COMP_METHOD] 114 ? nla_get_u32(tb[ZLIB_COMP_METHOD]) 115 : Z_DEFLATED, 116 window_bits, 117 mem_level, 118 tb[ZLIB_COMP_STRATEGY] 119 ? nla_get_u32(tb[ZLIB_COMP_STRATEGY]) 120 : Z_DEFAULT_STRATEGY); 121 if (ret != Z_OK) { 122 vfree(stream->workspace); 123 stream->workspace = NULL; 124 return -EINVAL; 125 } 126 127 return 0; 128} 129 130static 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 143static 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 %lu, avail_out %lu (consumed %lu, 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 181static 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 %lu, avail_out %lu (consumed %lu, 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 212static int zlib_decompress_setup(struct crypto_pcomp *tfm, const 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 226 ctx->decomp_windowBits = tb[ZLIB_DECOMP_WINDOWBITS] 227 ? nla_get_u32(tb[ZLIB_DECOMP_WINDOWBITS]) 228 : DEF_WBITS; 229 230 stream->workspace = vzalloc(zlib_inflate_workspacesize()); 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 244static 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 257static 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 %lu, avail_out %lu (consumed %lu, 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 296static 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 %lu, avail_out %lu (consumed %lu, 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 345static 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 365static int __init zlib_mod_init(void) 366{ 367 return crypto_register_pcomp(&zlib_alg); 368} 369 370static void __exit zlib_mod_fini(void) 371{ 372 crypto_unregister_pcomp(&zlib_alg); 373} 374 375module_init(zlib_mod_init); 376module_exit(zlib_mod_fini); 377 378MODULE_LICENSE("GPL"); 379MODULE_DESCRIPTION("Zlib Compression Algorithm"); 380MODULE_AUTHOR("Sony Corporation"); 381MODULE_ALIAS_CRYPTO("zlib"); 382