CVE-2017-15116 (C, published 2017-11-30T18:29Z)
Description: value: The rngapi_reset function in crypto/rng.c in the Linux kernel before 4.2 allows attackers to cause a denial of service (NULL pointer dereference).
Severity: MEDIUM (CVSS v3 base score: 5.5)
Weakness: CWE-476 \u2014 NULL Pointer Dereference
The product dereferences a pointer that it expects to be valid but is NULL.
Repository: https://github.com/torvalds/linux
Files changed:
crypto/rng.c
include/crypto/internal/rng.h
include/crypto/rng.h
include/linux/crypto.h
Commit message: crypto: rng - Remove old low-level rng interface

Now that all rng implementations have switched over to the new
interface, we can remove the old low-level interface.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>


Vulnerable code:
static inline struct old_rng_alg *crypto_old_rng_alg(struct crypto_rng *tfm)
{
	return &crypto_rng_tfm(tfm)->__crt_alg->cra_rng;
}

static int generate(struct crypto_rng *tfm, const u8 *src, unsigned int slen,
		    u8 *dst, unsigned int dlen)
{
	return crypto_old_rng_alg(tfm)->rng_make_random(tfm, dst, dlen);
}

static int rngapi_reset(struct crypto_rng *tfm, const u8 *seed,
			unsigned int slen)
{
	u8 *buf = NULL;
	u8 *src = (u8 *)seed;
	int err;

	if (slen) {
		buf = kmalloc(slen, GFP_KERNEL);
		if (!buf)
			return -ENOMEM;

		memcpy(buf, seed, slen);
		src = buf;
	}

	err = crypto_old_rng_alg(tfm)->rng_reset(tfm, src, slen);

	kzfree(buf);
	return err;
}

	err = tfm->seed(tfm, seed, slen);
	struct crypto_rng *rng = __crypto_rng_cast(tfm);
	struct rng_alg *alg = crypto_rng_alg(rng);
	struct old_rng_alg *oalg = crypto_old_rng_alg(rng);

	if (oalg->rng_make_random) {
		rng->generate = generate;
		rng->seed = rngapi_reset;
		rng->seedsize = oalg->seedsize;
		return 0;
	}

	rng->generate = alg->generate;
	rng->seed = alg->seed;
	rng->seedsize = alg->seedsize;

	return alg->cra_rng.rng_make_random ?
	       alg->cra_rng.seedsize : ralg->seedsize;
const struct crypto_type crypto_rng_type = {
EXPORT_SYMBOL_GPL(crypto_rng_type);
extern const struct crypto_type crypto_rng_type;

	int (*generate)(struct crypto_rng *tfm,
			const u8 *src, unsigned int slen,
			u8 *dst, unsigned int dlen);
	int (*seed)(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
	unsigned int seedsize;
	return tfm->generate(tfm, src, slen, dst, dlen);
	return tfm->seedsize;
struct crypto_rng;
/**
 * struct old_rng_alg - random number generator definition
 * @rng_make_random: The function defined by this variable obtains a random
 *		     number. The random number generator transform must generate
 *		     the random number out of the context provided with this
 *		     call.
 * @rng_reset: Reset of the random number generator by clearing the entire state.
 *	       With the invocation of this function call, the random number
 *             generator shall completely reinitialize its state. If the random
 *	       number generator requires a seed for setting up a new state,
 *	       the seed must be provided by the consumer while invoking this
 *	       function. The required size of the seed is defined with
 *	       @seedsize .
 * @seedsize: The seed size required for a random number generator
 *	      initialization defined with this variable. Some random number
 *	      generators like the SP800-90A DRBG does not require a seed as the
 *	      seeding is implemented internally without the need of support by
 *	      the consumer. In this case, the seed size is set to zero.
 */
struct old_rng_alg {
	int (*rng_make_random)(struct crypto_rng *tfm, u8 *rdata,
			       unsigned int dlen);
	int (*rng_reset)(struct crypto_rng *tfm, u8 *seed, unsigned int slen);

	unsigned int seedsize;
};

#define cra_rng		cra_u.rng
		struct old_rng_alg rng;

Fixed code:
 * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
	err = crypto_rng_alg(tfm)->seed(tfm, seed, slen);
	return ralg->seedsize;
static const struct crypto_type crypto_rng_type = {
 * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
 * Copyright (c) 2015 Herbert Xu <herbert@gondor.apana.org.au>
	return crypto_rng_alg(tfm)->generate(tfm, src, slen, dst, dlen);
	return crypto_rng_alg(tfm)->seedsize;