45888b40d2
To get rid of the variable length arrays on stack in the RS decoder it's necessary to allocate the decoder buffers per control structure instance. All usage sites have been checked for potential parallel decoder usage and fixed where necessary. Kees confirmed that the pstore decoding is strictly single threaded so there should be no surprises. Allocate them in the rs control structure sized depending on the number of roots for the chosen codec and adapt the decoder code to make use of them. Document the fact that decode operations based on a particular rs control instance cannot run in parallel and the caller has to ensure that as it's not possible to provide a proper locking construct which fits all use cases. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Kees Cook <keescook@chromium.org> Cc: Boris Brezillon <boris.brezillon@free-electrons.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Segher Boessenkool <segher@kernel.crashing.org> Cc: Kernel Hardening <kernel-hardening@lists.openwall.com> Cc: Richard Weinberger <richard@nod.at> Cc: Mike Snitzer <snitzer@redhat.com> Cc: Anton Vorontsov <anton@enomsg.org> Cc: Colin Cross <ccross@android.com> Cc: Andrew Morton <akpm@linuxfoundation.org> Cc: David Woodhouse <dwmw2@infradead.org> Cc: Alasdair Kergon <agk@redhat.com> Signed-off-by: Kees Cook <keescook@chromium.org>
131 lines
3.7 KiB
C
131 lines
3.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Generic Reed Solomon encoder / decoder library
|
|
*
|
|
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
|
|
*
|
|
* RS code lifted from reed solomon library written by Phil Karn
|
|
* Copyright 2002 Phil Karn, KA9Q
|
|
*/
|
|
#ifndef _RSLIB_H_
|
|
#define _RSLIB_H_
|
|
|
|
#include <linux/list.h>
|
|
#include <linux/types.h> /* for gfp_t */
|
|
#include <linux/gfp.h> /* for GFP_KERNEL */
|
|
|
|
/**
|
|
* struct rs_codec - rs codec data
|
|
*
|
|
* @mm: Bits per symbol
|
|
* @nn: Symbols per block (= (1<<mm)-1)
|
|
* @alpha_to: log lookup table
|
|
* @index_of: Antilog lookup table
|
|
* @genpoly: Generator polynomial
|
|
* @nroots: Number of generator roots = number of parity symbols
|
|
* @fcr: First consecutive root, index form
|
|
* @prim: Primitive element, index form
|
|
* @iprim: prim-th root of 1, index form
|
|
* @gfpoly: The primitive generator polynominal
|
|
* @gffunc: Function to generate the field, if non-canonical representation
|
|
* @users: Users of this structure
|
|
* @list: List entry for the rs codec list
|
|
*/
|
|
struct rs_codec {
|
|
int mm;
|
|
int nn;
|
|
uint16_t *alpha_to;
|
|
uint16_t *index_of;
|
|
uint16_t *genpoly;
|
|
int nroots;
|
|
int fcr;
|
|
int prim;
|
|
int iprim;
|
|
int gfpoly;
|
|
int (*gffunc)(int);
|
|
int users;
|
|
struct list_head list;
|
|
};
|
|
|
|
/**
|
|
* struct rs_control - rs control structure per instance
|
|
* @codec: The codec used for this instance
|
|
* @buffers: Internal scratch buffers used in calls to decode_rs()
|
|
*/
|
|
struct rs_control {
|
|
struct rs_codec *codec;
|
|
uint16_t buffers[0];
|
|
};
|
|
|
|
/* General purpose RS codec, 8-bit data width, symbol width 1-15 bit */
|
|
#ifdef CONFIG_REED_SOLOMON_ENC8
|
|
int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
|
|
uint16_t invmsk);
|
|
#endif
|
|
#ifdef CONFIG_REED_SOLOMON_DEC8
|
|
int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
|
|
uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
|
|
uint16_t *corr);
|
|
#endif
|
|
|
|
/* General purpose RS codec, 16-bit data width, symbol width 1-15 bit */
|
|
#ifdef CONFIG_REED_SOLOMON_ENC16
|
|
int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
|
|
uint16_t invmsk);
|
|
#endif
|
|
#ifdef CONFIG_REED_SOLOMON_DEC16
|
|
int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
|
|
uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
|
|
uint16_t *corr);
|
|
#endif
|
|
|
|
struct rs_control *init_rs_gfp(int symsize, int gfpoly, int fcr, int prim,
|
|
int nroots, gfp_t gfp);
|
|
|
|
/**
|
|
* init_rs - Create a RS control struct and initialize it
|
|
* @symsize: the symbol size (number of bits)
|
|
* @gfpoly: the extended Galois field generator polynomial coefficients,
|
|
* with the 0th coefficient in the low order bit. The polynomial
|
|
* must be primitive;
|
|
* @fcr: the first consecutive root of the rs code generator polynomial
|
|
* in index form
|
|
* @prim: primitive element to generate polynomial roots
|
|
* @nroots: RS code generator polynomial degree (number of roots)
|
|
*
|
|
* Allocations use GFP_KERNEL.
|
|
*/
|
|
static inline struct rs_control *init_rs(int symsize, int gfpoly, int fcr,
|
|
int prim, int nroots)
|
|
{
|
|
return init_rs_gfp(symsize, gfpoly, fcr, prim, nroots, GFP_KERNEL);
|
|
}
|
|
|
|
struct rs_control *init_rs_non_canonical(int symsize, int (*func)(int),
|
|
int fcr, int prim, int nroots);
|
|
|
|
/* Release a rs control structure */
|
|
void free_rs(struct rs_control *rs);
|
|
|
|
/** modulo replacement for galois field arithmetics
|
|
*
|
|
* @rs: Pointer to the RS codec
|
|
* @x: the value to reduce
|
|
*
|
|
* where
|
|
* rs->mm = number of bits per symbol
|
|
* rs->nn = (2^rs->mm) - 1
|
|
*
|
|
* Simple arithmetic modulo would return a wrong result for values
|
|
* >= 3 * rs->nn
|
|
*/
|
|
static inline int rs_modnn(struct rs_codec *rs, int x)
|
|
{
|
|
while (x >= rs->nn) {
|
|
x -= rs->nn;
|
|
x = (x >> rs->mm) + (x & rs->nn);
|
|
}
|
|
return x;
|
|
}
|
|
|
|
#endif
|