android_kernel_xiaomi_sm7250/drivers/char/lrng/lrng_internal.h
UtsavBalar1231 273ac0f0f8 LRNG: Backport to 4.19 kernel
- Required to fix compilation of LRNG on 4.19 kernel

Change-Id: I6a25f657d3ab2ee3f9e44cbe5a9c0314d6ca905f
Signed-off-by: UtsavBalar1231 <utsavbalar1231@gmail.com>
2022-11-12 11:23:17 +00:00

490 lines
17 KiB
C

/* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */
/*
* Copyright (C) 2018 - 2021, Stephan Mueller <smueller@chronox.de>
*/
#ifndef _LRNG_INTERNAL_H
#define _LRNG_INTERNAL_H
#include <crypto/sha.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/rwlock.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#define arch_get_random_seed_long_early arch_get_random_seed_long
#define arch_get_random_long_early arch_get_random_long
#define kfree_sensitive kzfree
/*************************** General LRNG parameter ***************************/
/* Security strength of LRNG -- this must match DRNG security strength */
#define LRNG_DRNG_SECURITY_STRENGTH_BYTES 32
#define LRNG_DRNG_SECURITY_STRENGTH_BITS (LRNG_DRNG_SECURITY_STRENGTH_BYTES * 8)
#define LRNG_DRNG_BLOCKSIZE 64 /* Maximum of DRNG block sizes */
#define LRNG_DRNG_INIT_SEED_SIZE_BITS (LRNG_DRNG_SECURITY_STRENGTH_BITS + \
CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS)
#define LRNG_DRNG_INIT_SEED_SIZE_BYTES (LRNG_DRNG_INIT_SEED_SIZE_BITS >> 3)
/*
* SP800-90A defines a maximum request size of 1<<16 bytes. The given value is
* considered a safer margin.
*
* This value is allowed to be changed.
*/
#define LRNG_DRNG_MAX_REQSIZE (1<<12)
/*
* SP800-90A defines a maximum number of requests between reseeds of 2^48.
* The given value is considered a much safer margin, balancing requests for
* frequent reseeds with the need to conserve entropy. This value MUST NOT be
* larger than INT_MAX because it is used in an atomic_t.
*
* This value is allowed to be changed.
*/
#define LRNG_DRNG_RESEED_THRESH (1<<20)
/*
* Maximum DRNG generation operations without reseed having full entropy
* This value defines the absolute maximum value of DRNG generation operations
* without a reseed holding full entropy. LRNG_DRNG_RESEED_THRESH is the
* threshold when a new reseed is attempted. But it is possible that this fails
* to deliver full entropy. In this case the DRNG will continue to provide data
* even though it was not reseeded with full entropy. To avoid in the extreme
* case that no reseed is performed for too long, this threshold is enforced.
* If that absolute low value is reached, the LRNG is marked as not operational.
*
* This value is allowed to be changed.
*/
#define LRNG_DRNG_MAX_WITHOUT_RESEED (1<<30)
/*
* Min required seed entropy is 128 bits covering the minimum entropy
* requirement of SP800-131A and the German BSI's TR02102.
*
* This value is allowed to be changed.
*/
#define LRNG_FULL_SEED_ENTROPY_BITS LRNG_DRNG_SECURITY_STRENGTH_BITS
#define LRNG_MIN_SEED_ENTROPY_BITS 128
#define LRNG_INIT_ENTROPY_BITS 32
/*
* Wakeup value
*
* This value is allowed to be changed but must not be larger than the
* digest size of the hash operation used update the aux_pool.
*/
#ifdef CONFIG_CRYPTO_LIB_SHA256
# define LRNG_ATOMIC_DIGEST_SIZE SHA256_DIGEST_SIZE
#else
# define LRNG_ATOMIC_DIGEST_SIZE SHA1_DIGEST_SIZE
#endif
#define LRNG_WRITE_WAKEUP_ENTROPY LRNG_ATOMIC_DIGEST_SIZE
/*
* If the switching support is configured, we must provide support up to
* the largest digest size. Without switching support, we know it is only
* the built-in digest size.
*/
#ifdef CONFIG_LRNG_DRNG_SWITCH
# define LRNG_MAX_DIGESTSIZE 64
#else
# define LRNG_MAX_DIGESTSIZE LRNG_ATOMIC_DIGEST_SIZE
#endif
/*
* Oversampling factor of IRQ events to obtain
* LRNG_DRNG_SECURITY_STRENGTH_BYTES. This factor is used when a
* high-resolution time stamp is not available. In this case, jiffies and
* register contents are used to fill the entropy pool. These noise sources
* are much less entropic than the high-resolution timer. The entropy content
* is the entropy content assumed with LRNG_IRQ_ENTROPY_BITS divided by
* LRNG_IRQ_OVERSAMPLING_FACTOR.
*
* This value is allowed to be changed.
*/
#define LRNG_IRQ_OVERSAMPLING_FACTOR 10
/* Alignmask that is intended to be identical to CRYPTO_MINALIGN */
#define LRNG_KCAPI_ALIGN ARCH_KMALLOC_MINALIGN
/*
* This definition must provide a buffer that is equal to SHASH_DESC_ON_STACK
* as it will be casted into a struct shash_desc.
*/
#define LRNG_POOL_SIZE (sizeof(struct shash_desc) + HASH_MAX_DESCSIZE)
/************************ Default DRNG implementation *************************/
extern struct chacha20_state chacha20;
extern const struct lrng_crypto_cb lrng_cc20_crypto_cb;
void lrng_cc20_init_state(struct chacha20_state *state);
/********************************** /proc *************************************/
#ifdef CONFIG_SYSCTL
void lrng_pool_inc_numa_node(void);
void lrng_proc_update_max_write_thresh(u32 new_digestsize);
#else
static inline void lrng_pool_inc_numa_node(void) { }
static inline void lrng_proc_update_max_write_thresh(u32 new_digestsize) { }
#endif
/****************************** LRNG interfaces *******************************/
extern u32 lrng_write_wakeup_bits;
extern int lrng_drng_reseed_max_time;
void lrng_writer_wakeup(void);
void lrng_init_wakeup(void);
void lrng_debug_report_seedlevel(const char *name);
void lrng_process_ready_list(void);
/* External interface to use of the switchable DRBG inside the kernel */
void get_random_bytes_full(void *buf, int nbytes);
/************************* Jitter RNG Entropy Source **************************/
#ifdef CONFIG_LRNG_JENT
u32 lrng_get_jent(u8 *outbuf, u32 requested_bits);
u32 lrng_jent_entropylevel(u32 requested_bits);
void lrng_jent_es_state(unsigned char *buf, size_t buflen);
#else /* CONFIG_LRNG_JENT */
static inline u32 lrng_get_jent(u8 *outbuf, u32 requested_bits) { return 0; }
static inline u32 lrng_jent_entropylevel(u32 requested_bits) { return 0; }
static inline void lrng_jent_es_state(unsigned char *buf, size_t buflen) { }
#endif /* CONFIG_LRNG_JENT */
/************************** CPU-based Entropy Source **************************/
static inline u32 lrng_fast_noise_entropylevel(u32 ent_bits, u32 requested_bits)
{
/* Obtain entropy statement */
ent_bits = ent_bits * requested_bits / LRNG_DRNG_SECURITY_STRENGTH_BITS;
/* Cap entropy to buffer size in bits */
ent_bits = min_t(u32, ent_bits, requested_bits);
return ent_bits;
}
#ifdef CONFIG_LRNG_CPU
u32 lrng_get_arch(u8 *outbuf, u32 requested_bits);
u32 lrng_archrandom_entropylevel(u32 requested_bits);
void lrng_arch_es_state(unsigned char *buf, size_t buflen);
#else /* CONFIG_LRNG_CPU */
static inline u32 lrng_get_arch(u8 *outbuf, u32 requested_bits) { return 0; }
static inline u32 lrng_archrandom_entropylevel(u32 requested_bits) { return 0; }
static inline void lrng_arch_es_state(unsigned char *buf, size_t buflen) { }
#endif /* CONFIG_LRNG_CPU */
/************************** Interrupt Entropy Source **************************/
#ifdef CONFIG_LRNG_IRQ
void lrng_pcpu_reset(void);
u32 lrng_pcpu_avail_pool_size(void);
u32 lrng_pcpu_avail_entropy(void);
int lrng_pcpu_switch_hash(int node,
const struct lrng_crypto_cb *new_cb, void *new_hash,
const struct lrng_crypto_cb *old_cb);
u32 lrng_pcpu_pool_hash(u8 *outbuf, u32 requested_bits, bool fully_seeded);
void lrng_pcpu_array_add_u32(u32 data);
u32 lrng_gcd_analyze(u32 *history, size_t nelem);
void lrng_irq_es_state(unsigned char *buf, size_t buflen);
#else /* CONFIG_LRNG_IRQ */
static inline void lrng_pcpu_reset(void) { }
static inline u32 lrng_pcpu_avail_pool_size(void) { return 0; }
static inline u32 lrng_pcpu_avail_entropy(void) { return 0; }
static inline int lrng_pcpu_switch_hash(int node,
const struct lrng_crypto_cb *new_cb, void *new_hash,
const struct lrng_crypto_cb *old_cb)
{
return 0;
}
static inline u32 lrng_pcpu_pool_hash(u8 *outbuf, u32 requested_bits,
bool fully_seeded)
{
return 0;
}
static inline void lrng_pcpu_array_add_u32(u32 data) { }
static inline void lrng_irq_es_state(unsigned char *buf, size_t buflen) { }
#endif /* CONFIG_LRNG_IRQ */
/****************************** DRNG processing *******************************/
/* DRNG state handle */
struct lrng_drng {
void *drng; /* DRNG handle */
void *hash; /* Hash handle */
const struct lrng_crypto_cb *crypto_cb; /* Crypto callbacks */
atomic_t requests; /* Number of DRNG requests */
atomic_t requests_since_fully_seeded; /* Number DRNG requests since
last fully seeded */
unsigned long last_seeded; /* Last time it was seeded */
bool fully_seeded; /* Is DRNG fully seeded? */
bool force_reseed; /* Force a reseed */
/* Lock write operations on DRNG state, DRNG replacement of crypto_cb */
struct mutex lock;
spinlock_t spin_lock;
/* Lock *hash replacement - always take before DRNG lock */
rwlock_t hash_lock;
};
extern struct mutex lrng_crypto_cb_update;
struct lrng_drng *lrng_drng_init_instance(void);
struct lrng_drng *lrng_drng_atomic_instance(void);
static __always_inline bool lrng_drng_is_atomic(struct lrng_drng *drng)
{
return (drng->drng == lrng_drng_atomic_instance()->drng);
}
/* Lock the DRNG */
static __always_inline void lrng_drng_lock(struct lrng_drng *drng,
unsigned long *flags)
__acquires(&drng->spin_lock)
{
/* Use spin lock in case the atomic DRNG context is used */
if (lrng_drng_is_atomic(drng)) {
spin_lock_irqsave(&drng->spin_lock, *flags);
/*
* In case a lock transition happened while we were spinning,
* catch this case and use the new lock type.
*/
if (!lrng_drng_is_atomic(drng)) {
spin_unlock_irqrestore(&drng->spin_lock, *flags);
__acquire(&drng->spin_lock);
mutex_lock(&drng->lock);
}
} else {
__acquire(&drng->spin_lock);
mutex_lock(&drng->lock);
}
}
/* Unlock the DRNG */
static __always_inline void lrng_drng_unlock(struct lrng_drng *drng,
unsigned long *flags)
__releases(&drng->spin_lock)
{
if (lrng_drng_is_atomic(drng)) {
spin_unlock_irqrestore(&drng->spin_lock, *flags);
} else {
mutex_unlock(&drng->lock);
__release(&drng->spin_lock);
}
}
void lrng_reset(void);
void lrng_drngs_init_cc20(bool force_seed);
bool lrng_sp80090c_compliant(void);
static inline u32 lrng_compress_osr(void)
{
return lrng_sp80090c_compliant() ? CONFIG_LRNG_OVERSAMPLE_ES_BITS : 0;
}
static inline u32 lrng_reduce_by_osr(u32 entropy_bits)
{
u32 osr_bits = lrng_compress_osr();
return (entropy_bits >= osr_bits) ? (entropy_bits - osr_bits) : 0;
}
bool lrng_get_available(void);
void lrng_set_available(void);
void lrng_drng_reset(struct lrng_drng *drng);
int lrng_drng_get_atomic(u8 *outbuf, u32 outbuflen);
int lrng_drng_get_sleep(u8 *outbuf, u32 outbuflen);
void lrng_drng_force_reseed(void);
void lrng_drng_seed_work(struct work_struct *dummy);
#ifdef CONFIG_NUMA
struct lrng_drng **lrng_drng_instances(void);
void lrng_drngs_numa_alloc(void);
#else /* CONFIG_NUMA */
static inline struct lrng_drng **lrng_drng_instances(void) { return NULL; }
static inline void lrng_drngs_numa_alloc(void) { return; }
#endif /* CONFIG_NUMA */
/************************* Entropy sources management *************************/
enum lrng_external_noise_source {
lrng_noise_source_hw,
lrng_noise_source_user
};
void lrng_set_entropy_thresh(u32 new);
u32 lrng_avail_entropy(void);
void lrng_reset_state(void);
bool lrng_state_exseed_allow(enum lrng_external_noise_source source);
void lrng_state_exseed_set(enum lrng_external_noise_source source, bool type);
bool lrng_state_min_seeded(void);
bool lrng_state_fully_seeded(void);
bool lrng_state_operational(void);
int lrng_pool_trylock(void);
void lrng_pool_unlock(void);
void lrng_pool_all_numa_nodes_seeded(bool set);
void lrng_pool_add_entropy(void);
struct entropy_buf {
u8 a[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
u8 b[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
u8 c[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
u8 d[LRNG_DRNG_INIT_SEED_SIZE_BYTES];
u32 now, a_bits, b_bits, c_bits, d_bits;
};
bool lrng_fully_seeded(bool fully_seeded, struct entropy_buf *eb);
void lrng_unset_fully_seeded(struct lrng_drng *drng);
void lrng_fill_seed_buffer(struct entropy_buf *entropy_buf, u32 requested_bits);
void lrng_init_ops(struct entropy_buf *eb);
/*********************** Auxiliary Pool Entropy Source ************************/
u32 lrng_avail_aux_entropy(void);
void lrng_aux_es_state(unsigned char *buf, size_t buflen);
u32 lrng_get_digestsize(void);
void lrng_pool_set_entropy(u32 entropy_bits);
int lrng_aux_switch_hash(const struct lrng_crypto_cb *new_cb, void *new_hash,
const struct lrng_crypto_cb *old_cb);
int lrng_pool_insert_aux(const u8 *inbuf, u32 inbuflen, u32 entropy_bits);
void lrng_get_backtrack_aux(struct entropy_buf *entropy_buf,
u32 requested_bits);
/* Obtain the security strength of the LRNG in bits */
static inline u32 lrng_security_strength(void)
{
/*
* We use a hash to read the entropy in the entropy pool. According to
* SP800-90B table 1, the entropy can be at most the digest size.
* Considering this together with the last sentence in section 3.1.5.1.2
* the security strength of a (approved) hash is equal to its output
* size. On the other hand the entropy cannot be larger than the
* security strength of the used DRBG.
*/
return min_t(u32, LRNG_FULL_SEED_ENTROPY_BITS, lrng_get_digestsize());
}
static inline u32 lrng_get_seed_entropy_osr(bool fully_seeded)
{
u32 requested_bits = lrng_security_strength();
/* Apply oversampling during initialization according to SP800-90C */
if (lrng_sp80090c_compliant() && !fully_seeded)
requested_bits += CONFIG_LRNG_SEED_BUFFER_INIT_ADD_BITS;
return requested_bits;
}
/************************** Health Test linking code **************************/
enum lrng_health_res {
lrng_health_pass, /* Health test passes on time stamp */
lrng_health_fail_use, /* Time stamp unhealthy, but mix in */
lrng_health_fail_drop /* Time stamp unhealthy, drop it */
};
#ifdef CONFIG_LRNG_HEALTH_TESTS
bool lrng_sp80090b_startup_complete(void);
bool lrng_sp80090b_compliant(void);
enum lrng_health_res lrng_health_test(u32 now_time);
void lrng_health_disable(void);
#else /* CONFIG_LRNG_HEALTH_TESTS */
static inline bool lrng_sp80090b_startup_complete(void) { return true; }
static inline bool lrng_sp80090b_compliant(void) { return false; }
static inline enum lrng_health_res
lrng_health_test(u32 now_time) { return lrng_health_pass; }
static inline void lrng_health_disable(void) { }
#endif /* CONFIG_LRNG_HEALTH_TESTS */
/****************************** Helper code ***********************************/
static inline u32 atomic_read_u32(atomic_t *v)
{
return (u32)atomic_read(v);
}
/******************** Crypto Primitive Switching Support **********************/
#ifdef CONFIG_LRNG_DRNG_SWITCH
static inline void lrng_hash_lock(struct lrng_drng *drng, unsigned long *flags)
{
read_lock_irqsave(&drng->hash_lock, *flags);
}
static inline void lrng_hash_unlock(struct lrng_drng *drng, unsigned long flags)
{
read_unlock_irqrestore(&drng->hash_lock, flags);
}
#else /* CONFIG_LRNG_DRNG_SWITCH */
static inline void lrng_hash_lock(struct lrng_drng *drng, unsigned long *flags)
{ }
static inline void lrng_hash_unlock(struct lrng_drng *drng, unsigned long flags)
{ }
#endif /* CONFIG_LRNG_DRNG_SWITCH */
/*************************** Auxiliary functions ******************************/
void invalidate_batched_entropy(void);
/***************************** Testing code ***********************************/
#ifdef CONFIG_LRNG_RAW_HIRES_ENTROPY
bool lrng_raw_hires_entropy_store(u32 value);
#else /* CONFIG_LRNG_RAW_HIRES_ENTROPY */
static inline bool lrng_raw_hires_entropy_store(u32 value) { return false; }
#endif /* CONFIG_LRNG_RAW_HIRES_ENTROPY */
#ifdef CONFIG_LRNG_RAW_JIFFIES_ENTROPY
bool lrng_raw_jiffies_entropy_store(u32 value);
#else /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */
static inline bool lrng_raw_jiffies_entropy_store(u32 value) { return false; }
#endif /* CONFIG_LRNG_RAW_JIFFIES_ENTROPY */
#ifdef CONFIG_LRNG_RAW_IRQ_ENTROPY
bool lrng_raw_irq_entropy_store(u32 value);
#else /* CONFIG_LRNG_RAW_IRQ_ENTROPY */
static inline bool lrng_raw_irq_entropy_store(u32 value) { return false; }
#endif /* CONFIG_LRNG_RAW_IRQ_ENTROPY */
#ifdef CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY
bool lrng_raw_irqflags_entropy_store(u32 value);
#else /* CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY */
static inline bool lrng_raw_irqflags_entropy_store(u32 value) { return false; }
#endif /* CONFIG_LRNG_RAW_IRQFLAGS_ENTROPY */
#ifdef CONFIG_LRNG_RAW_RETIP_ENTROPY
bool lrng_raw_retip_entropy_store(u32 value);
#else /* CONFIG_LRNG_RAW_RETIP_ENTROPY */
static inline bool lrng_raw_retip_entropy_store(u32 value) { return false; }
#endif /* CONFIG_LRNG_RAW_RETIP_ENTROPY */
#ifdef CONFIG_LRNG_RAW_REGS_ENTROPY
bool lrng_raw_regs_entropy_store(u32 value);
#else /* CONFIG_LRNG_RAW_REGS_ENTROPY */
static inline bool lrng_raw_regs_entropy_store(u32 value) { return false; }
#endif /* CONFIG_LRNG_RAW_REGS_ENTROPY */
#ifdef CONFIG_LRNG_RAW_ARRAY
bool lrng_raw_array_entropy_store(u32 value);
#else /* CONFIG_LRNG_RAW_ARRAY */
static inline bool lrng_raw_array_entropy_store(u32 value) { return false; }
#endif /* CONFIG_LRNG_RAW_ARRAY */
#ifdef CONFIG_LRNG_IRQ_PERF
bool lrng_perf_time(u32 start);
#else /* CONFIG_LRNG_IRQ_PERF */
static inline bool lrng_perf_time(u32 start) { return false; }
#endif /*CONFIG_LRNG_IRQ_PERF */
#endif /* _LRNG_INTERNAL_H */