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
  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, 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 %u, avail_out %u (consumed %u, 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 %u, avail_out %u (consumed %u, 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, 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 %u, avail_out %u (consumed %u, 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 %u, avail_out %u (consumed %u, 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");
 381
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.