hmac - require that the underlying hash algorithm is unkeyed in kernel-crypto CVE-2017-17806

Tracked by Jolla (Rejected)

asked 2018-01-22 09:35:58 +0300

this post is marked as community wiki

This post is a wiki. Anyone with karma >75 is welcome to improve it.

updated 2018-01-22 09:35:58 +0300

lpr gravatar image

The HMAC implementation (crypto/hmac.c) in the Linux kernel before 4.14.8 does not validate that the underlying cryptographic hash algorithm is unkeyed, allowing a local attacker able to use the AF_ALG-based hash interface (CONFIG_CRYPTO_USER_API_HASH) and the SHA-3 hash algorithm (CONFIG_CRYPTO_SHA3) to cause a kernel stack buffer overflow by executing a crafted sequence of system calls that encounter a missing SHA-3 initialization. 7.8high (attack range: local)

Patch is available and equal to kernel-3.2 backport.

Files affected: kernel-adaptation-sbj-3.4.108.20161101.1/crypto/hmac.c lines 197-207
kernel-adaptation-sbj-3.4.108.20161101.1/crypto/shash.c lines 24-34
kernel-adaptation-sbj-3.4.108.20161101.1/include/crypto/internal/hash.h lines 70-76

So this patch schould look like:
hmac.c

@@ -197,11 +197,15 @@ static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb)
salg = shash_attr_alg(tb[1], 0, 0);
if (IS_ERR(salg))
    return PTR_ERR(salg);
+   alg = &salg->base;

+   /* The underlying hash algorithm must be unkeyed */
err = -EINVAL;
+   if (crypto_shash_alg_has_setkey(salg))
+       goto out_put_alg;
+
ds = salg->digestsize;
ss = salg->statesize;
-   alg = &salg->base;
if (ds > alg->cra_blocksize ||
    ss < alg->cra_blocksize)
    goto out_put_alg;

shash.c

@@ -24,11 +24,12 @@

 static const struct crypto_type crypto_shash_type;

-static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
-              unsigned int keylen)
+int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+           unsigned int keylen)
  {
return -ENOSYS;
  }
+EXPORT_SYMBOL_GPL(shash_no_setkey);

 static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
              unsigned int keylen)

hash.h

@@ -70,6 +70,14 @@ int ahash_register_instance(struct crypto_template *tmpl,
            struct ahash_instance *inst);
 void ahash_free_instance(struct crypto_instance *inst);

+int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+           unsigned int keylen);
+
+static inline bool crypto_shash_alg_has_setkey(struct shash_alg *alg)
+{
+   return alg->setkey != shash_no_setkey;
+}
+
 int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
            struct hash_alg_common *alg,
            struct crypto_instance *inst);
edit retag flag offensive close delete