LCOV - code coverage report
Current view: top level - crypto - deflate.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 6 149 4.0 %
Date: 2021-04-22 12:43:58 Functions: 1 19 5.3 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Cryptographic API.
       4             :  *
       5             :  * Deflate algorithm (RFC 1951), implemented here primarily for use
       6             :  * by IPCOMP (RFC 3173 & RFC 2394).
       7             :  *
       8             :  * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
       9             :  *
      10             :  * FIXME: deflate transforms will require up to a total of about 436k of kernel
      11             :  * memory on i386 (390k for compression, the rest for decompression), as the
      12             :  * current zlib kernel code uses a worst case pre-allocation system by default.
      13             :  * This needs to be fixed so that the amount of memory required is properly
      14             :  * related to the  winbits and memlevel parameters.
      15             :  *
      16             :  * The default winbits of 11 should suit most packets, and it may be something
      17             :  * to configure on a per-tfm basis in the future.
      18             :  *
      19             :  * Currently, compression history is not maintained between tfm calls, as
      20             :  * it is not needed for IPCOMP and keeps the code simpler.  It can be
      21             :  * implemented if someone wants it.
      22             :  */
      23             : #include <linux/init.h>
      24             : #include <linux/module.h>
      25             : #include <linux/crypto.h>
      26             : #include <linux/zlib.h>
      27             : #include <linux/vmalloc.h>
      28             : #include <linux/interrupt.h>
      29             : #include <linux/mm.h>
      30             : #include <linux/net.h>
      31             : #include <crypto/internal/scompress.h>
      32             : 
      33             : #define DEFLATE_DEF_LEVEL               Z_DEFAULT_COMPRESSION
      34             : #define DEFLATE_DEF_WINBITS             11
      35             : #define DEFLATE_DEF_MEMLEVEL            MAX_MEM_LEVEL
      36             : 
      37             : struct deflate_ctx {
      38             :         struct z_stream_s comp_stream;
      39             :         struct z_stream_s decomp_stream;
      40             : };
      41             : 
      42           0 : static int deflate_comp_init(struct deflate_ctx *ctx, int format)
      43             : {
      44           0 :         int ret = 0;
      45           0 :         struct z_stream_s *stream = &ctx->comp_stream;
      46             : 
      47           0 :         stream->workspace = vzalloc(zlib_deflate_workspacesize(
      48             :                                     MAX_WBITS, MAX_MEM_LEVEL));
      49           0 :         if (!stream->workspace) {
      50           0 :                 ret = -ENOMEM;
      51           0 :                 goto out;
      52             :         }
      53           0 :         if (format)
      54           0 :                 ret = zlib_deflateInit(stream, 3);
      55             :         else
      56           0 :                 ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED,
      57             :                                         -DEFLATE_DEF_WINBITS,
      58             :                                         DEFLATE_DEF_MEMLEVEL,
      59             :                                         Z_DEFAULT_STRATEGY);
      60           0 :         if (ret != Z_OK) {
      61           0 :                 ret = -EINVAL;
      62           0 :                 goto out_free;
      63             :         }
      64           0 : out:
      65           0 :         return ret;
      66           0 : out_free:
      67           0 :         vfree(stream->workspace);
      68           0 :         goto out;
      69             : }
      70             : 
      71           0 : static int deflate_decomp_init(struct deflate_ctx *ctx, int format)
      72             : {
      73           0 :         int ret = 0;
      74           0 :         struct z_stream_s *stream = &ctx->decomp_stream;
      75             : 
      76           0 :         stream->workspace = vzalloc(zlib_inflate_workspacesize());
      77           0 :         if (!stream->workspace) {
      78           0 :                 ret = -ENOMEM;
      79           0 :                 goto out;
      80             :         }
      81           0 :         if (format)
      82           0 :                 ret = zlib_inflateInit(stream);
      83             :         else
      84           0 :                 ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS);
      85           0 :         if (ret != Z_OK) {
      86           0 :                 ret = -EINVAL;
      87           0 :                 goto out_free;
      88             :         }
      89           0 : out:
      90           0 :         return ret;
      91           0 : out_free:
      92           0 :         vfree(stream->workspace);
      93           0 :         goto out;
      94             : }
      95             : 
      96           0 : static void deflate_comp_exit(struct deflate_ctx *ctx)
      97             : {
      98           0 :         zlib_deflateEnd(&ctx->comp_stream);
      99           0 :         vfree(ctx->comp_stream.workspace);
     100           0 : }
     101             : 
     102           0 : static void deflate_decomp_exit(struct deflate_ctx *ctx)
     103             : {
     104           0 :         zlib_inflateEnd(&ctx->decomp_stream);
     105           0 :         vfree(ctx->decomp_stream.workspace);
     106           0 : }
     107             : 
     108           0 : static int __deflate_init(void *ctx, int format)
     109             : {
     110           0 :         int ret;
     111             : 
     112           0 :         ret = deflate_comp_init(ctx, format);
     113           0 :         if (ret)
     114           0 :                 goto out;
     115           0 :         ret = deflate_decomp_init(ctx, format);
     116           0 :         if (ret)
     117           0 :                 deflate_comp_exit(ctx);
     118           0 : out:
     119           0 :         return ret;
     120             : }
     121             : 
     122           0 : static void *gen_deflate_alloc_ctx(struct crypto_scomp *tfm, int format)
     123             : {
     124           0 :         struct deflate_ctx *ctx;
     125           0 :         int ret;
     126             : 
     127           0 :         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
     128           0 :         if (!ctx)
     129           0 :                 return ERR_PTR(-ENOMEM);
     130             : 
     131           0 :         ret = __deflate_init(ctx, format);
     132           0 :         if (ret) {
     133           0 :                 kfree(ctx);
     134           0 :                 return ERR_PTR(ret);
     135             :         }
     136             : 
     137             :         return ctx;
     138             : }
     139             : 
     140           0 : static void *deflate_alloc_ctx(struct crypto_scomp *tfm)
     141             : {
     142           0 :         return gen_deflate_alloc_ctx(tfm, 0);
     143             : }
     144             : 
     145           0 : static void *zlib_deflate_alloc_ctx(struct crypto_scomp *tfm)
     146             : {
     147           0 :         return gen_deflate_alloc_ctx(tfm, 1);
     148             : }
     149             : 
     150           0 : static int deflate_init(struct crypto_tfm *tfm)
     151             : {
     152           0 :         struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
     153             : 
     154           0 :         return __deflate_init(ctx, 0);
     155             : }
     156             : 
     157           0 : static void __deflate_exit(void *ctx)
     158             : {
     159           0 :         deflate_comp_exit(ctx);
     160           0 :         deflate_decomp_exit(ctx);
     161             : }
     162             : 
     163           0 : static void deflate_free_ctx(struct crypto_scomp *tfm, void *ctx)
     164             : {
     165           0 :         __deflate_exit(ctx);
     166           0 :         kfree_sensitive(ctx);
     167           0 : }
     168             : 
     169           0 : static void deflate_exit(struct crypto_tfm *tfm)
     170             : {
     171           0 :         struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
     172             : 
     173           0 :         __deflate_exit(ctx);
     174           0 : }
     175             : 
     176           0 : static int __deflate_compress(const u8 *src, unsigned int slen,
     177             :                               u8 *dst, unsigned int *dlen, void *ctx)
     178             : {
     179           0 :         int ret = 0;
     180           0 :         struct deflate_ctx *dctx = ctx;
     181           0 :         struct z_stream_s *stream = &dctx->comp_stream;
     182             : 
     183           0 :         ret = zlib_deflateReset(stream);
     184           0 :         if (ret != Z_OK) {
     185           0 :                 ret = -EINVAL;
     186           0 :                 goto out;
     187             :         }
     188             : 
     189           0 :         stream->next_in = (u8 *)src;
     190           0 :         stream->avail_in = slen;
     191           0 :         stream->next_out = (u8 *)dst;
     192           0 :         stream->avail_out = *dlen;
     193             : 
     194           0 :         ret = zlib_deflate(stream, Z_FINISH);
     195           0 :         if (ret != Z_STREAM_END) {
     196           0 :                 ret = -EINVAL;
     197           0 :                 goto out;
     198             :         }
     199           0 :         ret = 0;
     200           0 :         *dlen = stream->total_out;
     201           0 : out:
     202           0 :         return ret;
     203             : }
     204             : 
     205           0 : static int deflate_compress(struct crypto_tfm *tfm, const u8 *src,
     206             :                             unsigned int slen, u8 *dst, unsigned int *dlen)
     207             : {
     208           0 :         struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
     209             : 
     210           0 :         return __deflate_compress(src, slen, dst, dlen, dctx);
     211             : }
     212             : 
     213           0 : static int deflate_scompress(struct crypto_scomp *tfm, const u8 *src,
     214             :                              unsigned int slen, u8 *dst, unsigned int *dlen,
     215             :                              void *ctx)
     216             : {
     217           0 :         return __deflate_compress(src, slen, dst, dlen, ctx);
     218             : }
     219             : 
     220           0 : static int __deflate_decompress(const u8 *src, unsigned int slen,
     221             :                                 u8 *dst, unsigned int *dlen, void *ctx)
     222             : {
     223             : 
     224           0 :         int ret = 0;
     225           0 :         struct deflate_ctx *dctx = ctx;
     226           0 :         struct z_stream_s *stream = &dctx->decomp_stream;
     227             : 
     228           0 :         ret = zlib_inflateReset(stream);
     229           0 :         if (ret != Z_OK) {
     230           0 :                 ret = -EINVAL;
     231           0 :                 goto out;
     232             :         }
     233             : 
     234           0 :         stream->next_in = (u8 *)src;
     235           0 :         stream->avail_in = slen;
     236           0 :         stream->next_out = (u8 *)dst;
     237           0 :         stream->avail_out = *dlen;
     238             : 
     239           0 :         ret = zlib_inflate(stream, Z_SYNC_FLUSH);
     240             :         /*
     241             :          * Work around a bug in zlib, which sometimes wants to taste an extra
     242             :          * byte when being used in the (undocumented) raw deflate mode.
     243             :          * (From USAGI).
     244             :          */
     245           0 :         if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
     246           0 :                 u8 zerostuff = 0;
     247           0 :                 stream->next_in = &zerostuff;
     248           0 :                 stream->avail_in = 1;
     249           0 :                 ret = zlib_inflate(stream, Z_FINISH);
     250             :         }
     251           0 :         if (ret != Z_STREAM_END) {
     252           0 :                 ret = -EINVAL;
     253           0 :                 goto out;
     254             :         }
     255           0 :         ret = 0;
     256           0 :         *dlen = stream->total_out;
     257           0 : out:
     258           0 :         return ret;
     259             : }
     260             : 
     261           0 : static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src,
     262             :                               unsigned int slen, u8 *dst, unsigned int *dlen)
     263             : {
     264           0 :         struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
     265             : 
     266           0 :         return __deflate_decompress(src, slen, dst, dlen, dctx);
     267             : }
     268             : 
     269           0 : static int deflate_sdecompress(struct crypto_scomp *tfm, const u8 *src,
     270             :                                unsigned int slen, u8 *dst, unsigned int *dlen,
     271             :                                void *ctx)
     272             : {
     273           0 :         return __deflate_decompress(src, slen, dst, dlen, ctx);
     274             : }
     275             : 
     276             : static struct crypto_alg alg = {
     277             :         .cra_name               = "deflate",
     278             :         .cra_driver_name        = "deflate-generic",
     279             :         .cra_flags              = CRYPTO_ALG_TYPE_COMPRESS,
     280             :         .cra_ctxsize            = sizeof(struct deflate_ctx),
     281             :         .cra_module             = THIS_MODULE,
     282             :         .cra_init               = deflate_init,
     283             :         .cra_exit               = deflate_exit,
     284             :         .cra_u                  = { .compress = {
     285             :         .coa_compress           = deflate_compress,
     286             :         .coa_decompress         = deflate_decompress } }
     287             : };
     288             : 
     289             : static struct scomp_alg scomp[] = { {
     290             :         .alloc_ctx              = deflate_alloc_ctx,
     291             :         .free_ctx               = deflate_free_ctx,
     292             :         .compress               = deflate_scompress,
     293             :         .decompress             = deflate_sdecompress,
     294             :         .base                   = {
     295             :                 .cra_name       = "deflate",
     296             :                 .cra_driver_name = "deflate-scomp",
     297             :                 .cra_module      = THIS_MODULE,
     298             :         }
     299             : }, {
     300             :         .alloc_ctx              = zlib_deflate_alloc_ctx,
     301             :         .free_ctx               = deflate_free_ctx,
     302             :         .compress               = deflate_scompress,
     303             :         .decompress             = deflate_sdecompress,
     304             :         .base                   = {
     305             :                 .cra_name       = "zlib-deflate",
     306             :                 .cra_driver_name = "zlib-deflate-scomp",
     307             :                 .cra_module      = THIS_MODULE,
     308             :         }
     309             : } };
     310             : 
     311           1 : static int __init deflate_mod_init(void)
     312             : {
     313           1 :         int ret;
     314             : 
     315           1 :         ret = crypto_register_alg(&alg);
     316           1 :         if (ret)
     317             :                 return ret;
     318             : 
     319           1 :         ret = crypto_register_scomps(scomp, ARRAY_SIZE(scomp));
     320           1 :         if (ret) {
     321           0 :                 crypto_unregister_alg(&alg);
     322           0 :                 return ret;
     323             :         }
     324             : 
     325             :         return ret;
     326             : }
     327             : 
     328           0 : static void __exit deflate_mod_fini(void)
     329             : {
     330           0 :         crypto_unregister_alg(&alg);
     331           0 :         crypto_unregister_scomps(scomp, ARRAY_SIZE(scomp));
     332           0 : }
     333             : 
     334             : subsys_initcall(deflate_mod_init);
     335             : module_exit(deflate_mod_fini);
     336             : 
     337             : MODULE_LICENSE("GPL");
     338             : MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP");
     339             : MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
     340             : MODULE_ALIAS_CRYPTO("deflate");

Generated by: LCOV version 1.14