linux/crypto/zlib.c
<<
>>
Prefs
   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");
 382