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