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

ppp_deflate.c (18154B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ppp_deflate.c - interface the zlib procedures for Deflate compression
      4 * and decompression (as used by gzip) to the PPP code.
      5 *
      6 * Copyright 1994-1998 Paul Mackerras.
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/slab.h>
     11#include <linux/vmalloc.h>
     12#include <linux/init.h>
     13#include <linux/string.h>
     14
     15#include <linux/ppp_defs.h>
     16#include <linux/ppp-comp.h>
     17
     18#include <linux/zlib.h>
     19#include <asm/unaligned.h>
     20
     21/*
     22 * State for a Deflate (de)compressor.
     23 */
     24struct ppp_deflate_state {
     25    int		seqno;
     26    int		w_size;
     27    int		unit;
     28    int		mru;
     29    int		debug;
     30    z_stream	strm;
     31    struct compstat stats;
     32};
     33
     34#define DEFLATE_OVHD	2		/* Deflate overhead/packet */
     35
     36static void	*z_comp_alloc(unsigned char *options, int opt_len);
     37static void	*z_decomp_alloc(unsigned char *options, int opt_len);
     38static void	z_comp_free(void *state);
     39static void	z_decomp_free(void *state);
     40static int	z_comp_init(void *state, unsigned char *options,
     41				 int opt_len,
     42				 int unit, int hdrlen, int debug);
     43static int	z_decomp_init(void *state, unsigned char *options,
     44				   int opt_len,
     45				   int unit, int hdrlen, int mru, int debug);
     46static int	z_compress(void *state, unsigned char *rptr,
     47				unsigned char *obuf,
     48				int isize, int osize);
     49static void	z_incomp(void *state, unsigned char *ibuf, int icnt);
     50static int	z_decompress(void *state, unsigned char *ibuf,
     51				int isize, unsigned char *obuf, int osize);
     52static void	z_comp_reset(void *state);
     53static void	z_decomp_reset(void *state);
     54static void	z_comp_stats(void *state, struct compstat *stats);
     55
     56/**
     57 *	z_comp_free - free the memory used by a compressor
     58 *	@arg:	pointer to the private state for the compressor.
     59 */
     60static void z_comp_free(void *arg)
     61{
     62	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
     63
     64	if (state) {
     65		zlib_deflateEnd(&state->strm);
     66		vfree(state->strm.workspace);
     67		kfree(state);
     68	}
     69}
     70
     71/**
     72 *	z_comp_alloc - allocate space for a compressor.
     73 *	@options: pointer to CCP option data
     74 *	@opt_len: length of the CCP option at @options.
     75 *
     76 *	The @options pointer points to the a buffer containing the
     77 *	CCP option data for the compression being negotiated.  It is
     78 *	formatted according to RFC1979, and describes the window
     79 *	size that the peer is requesting that we use in compressing
     80 *	data to be sent to it.
     81 *
     82 *	Returns the pointer to the private state for the compressor,
     83 *	or NULL if we could not allocate enough memory.
     84 */
     85static void *z_comp_alloc(unsigned char *options, int opt_len)
     86{
     87	struct ppp_deflate_state *state;
     88	int w_size;
     89
     90	if (opt_len != CILEN_DEFLATE ||
     91	    (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
     92	    options[1] != CILEN_DEFLATE ||
     93	    DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
     94	    options[3] != DEFLATE_CHK_SEQUENCE)
     95		return NULL;
     96	w_size = DEFLATE_SIZE(options[2]);
     97	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
     98		return NULL;
     99
    100	state = kzalloc(sizeof(*state),
    101						     GFP_KERNEL);
    102	if (state == NULL)
    103		return NULL;
    104
    105	state->strm.next_in   = NULL;
    106	state->w_size         = w_size;
    107	state->strm.workspace = vmalloc(zlib_deflate_workspacesize(-w_size, 8));
    108	if (state->strm.workspace == NULL)
    109		goto out_free;
    110
    111	if (zlib_deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION,
    112			 DEFLATE_METHOD_VAL, -w_size, 8, Z_DEFAULT_STRATEGY)
    113	    != Z_OK)
    114		goto out_free;
    115	return (void *) state;
    116
    117out_free:
    118	z_comp_free(state);
    119	return NULL;
    120}
    121
    122/**
    123 *	z_comp_init - initialize a previously-allocated compressor.
    124 *	@arg:	pointer to the private state for the compressor
    125 *	@options: pointer to the CCP option data describing the
    126 *		compression that was negotiated with the peer
    127 *	@opt_len: length of the CCP option data at @options
    128 *	@unit:	PPP unit number for diagnostic messages
    129 *	@hdrlen: ignored (present for backwards compatibility)
    130 *	@debug:	debug flag; if non-zero, debug messages are printed.
    131 *
    132 *	The CCP options described by @options must match the options
    133 *	specified when the compressor was allocated.  The compressor
    134 *	history is reset.  Returns 0 for failure (CCP options don't
    135 *	match) or 1 for success.
    136 */
    137static int z_comp_init(void *arg, unsigned char *options, int opt_len,
    138		       int unit, int hdrlen, int debug)
    139{
    140	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
    141
    142	if (opt_len < CILEN_DEFLATE ||
    143	    (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
    144	    options[1] != CILEN_DEFLATE ||
    145	    DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
    146	    DEFLATE_SIZE(options[2]) != state->w_size ||
    147	    options[3] != DEFLATE_CHK_SEQUENCE)
    148		return 0;
    149
    150	state->seqno = 0;
    151	state->unit  = unit;
    152	state->debug = debug;
    153
    154	zlib_deflateReset(&state->strm);
    155
    156	return 1;
    157}
    158
    159/**
    160 *	z_comp_reset - reset a previously-allocated compressor.
    161 *	@arg:	pointer to private state for the compressor.
    162 *
    163 *	This clears the history for the compressor and makes it
    164 *	ready to start emitting a new compressed stream.
    165 */
    166static void z_comp_reset(void *arg)
    167{
    168	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
    169
    170	state->seqno = 0;
    171	zlib_deflateReset(&state->strm);
    172}
    173
    174/**
    175 *	z_compress - compress a PPP packet with Deflate compression.
    176 *	@arg:	pointer to private state for the compressor
    177 *	@rptr:	uncompressed packet (input)
    178 *	@obuf:	compressed packet (output)
    179 *	@isize:	size of uncompressed packet
    180 *	@osize:	space available at @obuf
    181 *
    182 *	Returns the length of the compressed packet, or 0 if the
    183 *	packet is incompressible.
    184 */
    185static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,
    186	       int isize, int osize)
    187{
    188	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
    189	int r, proto, off, olen, oavail;
    190	unsigned char *wptr;
    191
    192	/*
    193	 * Check that the protocol is in the range we handle.
    194	 */
    195	proto = PPP_PROTOCOL(rptr);
    196	if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
    197		return 0;
    198
    199	/* Don't generate compressed packets which are larger than
    200	   the uncompressed packet. */
    201	if (osize > isize)
    202		osize = isize;
    203
    204	wptr = obuf;
    205
    206	/*
    207	 * Copy over the PPP header and store the 2-byte sequence number.
    208	 */
    209	wptr[0] = PPP_ADDRESS(rptr);
    210	wptr[1] = PPP_CONTROL(rptr);
    211	put_unaligned_be16(PPP_COMP, wptr + 2);
    212	wptr += PPP_HDRLEN;
    213	put_unaligned_be16(state->seqno, wptr);
    214	wptr += DEFLATE_OVHD;
    215	olen = PPP_HDRLEN + DEFLATE_OVHD;
    216	state->strm.next_out = wptr;
    217	state->strm.avail_out = oavail = osize - olen;
    218	++state->seqno;
    219
    220	off = (proto > 0xff) ? 2 : 3;	/* skip 1st proto byte if 0 */
    221	rptr += off;
    222	state->strm.next_in = rptr;
    223	state->strm.avail_in = (isize - off);
    224
    225	for (;;) {
    226		r = zlib_deflate(&state->strm, Z_PACKET_FLUSH);
    227		if (r != Z_OK) {
    228			if (state->debug)
    229				printk(KERN_ERR
    230				       "z_compress: deflate returned %d\n", r);
    231			break;
    232		}
    233		if (state->strm.avail_out == 0) {
    234			olen += oavail;
    235			state->strm.next_out = NULL;
    236			state->strm.avail_out = oavail = 1000000;
    237		} else {
    238			break;		/* all done */
    239		}
    240	}
    241	olen += oavail - state->strm.avail_out;
    242
    243	/*
    244	 * See if we managed to reduce the size of the packet.
    245	 */
    246	if (olen < isize && olen <= osize) {
    247		state->stats.comp_bytes += olen;
    248		state->stats.comp_packets++;
    249	} else {
    250		state->stats.inc_bytes += isize;
    251		state->stats.inc_packets++;
    252		olen = 0;
    253	}
    254	state->stats.unc_bytes += isize;
    255	state->stats.unc_packets++;
    256
    257	return olen;
    258}
    259
    260/**
    261 *	z_comp_stats - return compression statistics for a compressor
    262 *		or decompressor.
    263 *	@arg:	pointer to private space for the (de)compressor
    264 *	@stats:	pointer to a struct compstat to receive the result.
    265 */
    266static void z_comp_stats(void *arg, struct compstat *stats)
    267{
    268	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
    269
    270	*stats = state->stats;
    271}
    272
    273/**
    274 *	z_decomp_free - Free the memory used by a decompressor.
    275 *	@arg:	pointer to private space for the decompressor.
    276 */
    277static void z_decomp_free(void *arg)
    278{
    279	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
    280
    281	if (state) {
    282		vfree(state->strm.workspace);
    283		kfree(state);
    284	}
    285}
    286
    287/**
    288 *	z_decomp_alloc - allocate space for a decompressor.
    289 *	@options: pointer to CCP option data
    290 *	@opt_len: length of the CCP option at @options.
    291 *
    292 *	The @options pointer points to the a buffer containing the
    293 *	CCP option data for the compression being negotiated.  It is
    294 *	formatted according to RFC1979, and describes the window
    295 *	size that we are requesting the peer to use in compressing
    296 *	data to be sent to us.
    297 *
    298 *	Returns the pointer to the private state for the decompressor,
    299 *	or NULL if we could not allocate enough memory.
    300 */
    301static void *z_decomp_alloc(unsigned char *options, int opt_len)
    302{
    303	struct ppp_deflate_state *state;
    304	int w_size;
    305
    306	if (opt_len != CILEN_DEFLATE ||
    307	    (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
    308	    options[1] != CILEN_DEFLATE ||
    309	    DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
    310	    options[3] != DEFLATE_CHK_SEQUENCE)
    311		return NULL;
    312	w_size = DEFLATE_SIZE(options[2]);
    313	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
    314		return NULL;
    315
    316	state = kzalloc(sizeof(*state), GFP_KERNEL);
    317	if (state == NULL)
    318		return NULL;
    319
    320	state->w_size         = w_size;
    321	state->strm.next_out  = NULL;
    322	state->strm.workspace = vmalloc(zlib_inflate_workspacesize());
    323	if (state->strm.workspace == NULL)
    324		goto out_free;
    325
    326	if (zlib_inflateInit2(&state->strm, -w_size) != Z_OK)
    327		goto out_free;
    328	return (void *) state;
    329
    330out_free:
    331	z_decomp_free(state);
    332	return NULL;
    333}
    334
    335/**
    336 *	z_decomp_init - initialize a previously-allocated decompressor.
    337 *	@arg:	pointer to the private state for the decompressor
    338 *	@options: pointer to the CCP option data describing the
    339 *		compression that was negotiated with the peer
    340 *	@opt_len: length of the CCP option data at @options
    341 *	@unit:	PPP unit number for diagnostic messages
    342 *	@hdrlen: ignored (present for backwards compatibility)
    343 *	@mru:	maximum length of decompressed packets
    344 *	@debug:	debug flag; if non-zero, debug messages are printed.
    345 *
    346 *	The CCP options described by @options must match the options
    347 *	specified when the decompressor was allocated.  The decompressor
    348 *	history is reset.  Returns 0 for failure (CCP options don't
    349 *	match) or 1 for success.
    350 */
    351static int z_decomp_init(void *arg, unsigned char *options, int opt_len,
    352			 int unit, int hdrlen, int mru, int debug)
    353{
    354	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
    355
    356	if (opt_len < CILEN_DEFLATE ||
    357	    (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT) ||
    358	    options[1] != CILEN_DEFLATE ||
    359	    DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL ||
    360	    DEFLATE_SIZE(options[2]) != state->w_size ||
    361	    options[3] != DEFLATE_CHK_SEQUENCE)
    362		return 0;
    363
    364	state->seqno = 0;
    365	state->unit  = unit;
    366	state->debug = debug;
    367	state->mru   = mru;
    368
    369	zlib_inflateReset(&state->strm);
    370
    371	return 1;
    372}
    373
    374/**
    375 *	z_decomp_reset - reset a previously-allocated decompressor.
    376 *	@arg:	pointer to private state for the decompressor.
    377 *
    378 *	This clears the history for the decompressor and makes it
    379 *	ready to receive a new compressed stream.
    380 */
    381static void z_decomp_reset(void *arg)
    382{
    383	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
    384
    385	state->seqno = 0;
    386	zlib_inflateReset(&state->strm);
    387}
    388
    389/**
    390 *	z_decompress - decompress a Deflate-compressed packet.
    391 *	@arg:	pointer to private state for the decompressor
    392 *	@ibuf:	pointer to input (compressed) packet data
    393 *	@isize:	length of input packet
    394 *	@obuf:	pointer to space for output (decompressed) packet
    395 *	@osize:	amount of space available at @obuf
    396 *
    397 * Because of patent problems, we return DECOMP_ERROR for errors
    398 * found by inspecting the input data and for system problems, but
    399 * DECOMP_FATALERROR for any errors which could possibly be said to
    400 * be being detected "after" decompression.  For DECOMP_ERROR,
    401 * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
    402 * infringing a patent of Motorola's if we do, so we take CCP down
    403 * instead.
    404 *
    405 * Given that the frame has the correct sequence number and a good FCS,
    406 * errors such as invalid codes in the input most likely indicate a
    407 * bug, so we return DECOMP_FATALERROR for them in order to turn off
    408 * compression, even though they are detected by inspecting the input.
    409 */
    410static int z_decompress(void *arg, unsigned char *ibuf, int isize,
    411		 unsigned char *obuf, int osize)
    412{
    413	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
    414	int olen, seq, r;
    415	int decode_proto, overflow;
    416	unsigned char overflow_buf[1];
    417
    418	if (isize <= PPP_HDRLEN + DEFLATE_OVHD) {
    419		if (state->debug)
    420			printk(KERN_DEBUG "z_decompress%d: short pkt (%d)\n",
    421			       state->unit, isize);
    422		return DECOMP_ERROR;
    423	}
    424
    425	/* Check the sequence number. */
    426	seq = get_unaligned_be16(ibuf + PPP_HDRLEN);
    427	if (seq != (state->seqno & 0xffff)) {
    428		if (state->debug)
    429			printk(KERN_DEBUG "z_decompress%d: bad seq # %d, expected %d\n",
    430			       state->unit, seq, state->seqno & 0xffff);
    431		return DECOMP_ERROR;
    432	}
    433	++state->seqno;
    434
    435	/*
    436	 * Fill in the first part of the PPP header.  The protocol field
    437	 * comes from the decompressed data.
    438	 */
    439	obuf[0] = PPP_ADDRESS(ibuf);
    440	obuf[1] = PPP_CONTROL(ibuf);
    441	obuf[2] = 0;
    442
    443	/*
    444	 * Set up to call inflate.  We set avail_out to 1 initially so we can
    445	 * look at the first byte of the output and decide whether we have
    446	 * a 1-byte or 2-byte protocol field.
    447	 */
    448	state->strm.next_in = ibuf + PPP_HDRLEN + DEFLATE_OVHD;
    449	state->strm.avail_in = isize - (PPP_HDRLEN + DEFLATE_OVHD);
    450	state->strm.next_out = obuf + 3;
    451	state->strm.avail_out = 1;
    452	decode_proto = 1;
    453	overflow = 0;
    454
    455	/*
    456	 * Call inflate, supplying more input or output as needed.
    457	 */
    458	for (;;) {
    459		r = zlib_inflate(&state->strm, Z_PACKET_FLUSH);
    460		if (r != Z_OK) {
    461			if (state->debug)
    462				printk(KERN_DEBUG "z_decompress%d: inflate returned %d (%s)\n",
    463				       state->unit, r, (state->strm.msg? state->strm.msg: ""));
    464			return DECOMP_FATALERROR;
    465		}
    466		if (state->strm.avail_out != 0)
    467			break;		/* all done */
    468		if (decode_proto) {
    469			state->strm.avail_out = osize - PPP_HDRLEN;
    470			if ((obuf[3] & 1) == 0) {
    471				/* 2-byte protocol field */
    472				obuf[2] = obuf[3];
    473				--state->strm.next_out;
    474				++state->strm.avail_out;
    475			}
    476			decode_proto = 0;
    477		} else if (!overflow) {
    478			/*
    479			 * We've filled up the output buffer; the only way to
    480			 * find out whether inflate has any more characters
    481			 * left is to give it another byte of output space.
    482			 */
    483			state->strm.next_out = overflow_buf;
    484			state->strm.avail_out = 1;
    485			overflow = 1;
    486		} else {
    487			if (state->debug)
    488				printk(KERN_DEBUG "z_decompress%d: ran out of mru\n",
    489				       state->unit);
    490			return DECOMP_FATALERROR;
    491		}
    492	}
    493
    494	if (decode_proto) {
    495		if (state->debug)
    496			printk(KERN_DEBUG "z_decompress%d: didn't get proto\n",
    497			       state->unit);
    498		return DECOMP_ERROR;
    499	}
    500
    501	olen = osize + overflow - state->strm.avail_out;
    502	state->stats.unc_bytes += olen;
    503	state->stats.unc_packets++;
    504	state->stats.comp_bytes += isize;
    505	state->stats.comp_packets++;
    506
    507	return olen;
    508}
    509
    510/**
    511 *	z_incomp - add incompressible input data to the history.
    512 *	@arg:	pointer to private state for the decompressor
    513 *	@ibuf:	pointer to input packet data
    514 *	@icnt:	length of input data.
    515 */
    516static void z_incomp(void *arg, unsigned char *ibuf, int icnt)
    517{
    518	struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg;
    519	int proto, r;
    520
    521	/*
    522	 * Check that the protocol is one we handle.
    523	 */
    524	proto = PPP_PROTOCOL(ibuf);
    525	if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
    526		return;
    527
    528	++state->seqno;
    529
    530	/*
    531	 * We start at the either the 1st or 2nd byte of the protocol field,
    532	 * depending on whether the protocol value is compressible.
    533	 */
    534	state->strm.next_in = ibuf + 3;
    535	state->strm.avail_in = icnt - 3;
    536	if (proto > 0xff) {
    537		--state->strm.next_in;
    538		++state->strm.avail_in;
    539	}
    540
    541	r = zlib_inflateIncomp(&state->strm);
    542	if (r != Z_OK) {
    543		/* gak! */
    544		if (state->debug) {
    545			printk(KERN_DEBUG "z_incomp%d: inflateIncomp returned %d (%s)\n",
    546			       state->unit, r, (state->strm.msg? state->strm.msg: ""));
    547		}
    548		return;
    549	}
    550
    551	/*
    552	 * Update stats.
    553	 */
    554	state->stats.inc_bytes += icnt;
    555	state->stats.inc_packets++;
    556	state->stats.unc_bytes += icnt;
    557	state->stats.unc_packets++;
    558}
    559
    560/*************************************************************
    561 * Module interface table
    562 *************************************************************/
    563
    564/* These are in ppp_generic.c */
    565extern int  ppp_register_compressor   (struct compressor *cp);
    566extern void ppp_unregister_compressor (struct compressor *cp);
    567
    568/*
    569 * Procedures exported to if_ppp.c.
    570 */
    571static struct compressor ppp_deflate = {
    572	.compress_proto =	CI_DEFLATE,
    573	.comp_alloc =		z_comp_alloc,
    574	.comp_free =		z_comp_free,
    575	.comp_init =		z_comp_init,
    576	.comp_reset =		z_comp_reset,
    577	.compress =		z_compress,
    578	.comp_stat =		z_comp_stats,
    579	.decomp_alloc =		z_decomp_alloc,
    580	.decomp_free =		z_decomp_free,
    581	.decomp_init =		z_decomp_init,
    582	.decomp_reset =		z_decomp_reset,
    583	.decompress =		z_decompress,
    584	.incomp =		z_incomp,
    585	.decomp_stat =		z_comp_stats,
    586	.owner =		THIS_MODULE
    587};
    588
    589static struct compressor ppp_deflate_draft = {
    590	.compress_proto =	CI_DEFLATE_DRAFT,
    591	.comp_alloc =		z_comp_alloc,
    592	.comp_free =		z_comp_free,
    593	.comp_init =		z_comp_init,
    594	.comp_reset =		z_comp_reset,
    595	.compress =		z_compress,
    596	.comp_stat =		z_comp_stats,
    597	.decomp_alloc =		z_decomp_alloc,
    598	.decomp_free =		z_decomp_free,
    599	.decomp_init =		z_decomp_init,
    600	.decomp_reset =		z_decomp_reset,
    601	.decompress =		z_decompress,
    602	.incomp =		z_incomp,
    603	.decomp_stat =		z_comp_stats,
    604	.owner =		THIS_MODULE
    605};
    606
    607static int __init deflate_init(void)
    608{
    609	int rc;
    610
    611	rc = ppp_register_compressor(&ppp_deflate);
    612	if (rc)
    613		return rc;
    614
    615	rc = ppp_register_compressor(&ppp_deflate_draft);
    616	if (rc) {
    617		ppp_unregister_compressor(&ppp_deflate);
    618		return rc;
    619	}
    620
    621	pr_info("PPP Deflate Compression module registered\n");
    622	return 0;
    623}
    624
    625static void __exit deflate_cleanup(void)
    626{
    627	ppp_unregister_compressor(&ppp_deflate);
    628	ppp_unregister_compressor(&ppp_deflate_draft);
    629}
    630
    631module_init(deflate_init);
    632module_exit(deflate_cleanup);
    633MODULE_LICENSE("Dual BSD/GPL");
    634MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE));
    635MODULE_ALIAS("ppp-compress-" __stringify(CI_DEFLATE_DRAFT));