cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

deflate.c (7895B)


      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
     37struct deflate_ctx {
     38	struct z_stream_s comp_stream;
     39	struct z_stream_s decomp_stream;
     40};
     41
     42static int deflate_comp_init(struct deflate_ctx *ctx, int format)
     43{
     44	int ret = 0;
     45	struct z_stream_s *stream = &ctx->comp_stream;
     46
     47	stream->workspace = vzalloc(zlib_deflate_workspacesize(
     48				    MAX_WBITS, MAX_MEM_LEVEL));
     49	if (!stream->workspace) {
     50		ret = -ENOMEM;
     51		goto out;
     52	}
     53	if (format)
     54		ret = zlib_deflateInit(stream, 3);
     55	else
     56		ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED,
     57					-DEFLATE_DEF_WINBITS,
     58					DEFLATE_DEF_MEMLEVEL,
     59					Z_DEFAULT_STRATEGY);
     60	if (ret != Z_OK) {
     61		ret = -EINVAL;
     62		goto out_free;
     63	}
     64out:
     65	return ret;
     66out_free:
     67	vfree(stream->workspace);
     68	goto out;
     69}
     70
     71static int deflate_decomp_init(struct deflate_ctx *ctx, int format)
     72{
     73	int ret = 0;
     74	struct z_stream_s *stream = &ctx->decomp_stream;
     75
     76	stream->workspace = vzalloc(zlib_inflate_workspacesize());
     77	if (!stream->workspace) {
     78		ret = -ENOMEM;
     79		goto out;
     80	}
     81	if (format)
     82		ret = zlib_inflateInit(stream);
     83	else
     84		ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS);
     85	if (ret != Z_OK) {
     86		ret = -EINVAL;
     87		goto out_free;
     88	}
     89out:
     90	return ret;
     91out_free:
     92	vfree(stream->workspace);
     93	goto out;
     94}
     95
     96static void deflate_comp_exit(struct deflate_ctx *ctx)
     97{
     98	zlib_deflateEnd(&ctx->comp_stream);
     99	vfree(ctx->comp_stream.workspace);
    100}
    101
    102static void deflate_decomp_exit(struct deflate_ctx *ctx)
    103{
    104	zlib_inflateEnd(&ctx->decomp_stream);
    105	vfree(ctx->decomp_stream.workspace);
    106}
    107
    108static int __deflate_init(void *ctx, int format)
    109{
    110	int ret;
    111
    112	ret = deflate_comp_init(ctx, format);
    113	if (ret)
    114		goto out;
    115	ret = deflate_decomp_init(ctx, format);
    116	if (ret)
    117		deflate_comp_exit(ctx);
    118out:
    119	return ret;
    120}
    121
    122static void *gen_deflate_alloc_ctx(struct crypto_scomp *tfm, int format)
    123{
    124	struct deflate_ctx *ctx;
    125	int ret;
    126
    127	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
    128	if (!ctx)
    129		return ERR_PTR(-ENOMEM);
    130
    131	ret = __deflate_init(ctx, format);
    132	if (ret) {
    133		kfree(ctx);
    134		return ERR_PTR(ret);
    135	}
    136
    137	return ctx;
    138}
    139
    140static void *deflate_alloc_ctx(struct crypto_scomp *tfm)
    141{
    142	return gen_deflate_alloc_ctx(tfm, 0);
    143}
    144
    145static void *zlib_deflate_alloc_ctx(struct crypto_scomp *tfm)
    146{
    147	return gen_deflate_alloc_ctx(tfm, 1);
    148}
    149
    150static int deflate_init(struct crypto_tfm *tfm)
    151{
    152	struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
    153
    154	return __deflate_init(ctx, 0);
    155}
    156
    157static void __deflate_exit(void *ctx)
    158{
    159	deflate_comp_exit(ctx);
    160	deflate_decomp_exit(ctx);
    161}
    162
    163static void deflate_free_ctx(struct crypto_scomp *tfm, void *ctx)
    164{
    165	__deflate_exit(ctx);
    166	kfree_sensitive(ctx);
    167}
    168
    169static void deflate_exit(struct crypto_tfm *tfm)
    170{
    171	struct deflate_ctx *ctx = crypto_tfm_ctx(tfm);
    172
    173	__deflate_exit(ctx);
    174}
    175
    176static int __deflate_compress(const u8 *src, unsigned int slen,
    177			      u8 *dst, unsigned int *dlen, void *ctx)
    178{
    179	int ret = 0;
    180	struct deflate_ctx *dctx = ctx;
    181	struct z_stream_s *stream = &dctx->comp_stream;
    182
    183	ret = zlib_deflateReset(stream);
    184	if (ret != Z_OK) {
    185		ret = -EINVAL;
    186		goto out;
    187	}
    188
    189	stream->next_in = (u8 *)src;
    190	stream->avail_in = slen;
    191	stream->next_out = (u8 *)dst;
    192	stream->avail_out = *dlen;
    193
    194	ret = zlib_deflate(stream, Z_FINISH);
    195	if (ret != Z_STREAM_END) {
    196		ret = -EINVAL;
    197		goto out;
    198	}
    199	ret = 0;
    200	*dlen = stream->total_out;
    201out:
    202	return ret;
    203}
    204
    205static int deflate_compress(struct crypto_tfm *tfm, const u8 *src,
    206			    unsigned int slen, u8 *dst, unsigned int *dlen)
    207{
    208	struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
    209
    210	return __deflate_compress(src, slen, dst, dlen, dctx);
    211}
    212
    213static int deflate_scompress(struct crypto_scomp *tfm, const u8 *src,
    214			     unsigned int slen, u8 *dst, unsigned int *dlen,
    215			     void *ctx)
    216{
    217	return __deflate_compress(src, slen, dst, dlen, ctx);
    218}
    219
    220static int __deflate_decompress(const u8 *src, unsigned int slen,
    221				u8 *dst, unsigned int *dlen, void *ctx)
    222{
    223
    224	int ret = 0;
    225	struct deflate_ctx *dctx = ctx;
    226	struct z_stream_s *stream = &dctx->decomp_stream;
    227
    228	ret = zlib_inflateReset(stream);
    229	if (ret != Z_OK) {
    230		ret = -EINVAL;
    231		goto out;
    232	}
    233
    234	stream->next_in = (u8 *)src;
    235	stream->avail_in = slen;
    236	stream->next_out = (u8 *)dst;
    237	stream->avail_out = *dlen;
    238
    239	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	if (ret == Z_OK && !stream->avail_in && stream->avail_out) {
    246		u8 zerostuff = 0;
    247		stream->next_in = &zerostuff;
    248		stream->avail_in = 1;
    249		ret = zlib_inflate(stream, Z_FINISH);
    250	}
    251	if (ret != Z_STREAM_END) {
    252		ret = -EINVAL;
    253		goto out;
    254	}
    255	ret = 0;
    256	*dlen = stream->total_out;
    257out:
    258	return ret;
    259}
    260
    261static int deflate_decompress(struct crypto_tfm *tfm, const u8 *src,
    262			      unsigned int slen, u8 *dst, unsigned int *dlen)
    263{
    264	struct deflate_ctx *dctx = crypto_tfm_ctx(tfm);
    265
    266	return __deflate_decompress(src, slen, dst, dlen, dctx);
    267}
    268
    269static int deflate_sdecompress(struct crypto_scomp *tfm, const u8 *src,
    270			       unsigned int slen, u8 *dst, unsigned int *dlen,
    271			       void *ctx)
    272{
    273	return __deflate_decompress(src, slen, dst, dlen, ctx);
    274}
    275
    276static 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
    289static 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
    311static int __init deflate_mod_init(void)
    312{
    313	int ret;
    314
    315	ret = crypto_register_alg(&alg);
    316	if (ret)
    317		return ret;
    318
    319	ret = crypto_register_scomps(scomp, ARRAY_SIZE(scomp));
    320	if (ret) {
    321		crypto_unregister_alg(&alg);
    322		return ret;
    323	}
    324
    325	return ret;
    326}
    327
    328static void __exit deflate_mod_fini(void)
    329{
    330	crypto_unregister_alg(&alg);
    331	crypto_unregister_scomps(scomp, ARRAY_SIZE(scomp));
    332}
    333
    334subsys_initcall(deflate_mod_init);
    335module_exit(deflate_mod_fini);
    336
    337MODULE_LICENSE("GPL");
    338MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP");
    339MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
    340MODULE_ALIAS_CRYPTO("deflate");